1use crate::{
2 MemoryTunables, PanicOnOom as _, Tunables, WasmResult, collections::TryCow, error::OutOfMemory,
3 prelude::*, wasm_unsupported,
4};
5use alloc::boxed::Box;
6use core::{fmt, ops::Range};
7use serde_derive::{Deserialize, Serialize};
8use smallvec::SmallVec;
9
10#[doc(hidden)]
11pub fn deserialize_boxed_slice<'de, T, D>(deserializer: D) -> Result<Box<[T]>, D::Error>
12where
13 T: serde::de::Deserialize<'de>,
14 D: serde::de::Deserializer<'de>,
15{
16 let tys: crate::collections::TryVec<T> = serde::Deserialize::deserialize(deserializer)?;
17 let tys = tys
18 .into_boxed_slice()
19 .map_err(|oom| serde::de::Error::custom(oom))?;
20 Ok(tys)
21}
22
23pub trait TypeTrace {
26 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
30 where
31 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>;
32
33 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
39 where
40 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>;
41
42 fn trace_engine_indices<F, E>(&self, func: &mut F) -> Result<(), E>
44 where
45 F: FnMut(VMSharedTypeIndex) -> Result<(), E>,
46 {
47 self.trace(&mut |idx| match idx {
48 EngineOrModuleTypeIndex::Engine(idx) => func(idx),
49 EngineOrModuleTypeIndex::Module(_) | EngineOrModuleTypeIndex::RecGroup(_) => Ok(()),
50 })
51 }
52
53 fn canonicalize_for_runtime_usage<F>(&mut self, module_to_engine: &mut F)
64 where
65 F: FnMut(ModuleInternedTypeIndex) -> VMSharedTypeIndex,
66 {
67 self.trace_mut::<_, ()>(&mut |idx| match idx {
68 EngineOrModuleTypeIndex::Engine(_) => Ok(()),
69 EngineOrModuleTypeIndex::Module(module_index) => {
70 let engine_index = module_to_engine(*module_index);
71 *idx = EngineOrModuleTypeIndex::Engine(engine_index);
72 Ok(())
73 }
74 EngineOrModuleTypeIndex::RecGroup(_) => {
75 panic!("should not already be canonicalized for hash consing")
76 }
77 })
78 .unwrap()
79 }
80
81 fn is_canonicalized_for_runtime_usage(&self) -> bool {
83 self.trace(&mut |idx| match idx {
84 EngineOrModuleTypeIndex::Engine(_) => Ok(()),
85 EngineOrModuleTypeIndex::Module(_) | EngineOrModuleTypeIndex::RecGroup(_) => Err(()),
86 })
87 .is_ok()
88 }
89
90 fn canonicalize_for_hash_consing<F>(
101 &mut self,
102 rec_group_range: Range<ModuleInternedTypeIndex>,
103 module_to_engine: &mut F,
104 ) where
105 F: FnMut(ModuleInternedTypeIndex) -> VMSharedTypeIndex,
106 {
107 self.trace_mut::<_, ()>(&mut |idx| match *idx {
108 EngineOrModuleTypeIndex::Engine(_) => Ok(()),
109 EngineOrModuleTypeIndex::Module(module_index) => {
110 *idx = if rec_group_range.start <= module_index {
111 debug_assert!(module_index < rec_group_range.end);
114 let relative = module_index.as_u32() - rec_group_range.start.as_u32();
115 let relative = RecGroupRelativeTypeIndex::from_u32(relative);
116 EngineOrModuleTypeIndex::RecGroup(relative)
117 } else {
118 debug_assert!(module_index < rec_group_range.start);
121 EngineOrModuleTypeIndex::Engine(module_to_engine(module_index))
122 };
123 Ok(())
124 }
125 EngineOrModuleTypeIndex::RecGroup(_) => {
126 panic!("should not already be canonicalized for hash consing")
127 }
128 })
129 .unwrap()
130 }
131
132 fn is_canonicalized_for_hash_consing(&self) -> bool {
134 self.trace(&mut |idx| match idx {
135 EngineOrModuleTypeIndex::Engine(_) | EngineOrModuleTypeIndex::RecGroup(_) => Ok(()),
136 EngineOrModuleTypeIndex::Module(_) => Err(()),
137 })
138 .is_ok()
139 }
140}
141
142#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
144pub enum WasmValType {
145 I32,
147 I64,
149 F32,
151 F64,
153 V128,
155 Ref(WasmRefType),
157}
158
159impl TryClone for WasmValType {
160 fn try_clone(&self) -> Result<Self, OutOfMemory> {
161 Ok(*self)
162 }
163}
164
165impl fmt::Display for WasmValType {
166 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
167 match self {
168 WasmValType::I32 => write!(f, "i32"),
169 WasmValType::I64 => write!(f, "i64"),
170 WasmValType::F32 => write!(f, "f32"),
171 WasmValType::F64 => write!(f, "f64"),
172 WasmValType::V128 => write!(f, "v128"),
173 WasmValType::Ref(rt) => write!(f, "{rt}"),
174 }
175 }
176}
177
178impl TypeTrace for WasmValType {
179 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
180 where
181 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
182 {
183 match self {
184 WasmValType::Ref(r) => r.trace(func),
185 WasmValType::I32
186 | WasmValType::I64
187 | WasmValType::F32
188 | WasmValType::F64
189 | WasmValType::V128 => Ok(()),
190 }
191 }
192
193 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
194 where
195 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
196 {
197 match self {
198 WasmValType::Ref(r) => r.trace_mut(func),
199 WasmValType::I32
200 | WasmValType::I64
201 | WasmValType::F32
202 | WasmValType::F64
203 | WasmValType::V128 => Ok(()),
204 }
205 }
206}
207
208impl WasmValType {
209 pub const FUNCREF: WasmValType = WasmValType::Ref(WasmRefType::FUNCREF);
211
212 #[inline]
214 pub fn is_vmgcref_type(&self) -> bool {
215 match self {
216 WasmValType::Ref(r) => r.is_vmgcref_type(),
217 _ => false,
218 }
219 }
220
221 #[inline]
227 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
228 match self {
229 WasmValType::Ref(r) => r.is_vmgcref_type_and_not_i31(),
230 _ => false,
231 }
232 }
233
234 fn trampoline_type(&self) -> Self {
235 match self {
236 WasmValType::Ref(r) => WasmValType::Ref(WasmRefType {
237 nullable: true,
238 heap_type: r.heap_type.top().into(),
239 }),
240 WasmValType::I32
241 | WasmValType::I64
242 | WasmValType::F32
243 | WasmValType::F64
244 | WasmValType::V128 => *self,
245 }
246 }
247
248 pub fn int_from_bits(bits: u8) -> Self {
252 match bits {
253 32 => Self::I32,
254 64 => Self::I64,
255 size => panic!("invalid int bits for WasmValType: {size}"),
256 }
257 }
258
259 pub fn unwrap_ref_type(&self) -> WasmRefType {
263 match self {
264 WasmValType::Ref(ref_type) => *ref_type,
265 _ => panic!("Called WasmValType::unwrap_ref_type on non-reference type"),
266 }
267 }
268}
269
270#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
272pub struct WasmRefType {
273 pub nullable: bool,
275 pub heap_type: WasmHeapType,
277}
278
279impl TypeTrace for WasmRefType {
280 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
281 where
282 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
283 {
284 self.heap_type.trace(func)
285 }
286
287 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
288 where
289 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
290 {
291 self.heap_type.trace_mut(func)
292 }
293}
294
295impl WasmRefType {
296 pub const EXTERNREF: WasmRefType = WasmRefType {
298 nullable: true,
299 heap_type: WasmHeapType::Extern,
300 };
301 pub const FUNCREF: WasmRefType = WasmRefType {
303 nullable: true,
304 heap_type: WasmHeapType::Func,
305 };
306
307 #[inline]
309 pub fn is_vmgcref_type(&self) -> bool {
310 self.heap_type.is_vmgcref_type()
311 }
312
313 #[inline]
319 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
320 self.heap_type.is_vmgcref_type_and_not_i31()
321 }
322}
323
324impl fmt::Display for WasmRefType {
325 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
326 match *self {
327 Self::FUNCREF => write!(f, "funcref"),
328 Self::EXTERNREF => write!(f, "externref"),
329 _ => {
330 if self.nullable {
331 write!(f, "(ref null {})", self.heap_type)
332 } else {
333 write!(f, "(ref {})", self.heap_type)
334 }
335 }
336 }
337 }
338}
339
340#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
345pub enum EngineOrModuleTypeIndex {
346 Engine(VMSharedTypeIndex),
349
350 Module(ModuleInternedTypeIndex),
353
354 RecGroup(RecGroupRelativeTypeIndex),
358}
359
360impl From<ModuleInternedTypeIndex> for EngineOrModuleTypeIndex {
361 #[inline]
362 fn from(i: ModuleInternedTypeIndex) -> Self {
363 Self::Module(i)
364 }
365}
366
367impl From<VMSharedTypeIndex> for EngineOrModuleTypeIndex {
368 #[inline]
369 fn from(i: VMSharedTypeIndex) -> Self {
370 Self::Engine(i)
371 }
372}
373
374impl From<RecGroupRelativeTypeIndex> for EngineOrModuleTypeIndex {
375 #[inline]
376 fn from(i: RecGroupRelativeTypeIndex) -> Self {
377 Self::RecGroup(i)
378 }
379}
380
381impl fmt::Display for EngineOrModuleTypeIndex {
382 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
383 match self {
384 Self::Engine(i) => write!(f, "(engine {})", i.bits()),
385 Self::Module(i) => write!(f, "(module {})", i.as_u32()),
386 Self::RecGroup(i) => write!(f, "(recgroup {})", i.as_u32()),
387 }
388 }
389}
390
391impl EngineOrModuleTypeIndex {
392 pub fn is_engine_type_index(self) -> bool {
394 matches!(self, Self::Engine(_))
395 }
396
397 #[inline]
399 pub fn as_engine_type_index(self) -> Option<VMSharedTypeIndex> {
400 match self {
401 Self::Engine(e) => Some(e),
402 Self::RecGroup(_) | Self::Module(_) => None,
403 }
404 }
405
406 #[track_caller]
408 #[inline]
409 pub fn unwrap_engine_type_index(self) -> VMSharedTypeIndex {
410 match self.as_engine_type_index() {
411 Some(x) => x,
412 None => panic!("`unwrap_engine_type_index` on {self:?}"),
413 }
414 }
415
416 pub fn is_module_type_index(self) -> bool {
418 matches!(self, Self::Module(_))
419 }
420
421 pub fn as_module_type_index(self) -> Option<ModuleInternedTypeIndex> {
423 match self {
424 Self::Module(e) => Some(e),
425 Self::RecGroup(_) | Self::Engine(_) => None,
426 }
427 }
428
429 #[track_caller]
431 pub fn unwrap_module_type_index(self) -> ModuleInternedTypeIndex {
432 match self.as_module_type_index() {
433 Some(x) => x,
434 None => panic!("`unwrap_module_type_index` on {self:?}"),
435 }
436 }
437
438 pub fn is_rec_group_type_index(self) -> bool {
440 matches!(self, Self::RecGroup(_))
441 }
442
443 pub fn as_rec_group_type_index(self) -> Option<RecGroupRelativeTypeIndex> {
445 match self {
446 Self::RecGroup(r) => Some(r),
447 Self::Module(_) | Self::Engine(_) => None,
448 }
449 }
450
451 #[track_caller]
453 pub fn unwrap_rec_group_type_index(self) -> RecGroupRelativeTypeIndex {
454 match self.as_rec_group_type_index() {
455 Some(x) => x,
456 None => panic!("`unwrap_rec_group_type_index` on {self:?}"),
457 }
458 }
459}
460
461#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
463#[expect(missing_docs, reason = "self-describing variants")]
464pub enum WasmHeapType {
465 Extern,
467 NoExtern,
468
469 Func,
471 ConcreteFunc(EngineOrModuleTypeIndex),
472 NoFunc,
473
474 Exn,
476 ConcreteExn(EngineOrModuleTypeIndex),
477 NoExn,
478
479 Cont,
481 ConcreteCont(EngineOrModuleTypeIndex),
482 NoCont,
483
484 Any,
486 Eq,
487 I31,
488 Array,
489 ConcreteArray(EngineOrModuleTypeIndex),
490 Struct,
491 ConcreteStruct(EngineOrModuleTypeIndex),
492 None,
493}
494
495impl From<WasmHeapTopType> for WasmHeapType {
496 #[inline]
497 fn from(value: WasmHeapTopType) -> Self {
498 match value {
499 WasmHeapTopType::Extern => Self::Extern,
500 WasmHeapTopType::Any => Self::Any,
501 WasmHeapTopType::Func => Self::Func,
502 WasmHeapTopType::Cont => Self::Cont,
503 WasmHeapTopType::Exn => Self::Exn,
504 }
505 }
506}
507
508impl From<WasmHeapBottomType> for WasmHeapType {
509 #[inline]
510 fn from(value: WasmHeapBottomType) -> Self {
511 match value {
512 WasmHeapBottomType::NoExtern => Self::NoExtern,
513 WasmHeapBottomType::None => Self::None,
514 WasmHeapBottomType::NoFunc => Self::NoFunc,
515 WasmHeapBottomType::NoCont => Self::NoCont,
516 WasmHeapBottomType::NoExn => Self::NoExn,
517 }
518 }
519}
520
521impl fmt::Display for WasmHeapType {
522 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
523 match self {
524 Self::Extern => write!(f, "extern"),
525 Self::NoExtern => write!(f, "noextern"),
526 Self::Func => write!(f, "func"),
527 Self::ConcreteFunc(i) => write!(f, "func {i}"),
528 Self::NoFunc => write!(f, "nofunc"),
529 Self::Cont => write!(f, "cont"),
530 Self::ConcreteCont(i) => write!(f, "cont {i}"),
531 Self::NoCont => write!(f, "nocont"),
532 Self::Any => write!(f, "any"),
533 Self::Eq => write!(f, "eq"),
534 Self::I31 => write!(f, "i31"),
535 Self::Array => write!(f, "array"),
536 Self::ConcreteArray(i) => write!(f, "array {i}"),
537 Self::Struct => write!(f, "struct"),
538 Self::ConcreteStruct(i) => write!(f, "struct {i}"),
539 Self::Exn => write!(f, "exn"),
540 Self::ConcreteExn(i) => write!(f, "exn {i}"),
541 Self::NoExn => write!(f, "noexn"),
542 Self::None => write!(f, "none"),
543 }
544 }
545}
546
547impl TypeTrace for WasmHeapType {
548 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
549 where
550 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
551 {
552 match *self {
553 Self::ConcreteArray(i) => func(i),
554 Self::ConcreteFunc(i) => func(i),
555 Self::ConcreteStruct(i) => func(i),
556 Self::ConcreteCont(i) => func(i),
557 Self::ConcreteExn(i) => func(i),
558 Self::Extern
561 | Self::NoExtern
562 | Self::Func
563 | Self::NoFunc
564 | Self::Cont
565 | Self::NoCont
566 | Self::Any
567 | Self::Eq
568 | Self::I31
569 | Self::Array
570 | Self::Struct
571 | Self::Exn
572 | Self::NoExn
573 | Self::None => Ok(()),
574 }
575 }
576
577 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
578 where
579 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
580 {
581 match self {
582 Self::ConcreteArray(i) => func(i),
583 Self::ConcreteFunc(i) => func(i),
584 Self::ConcreteStruct(i) => func(i),
585 Self::ConcreteCont(i) => func(i),
586 Self::ConcreteExn(i) => func(i),
587 Self::Extern
590 | Self::NoExtern
591 | Self::Func
592 | Self::NoFunc
593 | Self::Cont
594 | Self::NoCont
595 | Self::Any
596 | Self::Eq
597 | Self::I31
598 | Self::Array
599 | Self::Struct
600 | Self::Exn
601 | Self::NoExn
602 | Self::None => Ok(()),
603 }
604 }
605}
606
607impl WasmHeapType {
608 #[inline]
610 pub fn is_vmgcref_type(&self) -> bool {
611 match self.top() {
612 WasmHeapTopType::Any | WasmHeapTopType::Extern | WasmHeapTopType::Exn => true,
616
617 WasmHeapTopType::Func => false,
619 WasmHeapTopType::Cont => false,
620 }
621 }
622
623 #[inline]
629 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
630 self.is_vmgcref_type() && *self != Self::I31
631 }
632
633 #[inline]
635 pub fn is_top(&self) -> bool {
636 *self == Self::from(self.top())
637 }
638
639 #[inline]
641 pub fn top(&self) -> WasmHeapTopType {
642 match self {
643 WasmHeapType::Extern | WasmHeapType::NoExtern => WasmHeapTopType::Extern,
644
645 WasmHeapType::Func | WasmHeapType::ConcreteFunc(_) | WasmHeapType::NoFunc => {
646 WasmHeapTopType::Func
647 }
648
649 WasmHeapType::Cont | WasmHeapType::ConcreteCont(_) | WasmHeapType::NoCont => {
650 WasmHeapTopType::Cont
651 }
652
653 WasmHeapType::Exn | WasmHeapType::ConcreteExn(_) | WasmHeapType::NoExn => {
654 WasmHeapTopType::Exn
655 }
656
657 WasmHeapType::Any
658 | WasmHeapType::Eq
659 | WasmHeapType::I31
660 | WasmHeapType::Array
661 | WasmHeapType::ConcreteArray(_)
662 | WasmHeapType::Struct
663 | WasmHeapType::ConcreteStruct(_)
664 | WasmHeapType::None => WasmHeapTopType::Any,
665 }
666 }
667
668 #[inline]
670 pub fn is_bottom(&self) -> bool {
671 *self == Self::from(self.bottom())
672 }
673
674 #[inline]
676 pub fn bottom(&self) -> WasmHeapBottomType {
677 match self {
678 WasmHeapType::Extern | WasmHeapType::NoExtern => WasmHeapBottomType::NoExtern,
679
680 WasmHeapType::Func | WasmHeapType::ConcreteFunc(_) | WasmHeapType::NoFunc => {
681 WasmHeapBottomType::NoFunc
682 }
683
684 WasmHeapType::Cont | WasmHeapType::ConcreteCont(_) | WasmHeapType::NoCont => {
685 WasmHeapBottomType::NoCont
686 }
687
688 WasmHeapType::Exn | WasmHeapType::ConcreteExn(_) | WasmHeapType::NoExn => {
689 WasmHeapBottomType::NoExn
690 }
691
692 WasmHeapType::Any
693 | WasmHeapType::Eq
694 | WasmHeapType::I31
695 | WasmHeapType::Array
696 | WasmHeapType::ConcreteArray(_)
697 | WasmHeapType::Struct
698 | WasmHeapType::ConcreteStruct(_)
699 | WasmHeapType::None => WasmHeapBottomType::None,
700 }
701 }
702}
703
704#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
706pub enum WasmHeapTopType {
707 Extern,
709 Any,
711 Func,
713 Exn,
715 Cont,
717}
718
719#[derive(Debug, Clone, Copy, Eq, PartialEq)]
721pub enum WasmHeapBottomType {
722 NoExtern,
724 None,
726 NoFunc,
728 NoExn,
730 NoCont,
732}
733
734#[derive(Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
736pub struct WasmFuncType {
737 #[serde(deserialize_with = "deserialize_boxed_slice")]
738 params_results: Box<[WasmValType]>,
739 params_len: u32,
740 non_i31_gc_ref_params_count: u32,
741 non_i31_gc_ref_results_count: u32,
742}
743
744impl TryClone for WasmFuncType {
745 fn try_clone(&self) -> Result<Self, OutOfMemory> {
746 Ok(Self {
747 params_results: TryClone::try_clone(&self.params_results)?,
748 params_len: self.params_len,
749 non_i31_gc_ref_params_count: self.non_i31_gc_ref_params_count,
750 non_i31_gc_ref_results_count: self.non_i31_gc_ref_results_count,
751 })
752 }
753}
754
755impl fmt::Display for WasmFuncType {
756 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
757 write!(f, "(func")?;
758 if !self.params().is_empty() {
759 write!(f, " (param")?;
760 for p in self.params() {
761 write!(f, " {p}")?;
762 }
763 write!(f, ")")?;
764 }
765 if !self.results().is_empty() {
766 write!(f, " (result")?;
767 for r in self.results() {
768 write!(f, " {r}")?;
769 }
770 write!(f, ")")?;
771 }
772 write!(f, ")")
773 }
774}
775
776impl TypeTrace for WasmFuncType {
777 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
778 where
779 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
780 {
781 for ty in self.params_results.iter() {
782 ty.trace(func)?;
783 }
784 Ok(())
785 }
786
787 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
788 where
789 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
790 {
791 for ty in self.params_results.iter_mut() {
792 ty.trace_mut(func)?;
793 }
794 Ok(())
795 }
796}
797
798impl WasmFuncType {
799 #[inline]
801 pub fn new(
802 params: impl IntoIterator<Item = WasmValType>,
803 results: impl IntoIterator<Item = WasmValType>,
804 ) -> Result<Self, OutOfMemory> {
805 let mut params_results: crate::collections::TryVec<_> = params.into_iter().try_collect()?;
806 let non_i31_gc_ref_params_count = params_results
807 .iter()
808 .filter(|p| p.is_vmgcref_type_and_not_i31())
809 .count();
810
811 let params_len = params_results.len();
812 params_results.try_extend(results)?;
813 let non_i31_gc_ref_results_count = params_results[params_len..]
814 .iter()
815 .filter(|r| r.is_vmgcref_type_and_not_i31())
816 .count();
817
818 let params_results = params_results.into_boxed_slice()?;
819 let params_len = u32::try_from(params_len).unwrap();
820 let non_i31_gc_ref_params_count = u32::try_from(non_i31_gc_ref_params_count).unwrap();
821 let non_i31_gc_ref_results_count = u32::try_from(non_i31_gc_ref_results_count).unwrap();
822
823 Ok(Self {
824 params_results,
825 params_len,
826 non_i31_gc_ref_params_count,
827 non_i31_gc_ref_results_count,
828 })
829 }
830
831 fn results_start(&self) -> usize {
832 usize::try_from(self.params_len).unwrap()
833 }
834
835 #[inline]
837 pub fn params(&self) -> &[WasmValType] {
838 &self.params_results[..self.results_start()]
839 }
840
841 #[inline]
843 pub fn non_i31_gc_ref_params_count(&self) -> usize {
844 usize::try_from(self.non_i31_gc_ref_params_count).unwrap()
845 }
846
847 #[inline]
849 pub fn results(&self) -> &[WasmValType] {
850 &self.params_results[self.results_start()..]
851 }
852
853 #[inline]
855 pub fn non_i31_gc_ref_results_count(&self) -> usize {
856 usize::try_from(self.non_i31_gc_ref_results_count).unwrap()
857 }
858
859 pub fn is_trampoline_type(&self) -> bool {
861 self.params().iter().all(|p| *p == p.trampoline_type())
862 && self.results().iter().all(|r| *r == r.trampoline_type())
863 }
864
865 pub fn trampoline_type(&self) -> Result<TryCow<'_, Self>, OutOfMemory> {
891 if self.is_trampoline_type() {
892 return Ok(TryCow::Borrowed(self));
893 }
894
895 Ok(TryCow::Owned(Self::new(
896 self.params().iter().map(|p| p.trampoline_type()),
897 self.results().iter().map(|r| r.trampoline_type()),
898 )?))
899 }
900}
901
902#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
904pub struct WasmContType(EngineOrModuleTypeIndex);
905
906impl fmt::Display for WasmContType {
907 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
908 write!(f, "(cont {})", self.0)
909 }
910}
911
912impl WasmContType {
913 pub fn new(idx: EngineOrModuleTypeIndex) -> Self {
915 WasmContType(idx)
916 }
917
918 pub fn unwrap_module_type_index(self) -> ModuleInternedTypeIndex {
920 match self.0 {
921 EngineOrModuleTypeIndex::Engine(_) => panic!("not module interned"),
922 EngineOrModuleTypeIndex::Module(idx) => idx,
923 EngineOrModuleTypeIndex::RecGroup(_) => todo!(),
924 }
925 }
926}
927
928impl TypeTrace for WasmContType {
929 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
930 where
931 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
932 {
933 func(self.0)
934 }
935
936 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
937 where
938 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
939 {
940 func(&mut self.0)
941 }
942}
943
944#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
969pub struct WasmExnType {
970 pub func_ty: EngineOrModuleTypeIndex,
974 #[serde(deserialize_with = "deserialize_boxed_slice")]
981 pub fields: Box<[WasmFieldType]>,
982}
983
984impl TryClone for WasmExnType {
985 fn try_clone(&self) -> Result<Self, OutOfMemory> {
986 Ok(Self {
987 func_ty: self.func_ty,
988 fields: self.fields.try_clone()?,
989 })
990 }
991}
992
993impl fmt::Display for WasmExnType {
994 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
995 write!(f, "(exn ({})", self.func_ty)?;
996 for ty in self.fields.iter() {
997 write!(f, " {ty}")?;
998 }
999 write!(f, ")")
1000 }
1001}
1002
1003impl TypeTrace for WasmExnType {
1004 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1005 where
1006 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1007 {
1008 func(self.func_ty)?;
1009 for f in self.fields.iter() {
1010 f.trace(func)?;
1011 }
1012 Ok(())
1013 }
1014
1015 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1016 where
1017 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1018 {
1019 func(&mut self.func_ty)?;
1020 for f in self.fields.iter_mut() {
1021 f.trace_mut(func)?;
1022 }
1023 Ok(())
1024 }
1025}
1026
1027#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1029pub enum WasmStorageType {
1030 I8,
1032 I16,
1034 Val(WasmValType),
1036}
1037
1038impl fmt::Display for WasmStorageType {
1039 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1040 match self {
1041 WasmStorageType::I8 => write!(f, "i8"),
1042 WasmStorageType::I16 => write!(f, "i16"),
1043 WasmStorageType::Val(v) => fmt::Display::fmt(v, f),
1044 }
1045 }
1046}
1047
1048impl TypeTrace for WasmStorageType {
1049 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1050 where
1051 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1052 {
1053 match self {
1054 WasmStorageType::I8 | WasmStorageType::I16 => Ok(()),
1055 WasmStorageType::Val(v) => v.trace(func),
1056 }
1057 }
1058
1059 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1060 where
1061 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1062 {
1063 match self {
1064 WasmStorageType::I8 | WasmStorageType::I16 => Ok(()),
1065 WasmStorageType::Val(v) => v.trace_mut(func),
1066 }
1067 }
1068}
1069
1070impl WasmStorageType {
1071 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
1077 match self {
1078 WasmStorageType::I8 | WasmStorageType::I16 => false,
1079 WasmStorageType::Val(v) => v.is_vmgcref_type_and_not_i31(),
1080 }
1081 }
1082}
1083
1084#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
1086pub struct WasmFieldType {
1087 pub element_type: WasmStorageType,
1089
1090 pub mutable: bool,
1092}
1093
1094impl TryClone for WasmFieldType {
1095 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1096 Ok(*self)
1097 }
1098}
1099
1100impl fmt::Display for WasmFieldType {
1101 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1102 if self.mutable {
1103 write!(f, "(mut {})", self.element_type)
1104 } else {
1105 fmt::Display::fmt(&self.element_type, f)
1106 }
1107 }
1108}
1109
1110impl TypeTrace for WasmFieldType {
1111 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1112 where
1113 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1114 {
1115 self.element_type.trace(func)
1116 }
1117
1118 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1119 where
1120 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1121 {
1122 self.element_type.trace_mut(func)
1123 }
1124}
1125
1126#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
1128pub struct WasmArrayType(pub WasmFieldType);
1129
1130impl fmt::Display for WasmArrayType {
1131 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1132 write!(f, "(array {})", self.0)
1133 }
1134}
1135
1136impl TypeTrace for WasmArrayType {
1137 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1138 where
1139 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1140 {
1141 self.0.trace(func)
1142 }
1143
1144 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1145 where
1146 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1147 {
1148 self.0.trace_mut(func)
1149 }
1150}
1151
1152#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1154pub struct WasmStructType {
1155 #[serde(deserialize_with = "deserialize_boxed_slice")]
1157 pub fields: Box<[WasmFieldType]>,
1158}
1159
1160impl TryClone for WasmStructType {
1161 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1162 Ok(Self {
1163 fields: self.fields.try_clone()?,
1164 })
1165 }
1166}
1167
1168impl fmt::Display for WasmStructType {
1169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1170 write!(f, "(struct")?;
1171 for ty in self.fields.iter() {
1172 write!(f, " {ty}")?;
1173 }
1174 write!(f, ")")
1175 }
1176}
1177
1178impl TypeTrace for WasmStructType {
1179 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1180 where
1181 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1182 {
1183 for f in self.fields.iter() {
1184 f.trace(func)?;
1185 }
1186 Ok(())
1187 }
1188
1189 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1190 where
1191 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1192 {
1193 for f in self.fields.iter_mut() {
1194 f.trace_mut(func)?;
1195 }
1196 Ok(())
1197 }
1198}
1199
1200#[derive(Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1201#[expect(missing_docs, reason = "self-describing type")]
1202pub struct WasmCompositeType {
1203 pub inner: WasmCompositeInnerType,
1205 pub shared: bool,
1208}
1209
1210impl TryClone for WasmCompositeType {
1211 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1212 Ok(Self {
1213 inner: self.inner.try_clone()?,
1214 shared: self.shared,
1215 })
1216 }
1217}
1218
1219impl fmt::Display for WasmCompositeType {
1220 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1221 if self.shared {
1222 write!(f, "(shared ")?;
1223 }
1224 fmt::Display::fmt(&self.inner, f)?;
1225 if self.shared {
1226 write!(f, ")")?;
1227 }
1228 Ok(())
1229 }
1230}
1231
1232#[derive(Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1234#[expect(missing_docs, reason = "self-describing variants")]
1235pub enum WasmCompositeInnerType {
1236 Array(WasmArrayType),
1237 Func(WasmFuncType),
1238 Struct(WasmStructType),
1239 Cont(WasmContType),
1240 Exn(WasmExnType),
1241}
1242
1243impl TryClone for WasmCompositeInnerType {
1244 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1245 Ok(match self {
1246 Self::Array(ty) => Self::Array(*ty),
1247 Self::Func(ty) => Self::Func(ty.try_clone()?),
1248 Self::Struct(ty) => Self::Struct(ty.try_clone()?),
1249 Self::Cont(ty) => Self::Cont(*ty),
1250 Self::Exn(ty) => Self::Exn(ty.try_clone()?),
1251 })
1252 }
1253}
1254
1255impl fmt::Display for WasmCompositeInnerType {
1256 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1257 match self {
1258 Self::Array(ty) => fmt::Display::fmt(ty, f),
1259 Self::Func(ty) => fmt::Display::fmt(ty, f),
1260 Self::Struct(ty) => fmt::Display::fmt(ty, f),
1261 Self::Cont(ty) => fmt::Display::fmt(ty, f),
1262 Self::Exn(ty) => fmt::Display::fmt(ty, f),
1263 }
1264 }
1265}
1266
1267#[expect(missing_docs, reason = "self-describing functions")]
1268impl WasmCompositeInnerType {
1269 #[inline]
1270 pub fn is_array(&self) -> bool {
1271 matches!(self, Self::Array(_))
1272 }
1273
1274 #[inline]
1275 pub fn as_array(&self) -> Option<&WasmArrayType> {
1276 match self {
1277 Self::Array(f) => Some(f),
1278 _ => None,
1279 }
1280 }
1281
1282 #[inline]
1283 pub fn unwrap_array(&self) -> &WasmArrayType {
1284 self.as_array().unwrap()
1285 }
1286
1287 #[inline]
1288 pub fn is_func(&self) -> bool {
1289 matches!(self, Self::Func(_))
1290 }
1291
1292 #[inline]
1293 pub fn as_func(&self) -> Option<&WasmFuncType> {
1294 match self {
1295 Self::Func(f) => Some(f),
1296 _ => None,
1297 }
1298 }
1299
1300 #[inline]
1301 pub fn unwrap_func(&self) -> &WasmFuncType {
1302 self.as_func().unwrap()
1303 }
1304
1305 #[inline]
1306 pub fn is_struct(&self) -> bool {
1307 matches!(self, Self::Struct(_))
1308 }
1309
1310 #[inline]
1311 pub fn as_struct(&self) -> Option<&WasmStructType> {
1312 match self {
1313 Self::Struct(f) => Some(f),
1314 _ => None,
1315 }
1316 }
1317
1318 #[inline]
1319 pub fn unwrap_struct(&self) -> &WasmStructType {
1320 self.as_struct().unwrap()
1321 }
1322
1323 #[inline]
1324 pub fn is_cont(&self) -> bool {
1325 matches!(self, Self::Cont(_))
1326 }
1327
1328 #[inline]
1329 pub fn as_cont(&self) -> Option<&WasmContType> {
1330 match self {
1331 Self::Cont(f) => Some(f),
1332 _ => None,
1333 }
1334 }
1335
1336 #[inline]
1337 pub fn unwrap_cont(&self) -> &WasmContType {
1338 self.as_cont().unwrap()
1339 }
1340
1341 #[inline]
1342 pub fn is_exn(&self) -> bool {
1343 matches!(self, Self::Exn(_))
1344 }
1345
1346 #[inline]
1347 pub fn as_exn(&self) -> Option<&WasmExnType> {
1348 match self {
1349 Self::Exn(f) => Some(f),
1350 _ => None,
1351 }
1352 }
1353
1354 #[inline]
1355 pub fn unwrap_exn(&self) -> &WasmExnType {
1356 self.as_exn().unwrap()
1357 }
1358}
1359
1360impl TypeTrace for WasmCompositeType {
1361 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1362 where
1363 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1364 {
1365 match &self.inner {
1366 WasmCompositeInnerType::Array(a) => a.trace(func),
1367 WasmCompositeInnerType::Func(f) => f.trace(func),
1368 WasmCompositeInnerType::Struct(a) => a.trace(func),
1369 WasmCompositeInnerType::Cont(c) => c.trace(func),
1370 WasmCompositeInnerType::Exn(e) => e.trace(func),
1371 }
1372 }
1373
1374 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1375 where
1376 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1377 {
1378 match &mut self.inner {
1379 WasmCompositeInnerType::Array(a) => a.trace_mut(func),
1380 WasmCompositeInnerType::Func(f) => f.trace_mut(func),
1381 WasmCompositeInnerType::Struct(a) => a.trace_mut(func),
1382 WasmCompositeInnerType::Cont(c) => c.trace_mut(func),
1383 WasmCompositeInnerType::Exn(e) => e.trace_mut(func),
1384 }
1385 }
1386}
1387
1388#[derive(Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1390pub struct WasmSubType {
1391 pub is_final: bool,
1394
1395 pub supertype: Option<EngineOrModuleTypeIndex>,
1397
1398 pub composite_type: WasmCompositeType,
1400}
1401
1402impl TryClone for WasmSubType {
1403 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1404 Ok(Self {
1405 is_final: self.is_final,
1406 supertype: self.supertype,
1407 composite_type: self.composite_type.try_clone()?,
1408 })
1409 }
1410}
1411
1412impl fmt::Display for WasmSubType {
1413 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1414 if self.is_final && self.supertype.is_none() {
1415 fmt::Display::fmt(&self.composite_type, f)
1416 } else {
1417 write!(f, "(sub")?;
1418 if self.is_final {
1419 write!(f, " final")?;
1420 }
1421 if let Some(sup) = self.supertype {
1422 write!(f, " {sup}")?;
1423 }
1424 write!(f, " {})", self.composite_type)
1425 }
1426 }
1427}
1428
1429#[expect(missing_docs, reason = "self-describing functions")]
1433impl WasmSubType {
1434 #[inline]
1435 pub fn is_func(&self) -> bool {
1436 self.composite_type.inner.is_func() && !self.composite_type.shared
1437 }
1438
1439 #[inline]
1440 pub fn as_func(&self) -> Option<&WasmFuncType> {
1441 if self.composite_type.shared {
1442 None
1443 } else {
1444 self.composite_type.inner.as_func()
1445 }
1446 }
1447
1448 #[inline]
1449 pub fn unwrap_func(&self) -> &WasmFuncType {
1450 assert!(!self.composite_type.shared);
1451 self.composite_type.inner.unwrap_func()
1452 }
1453
1454 #[inline]
1455 pub fn is_array(&self) -> bool {
1456 self.composite_type.inner.is_array() && !self.composite_type.shared
1457 }
1458
1459 #[inline]
1460 pub fn as_array(&self) -> Option<&WasmArrayType> {
1461 if self.composite_type.shared {
1462 None
1463 } else {
1464 self.composite_type.inner.as_array()
1465 }
1466 }
1467
1468 #[inline]
1469 pub fn unwrap_array(&self) -> &WasmArrayType {
1470 assert!(!self.composite_type.shared);
1471 self.composite_type.inner.unwrap_array()
1472 }
1473
1474 #[inline]
1475 pub fn is_struct(&self) -> bool {
1476 self.composite_type.inner.is_struct() && !self.composite_type.shared
1477 }
1478
1479 #[inline]
1480 pub fn as_struct(&self) -> Option<&WasmStructType> {
1481 if self.composite_type.shared {
1482 None
1483 } else {
1484 self.composite_type.inner.as_struct()
1485 }
1486 }
1487
1488 #[inline]
1489 pub fn unwrap_struct(&self) -> &WasmStructType {
1490 assert!(!self.composite_type.shared);
1491 self.composite_type.inner.unwrap_struct()
1492 }
1493
1494 #[inline]
1495 pub fn is_cont(&self) -> bool {
1496 self.composite_type.inner.is_cont() && !self.composite_type.shared
1497 }
1498
1499 #[inline]
1500 pub fn as_cont(&self) -> Option<&WasmContType> {
1501 if self.composite_type.shared {
1502 None
1503 } else {
1504 self.composite_type.inner.as_cont()
1505 }
1506 }
1507
1508 #[inline]
1509 pub fn unwrap_cont(&self) -> &WasmContType {
1510 assert!(!self.composite_type.shared);
1511 self.composite_type.inner.unwrap_cont()
1512 }
1513
1514 #[inline]
1515 pub fn is_exn(&self) -> bool {
1516 self.composite_type.inner.is_exn() && !self.composite_type.shared
1517 }
1518
1519 #[inline]
1520 pub fn as_exn(&self) -> Option<&WasmExnType> {
1521 if self.composite_type.shared {
1522 None
1523 } else {
1524 self.composite_type.inner.as_exn()
1525 }
1526 }
1527
1528 #[inline]
1529 pub fn unwrap_exn(&self) -> &WasmExnType {
1530 assert!(!self.composite_type.shared);
1531 self.composite_type.inner.unwrap_exn()
1532 }
1533}
1534
1535impl TypeTrace for WasmSubType {
1536 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1537 where
1538 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1539 {
1540 if let Some(sup) = self.supertype {
1541 func(sup)?;
1542 }
1543 self.composite_type.trace(func)
1544 }
1545
1546 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1547 where
1548 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1549 {
1550 if let Some(sup) = self.supertype.as_mut() {
1551 func(sup)?;
1552 }
1553 self.composite_type.trace_mut(func)
1554 }
1555}
1556
1557#[derive(Debug, Default, Eq, PartialEq, Hash, Serialize, Deserialize)]
1568pub struct WasmRecGroup {
1569 #[serde(deserialize_with = "deserialize_boxed_slice")]
1571 pub types: Box<[WasmSubType]>,
1572}
1573
1574impl TypeTrace for WasmRecGroup {
1575 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1576 where
1577 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1578 {
1579 for ty in self.types.iter() {
1580 ty.trace(func)?;
1581 }
1582 Ok(())
1583 }
1584
1585 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1586 where
1587 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1588 {
1589 for ty in self.types.iter_mut() {
1590 ty.trace_mut(func)?;
1591 }
1592 Ok(())
1593 }
1594}
1595
1596macro_rules! entity_impl_with_try_clone {
1597 ( $ty:ident ) => {
1598 cranelift_entity::entity_impl!($ty);
1599
1600 impl TryClone for $ty {
1601 #[inline]
1602 fn try_clone(&self) -> Result<Self, $crate::error::OutOfMemory> {
1603 Ok(*self)
1604 }
1605 }
1606 };
1607}
1608
1609#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1611pub struct FuncIndex(u32);
1612entity_impl_with_try_clone!(FuncIndex);
1613
1614#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1616pub struct DefinedFuncIndex(u32);
1617entity_impl_with_try_clone!(DefinedFuncIndex);
1618
1619#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1621pub struct DefinedTableIndex(u32);
1622entity_impl_with_try_clone!(DefinedTableIndex);
1623
1624#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1626pub struct DefinedMemoryIndex(u32);
1627entity_impl_with_try_clone!(DefinedMemoryIndex);
1628
1629#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1631pub struct OwnedMemoryIndex(u32);
1632entity_impl_with_try_clone!(OwnedMemoryIndex);
1633
1634#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1636pub struct DefinedGlobalIndex(u32);
1637entity_impl_with_try_clone!(DefinedGlobalIndex);
1638
1639#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1641pub struct TableIndex(u32);
1642entity_impl_with_try_clone!(TableIndex);
1643
1644#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1646pub struct GlobalIndex(u32);
1647entity_impl_with_try_clone!(GlobalIndex);
1648
1649#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1651pub struct MemoryIndex(u32);
1652entity_impl_with_try_clone!(MemoryIndex);
1653
1654#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1657pub struct ModuleInternedRecGroupIndex(u32);
1658entity_impl_with_try_clone!(ModuleInternedRecGroupIndex);
1659
1660#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1663pub struct EngineInternedRecGroupIndex(u32);
1664entity_impl_with_try_clone!(EngineInternedRecGroupIndex);
1665
1666#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1668pub struct TypeIndex(u32);
1669entity_impl_with_try_clone!(TypeIndex);
1670
1671#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1677pub struct RecGroupRelativeTypeIndex(u32);
1678entity_impl_with_try_clone!(RecGroupRelativeTypeIndex);
1679
1680#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1688pub struct ModuleInternedTypeIndex(u32);
1689entity_impl_with_try_clone!(ModuleInternedTypeIndex);
1690
1691#[repr(transparent)] #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1700pub struct VMSharedTypeIndex(u32);
1701entity_impl_with_try_clone!(VMSharedTypeIndex);
1702
1703impl VMSharedTypeIndex {
1704 #[inline]
1706 pub fn new(value: u32) -> Self {
1707 assert_ne!(
1708 value,
1709 u32::MAX,
1710 "u32::MAX is reserved for the default value"
1711 );
1712 Self(value)
1713 }
1714
1715 #[inline]
1717 pub fn bits(&self) -> u32 {
1718 self.0
1719 }
1720}
1721
1722impl Default for VMSharedTypeIndex {
1723 #[inline]
1724 fn default() -> Self {
1725 Self(u32::MAX)
1726 }
1727}
1728
1729#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1731pub struct DataIndex(u32);
1732entity_impl_with_try_clone!(DataIndex);
1733
1734#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1745pub struct RuntimeDataIndex(u32);
1746entity_impl_with_try_clone!(RuntimeDataIndex);
1747
1748#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1750pub struct ElemIndex(u32);
1751entity_impl_with_try_clone!(ElemIndex);
1752
1753#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1758pub struct PassiveElemIndex(u32);
1759entity_impl_with_try_clone!(PassiveElemIndex);
1760
1761#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1763pub struct DefinedTagIndex(u32);
1764entity_impl_with_try_clone!(DefinedTagIndex);
1765
1766#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1768pub struct TagIndex(u32);
1769entity_impl_with_try_clone!(TagIndex);
1770
1771#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1776pub struct StaticModuleIndex(u32);
1777entity_impl_with_try_clone!(StaticModuleIndex);
1778
1779#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1781pub enum EntityIndex {
1782 Function(FuncIndex),
1784 Table(TableIndex),
1786 Memory(MemoryIndex),
1788 Global(GlobalIndex),
1790 Tag(TagIndex),
1792}
1793
1794impl From<FuncIndex> for EntityIndex {
1795 fn from(idx: FuncIndex) -> EntityIndex {
1796 EntityIndex::Function(idx)
1797 }
1798}
1799
1800impl From<TableIndex> for EntityIndex {
1801 fn from(idx: TableIndex) -> EntityIndex {
1802 EntityIndex::Table(idx)
1803 }
1804}
1805
1806impl From<MemoryIndex> for EntityIndex {
1807 fn from(idx: MemoryIndex) -> EntityIndex {
1808 EntityIndex::Memory(idx)
1809 }
1810}
1811
1812impl From<GlobalIndex> for EntityIndex {
1813 fn from(idx: GlobalIndex) -> EntityIndex {
1814 EntityIndex::Global(idx)
1815 }
1816}
1817
1818impl From<TagIndex> for EntityIndex {
1819 fn from(idx: TagIndex) -> EntityIndex {
1820 EntityIndex::Tag(idx)
1821 }
1822}
1823
1824#[derive(Clone, Debug, Serialize, Deserialize)]
1827pub enum EntityType {
1828 Global(Global),
1830 Memory(Memory),
1832 Tag(Tag),
1834 Table(Table),
1836 Function(EngineOrModuleTypeIndex),
1839}
1840
1841impl TypeTrace for EntityType {
1842 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1843 where
1844 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1845 {
1846 match self {
1847 Self::Global(g) => g.trace(func),
1848 Self::Table(t) => t.trace(func),
1849 Self::Function(idx) => func(*idx),
1850 Self::Memory(_) => Ok(()),
1851 Self::Tag(t) => t.trace(func),
1852 }
1853 }
1854
1855 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1856 where
1857 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1858 {
1859 match self {
1860 Self::Global(g) => g.trace_mut(func),
1861 Self::Table(t) => t.trace_mut(func),
1862 Self::Function(idx) => func(idx),
1863 Self::Memory(_) => Ok(()),
1864 Self::Tag(t) => t.trace_mut(func),
1865 }
1866 }
1867}
1868
1869impl EntityType {
1870 pub fn unwrap_global(&self) -> &Global {
1872 match self {
1873 EntityType::Global(g) => g,
1874 _ => panic!("not a global"),
1875 }
1876 }
1877
1878 pub fn unwrap_memory(&self) -> &Memory {
1880 match self {
1881 EntityType::Memory(g) => g,
1882 _ => panic!("not a memory"),
1883 }
1884 }
1885
1886 pub fn unwrap_tag(&self) -> &Tag {
1888 match self {
1889 EntityType::Tag(g) => g,
1890 _ => panic!("not a tag"),
1891 }
1892 }
1893
1894 pub fn unwrap_table(&self) -> &Table {
1896 match self {
1897 EntityType::Table(g) => g,
1898 _ => panic!("not a table"),
1899 }
1900 }
1901
1902 pub fn unwrap_func(&self) -> EngineOrModuleTypeIndex {
1904 match self {
1905 EntityType::Function(g) => *g,
1906 _ => panic!("not a func"),
1907 }
1908 }
1909}
1910
1911#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1919pub struct Global {
1920 pub wasm_ty: crate::WasmValType,
1922 pub mutability: bool,
1924}
1925
1926impl TypeTrace for Global {
1927 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1928 where
1929 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1930 {
1931 let Global {
1932 wasm_ty,
1933 mutability: _,
1934 } = self;
1935 wasm_ty.trace(func)
1936 }
1937
1938 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1939 where
1940 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1941 {
1942 let Global {
1943 wasm_ty,
1944 mutability: _,
1945 } = self;
1946 wasm_ty.trace_mut(func)
1947 }
1948}
1949
1950#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1954pub struct ConstExpr {
1955 ops: SmallVec<[ConstOp; 2]>,
1956}
1957
1958impl ConstExpr {
1959 pub fn new(ops: impl IntoIterator<Item = ConstOp>) -> Self {
1965 let ops = ops.into_iter().collect::<SmallVec<[ConstOp; 2]>>();
1966 assert!(!ops.is_empty());
1967 ConstExpr { ops }
1968 }
1969
1970 pub fn from_wasmparser(
1975 env: &dyn TypeConvert,
1976 expr: wasmparser::ConstExpr<'_>,
1977 ) -> WasmResult<(Self, SmallVec<[FuncIndex; 1]>)> {
1978 let mut iter = expr
1979 .get_operators_reader()
1980 .into_iter_with_offsets()
1981 .peekable();
1982
1983 let mut ops = SmallVec::<[ConstOp; 2]>::new();
1984 let mut escaped = SmallVec::<[FuncIndex; 1]>::new();
1985 while let Some(res) = iter.next() {
1986 let (op, offset) = res?;
1987
1988 if matches!(op, wasmparser::Operator::End) && iter.peek().is_none() {
1992 break;
1993 }
1994
1995 if let wasmparser::Operator::RefFunc { function_index } = &op {
1998 escaped.push(FuncIndex::from_u32(*function_index));
1999 }
2000
2001 ops.push(ConstOp::from_wasmparser(env, op, offset)?);
2002 }
2003 Ok((Self { ops }, escaped))
2004 }
2005
2006 #[inline]
2008 pub fn ops(&self) -> &[ConstOp] {
2009 &self.ops
2010 }
2011
2012 pub fn provably_nonzero_i32(&self) -> bool {
2022 match self.const_eval() {
2023 Some(GlobalConstValue::I32(x)) => x != 0,
2024
2025 _ => false,
2028 }
2029 }
2030
2031 pub fn const_eval(&self) -> Option<GlobalConstValue> {
2033 match self.ops() {
2036 [ConstOp::I32Const(x)] => Some(GlobalConstValue::I32(*x)),
2037 [ConstOp::I64Const(x)] => Some(GlobalConstValue::I64(*x)),
2038 [ConstOp::F32Const(x)] => Some(GlobalConstValue::F32(*x)),
2039 [ConstOp::F64Const(x)] => Some(GlobalConstValue::F64(*x)),
2040 [ConstOp::V128Const(x)] => Some(GlobalConstValue::V128(*x)),
2041 _ => None,
2042 }
2043 }
2044}
2045
2046#[expect(missing_docs, reason = "self-describing variants")]
2048#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
2049pub enum GlobalConstValue {
2050 I32(i32),
2051 I64(i64),
2052 F32(u32),
2053 F64(u64),
2054 V128(u128),
2055}
2056
2057#[expect(missing_docs, reason = "self-describing variants")]
2059#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
2060pub enum ConstOp {
2061 I32Const(i32),
2062 I64Const(i64),
2063 F32Const(u32),
2064 F64Const(u64),
2065 V128Const(u128),
2066 GlobalGet(GlobalIndex),
2067 RefI31,
2068 RefNull(WasmHeapType),
2069 RefFunc(FuncIndex),
2070 I32Add,
2071 I32Sub,
2072 I32Mul,
2073 I64Add,
2074 I64Sub,
2075 I64Mul,
2076 StructNew {
2077 struct_type_index: TypeIndex,
2078 },
2079 StructNewDefault {
2080 struct_type_index: TypeIndex,
2081 },
2082 ArrayNew {
2083 array_type_index: TypeIndex,
2084 },
2085 ArrayNewDefault {
2086 array_type_index: TypeIndex,
2087 },
2088 ArrayNewFixed {
2089 array_type_index: TypeIndex,
2090 array_size: u32,
2091 },
2092 ExternConvertAny,
2093 AnyConvertExtern,
2094}
2095
2096impl ConstOp {
2097 pub fn from_wasmparser(
2099 env: &dyn TypeConvert,
2100 op: wasmparser::Operator<'_>,
2101 offset: usize,
2102 ) -> WasmResult<Self> {
2103 use wasmparser::Operator as O;
2104 Ok(match op {
2105 O::I32Const { value } => Self::I32Const(value),
2106 O::I64Const { value } => Self::I64Const(value),
2107 O::F32Const { value } => Self::F32Const(value.bits()),
2108 O::F64Const { value } => Self::F64Const(value.bits()),
2109 O::V128Const { value } => Self::V128Const(u128::from_le_bytes(*value.bytes())),
2110 O::RefNull { hty } => Self::RefNull(env.convert_heap_type(hty)?),
2111 O::RefFunc { function_index } => Self::RefFunc(FuncIndex::from_u32(function_index)),
2112 O::GlobalGet { global_index } => Self::GlobalGet(GlobalIndex::from_u32(global_index)),
2113 O::RefI31 => Self::RefI31,
2114 O::I32Add => Self::I32Add,
2115 O::I32Sub => Self::I32Sub,
2116 O::I32Mul => Self::I32Mul,
2117 O::I64Add => Self::I64Add,
2118 O::I64Sub => Self::I64Sub,
2119 O::I64Mul => Self::I64Mul,
2120 O::StructNew { struct_type_index } => Self::StructNew {
2121 struct_type_index: TypeIndex::from_u32(struct_type_index),
2122 },
2123 O::StructNewDefault { struct_type_index } => Self::StructNewDefault {
2124 struct_type_index: TypeIndex::from_u32(struct_type_index),
2125 },
2126 O::ArrayNew { array_type_index } => Self::ArrayNew {
2127 array_type_index: TypeIndex::from_u32(array_type_index),
2128 },
2129 O::ArrayNewDefault { array_type_index } => Self::ArrayNewDefault {
2130 array_type_index: TypeIndex::from_u32(array_type_index),
2131 },
2132 O::ArrayNewFixed {
2133 array_type_index,
2134 array_size,
2135 } => Self::ArrayNewFixed {
2136 array_type_index: TypeIndex::from_u32(array_type_index),
2137 array_size,
2138 },
2139 O::ExternConvertAny => Self::ExternConvertAny,
2140 O::AnyConvertExtern => Self::AnyConvertExtern,
2141 op => {
2142 return Err(wasm_unsupported!(
2143 "unsupported opcode in const expression at offset {offset:#x}: {op:?}",
2144 ));
2145 }
2146 })
2147 }
2148}
2149
2150#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2152#[expect(missing_docs, reason = "self-describing variants")]
2153pub enum IndexType {
2154 I32,
2155 I64,
2156}
2157
2158#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2160#[expect(missing_docs, reason = "self-describing fields")]
2161pub struct Limits {
2162 pub min: u64,
2163 pub max: Option<u64>,
2164}
2165
2166#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2168pub struct Table {
2169 pub idx_type: IndexType,
2171 pub limits: Limits,
2174 pub ref_type: WasmRefType,
2176}
2177
2178impl TypeTrace for Table {
2179 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
2180 where
2181 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
2182 {
2183 let Table {
2184 ref_type: wasm_ty,
2185 idx_type: _,
2186 limits: _,
2187 } = self;
2188 wasm_ty.trace(func)
2189 }
2190
2191 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
2192 where
2193 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
2194 {
2195 let Table {
2196 ref_type: wasm_ty,
2197 idx_type: _,
2198 limits: _,
2199 } = self;
2200 wasm_ty.trace_mut(func)
2201 }
2202}
2203
2204#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2206pub struct Memory {
2207 pub idx_type: IndexType,
2209 pub limits: Limits,
2212 pub shared: bool,
2214 pub page_size_log2: u8,
2219}
2220
2221pub const WASM32_MAX_SIZE: u64 = 1 << 32;
2223
2224impl Memory {
2225 pub const DEFAULT_PAGE_SIZE: u32 = 0x10000;
2227
2228 pub const DEFAULT_PAGE_SIZE_LOG2: u8 = {
2230 let log2 = 16;
2231 assert!(1 << log2 == Memory::DEFAULT_PAGE_SIZE);
2232 log2
2233 };
2234
2235 pub fn minimum_byte_size(&self) -> Result<u64, SizeOverflow> {
2243 self.limits
2244 .min
2245 .checked_mul(self.page_size())
2246 .ok_or(SizeOverflow)
2247 }
2248
2249 pub fn maximum_byte_size(&self) -> Result<u64, SizeOverflow> {
2264 match self.limits.max {
2265 Some(max) => max.checked_mul(self.page_size()).ok_or(SizeOverflow),
2266 None => {
2267 let min = self.minimum_byte_size()?;
2268 Ok(min.max(self.max_size_based_on_index_type()))
2269 }
2270 }
2271 }
2272
2273 pub fn page_size(&self) -> u64 {
2275 debug_assert!(
2276 self.page_size_log2 == 16 || self.page_size_log2 == 0,
2277 "invalid page_size_log2: {}; must be 16 or 0",
2278 self.page_size_log2
2279 );
2280 1 << self.page_size_log2
2281 }
2282
2283 pub fn max_size_based_on_index_type(&self) -> u64 {
2288 match self.idx_type {
2289 IndexType::I64 =>
2290 {
2298 0_u64.wrapping_sub(self.page_size())
2299 }
2300 IndexType::I32 => WASM32_MAX_SIZE,
2301 }
2302 }
2303
2304 pub fn can_use_virtual_memory(&self, tunables: &Tunables, host_page_size_log2: u8) -> bool {
2316 tunables.signals_based_traps && self.page_size_log2 >= host_page_size_log2
2317 }
2318
2319 pub fn can_elide_bounds_check(
2339 &self,
2340 memory_tunables: &MemoryTunables<'_>,
2341 host_page_size_log2: u8,
2342 ) -> bool {
2343 self.can_use_virtual_memory(memory_tunables.tunables(), host_page_size_log2)
2344 && self.idx_type == IndexType::I32
2345 && memory_tunables.reservation() + memory_tunables.guard_size() >= (1 << 32)
2346 }
2347
2348 pub fn static_heap_size(&self) -> Option<u64> {
2352 let min = self.minimum_byte_size().ok()?;
2353 let max = self.maximum_byte_size().ok()?;
2354 if min == max { Some(min) } else { None }
2355 }
2356
2357 pub fn memory_may_move(&self, memory_tunables: &MemoryTunables<'_>) -> bool {
2364 if self.shared {
2368 return false;
2369 }
2370
2371 if !memory_tunables.may_move() {
2374 return false;
2375 }
2376
2377 if self.limits.max.is_some_and(|max| self.limits.min == max) {
2380 return false;
2381 }
2382
2383 let max = self.maximum_byte_size().unwrap_or(u64::MAX);
2386 max > memory_tunables.reservation()
2387 }
2388
2389 pub fn allow_growth_to(&self, size: usize) -> bool {
2399 if self.page_size_log2 != 0 {
2400 return true;
2401 }
2402 match self.idx_type {
2403 IndexType::I32 => size < 0xffff_ffff,
2412
2413 IndexType::I64 => true,
2416 }
2417 }
2418}
2419
2420#[derive(Copy, Clone, Debug)]
2421#[expect(missing_docs, reason = "self-describing error struct")]
2422pub struct SizeOverflow;
2423
2424impl fmt::Display for SizeOverflow {
2425 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2426 f.write_str("size overflow calculating memory size")
2427 }
2428}
2429
2430impl core::error::Error for SizeOverflow {}
2431
2432impl From<wasmparser::MemoryType> for Memory {
2433 fn from(ty: wasmparser::MemoryType) -> Memory {
2434 let idx_type = match ty.memory64 {
2435 false => IndexType::I32,
2436 true => IndexType::I64,
2437 };
2438 let limits = Limits {
2439 min: ty.initial,
2440 max: ty.maximum,
2441 };
2442 let page_size_log2 = u8::try_from(ty.page_size_log2.unwrap_or(16)).unwrap();
2443 debug_assert!(
2444 page_size_log2 == 16 || page_size_log2 == 0,
2445 "invalid page_size_log2: {page_size_log2}; must be 16 or 0"
2446 );
2447 Memory {
2448 idx_type,
2449 limits,
2450 shared: ty.shared,
2451 page_size_log2,
2452 }
2453 }
2454}
2455
2456#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2458pub struct Tag {
2459 pub signature: EngineOrModuleTypeIndex,
2461 pub exception: EngineOrModuleTypeIndex,
2463}
2464
2465impl TypeTrace for Tag {
2466 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
2467 where
2468 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
2469 {
2470 func(self.signature)?;
2471 func(self.exception)?;
2472 Ok(())
2473 }
2474
2475 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
2476 where
2477 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
2478 {
2479 func(&mut self.signature)?;
2480 func(&mut self.exception)?;
2481 Ok(())
2482 }
2483}
2484
2485#[expect(missing_docs, reason = "self-describing functions")]
2487pub trait TypeConvert {
2488 fn convert_global_type(&self, ty: &wasmparser::GlobalType) -> WasmResult<Global> {
2490 Ok(Global {
2491 wasm_ty: self.convert_valtype(ty.content_type)?,
2492 mutability: ty.mutable,
2493 })
2494 }
2495
2496 fn convert_table_type(&self, ty: &wasmparser::TableType) -> WasmResult<Table> {
2498 let idx_type = match ty.table64 {
2499 false => IndexType::I32,
2500 true => IndexType::I64,
2501 };
2502 let limits = Limits {
2503 min: ty.initial,
2504 max: ty.maximum,
2505 };
2506 Ok(Table {
2507 idx_type,
2508 limits,
2509 ref_type: self.convert_ref_type(ty.element_type)?,
2510 })
2511 }
2512
2513 fn convert_sub_type(&self, ty: &wasmparser::SubType) -> WasmResult<WasmSubType> {
2514 Ok(WasmSubType {
2515 is_final: ty.is_final,
2516 supertype: ty.supertype_idx.map(|i| self.lookup_type_index(i.unpack())),
2517 composite_type: self.convert_composite_type(&ty.composite_type)?,
2518 })
2519 }
2520
2521 fn convert_composite_type(
2522 &self,
2523 ty: &wasmparser::CompositeType,
2524 ) -> WasmResult<WasmCompositeType> {
2525 let inner = match &ty.inner {
2526 wasmparser::CompositeInnerType::Func(f) => {
2527 WasmCompositeInnerType::Func(self.convert_func_type(f)?)
2528 }
2529 wasmparser::CompositeInnerType::Array(a) => {
2530 WasmCompositeInnerType::Array(self.convert_array_type(a)?)
2531 }
2532 wasmparser::CompositeInnerType::Struct(s) => {
2533 WasmCompositeInnerType::Struct(self.convert_struct_type(s)?)
2534 }
2535 wasmparser::CompositeInnerType::Cont(c) => {
2536 WasmCompositeInnerType::Cont(self.convert_cont_type(c))
2537 }
2538 };
2539 Ok(WasmCompositeType {
2540 inner,
2541 shared: ty.shared,
2542 })
2543 }
2544
2545 fn convert_cont_type(&self, ty: &wasmparser::ContType) -> WasmContType {
2547 if let WasmHeapType::ConcreteFunc(sigidx) = self.lookup_heap_type(ty.0.unpack()) {
2548 WasmContType::new(sigidx)
2549 } else {
2550 panic!("Failed to extract signature index for continuation type.")
2551 }
2552 }
2553
2554 fn convert_struct_type(&self, ty: &wasmparser::StructType) -> WasmResult<WasmStructType> {
2555 Ok(WasmStructType {
2556 fields: ty
2557 .fields
2558 .iter()
2559 .map(|f| self.convert_field_type(f))
2560 .collect::<WasmResult<_>>()?,
2561 })
2562 }
2563
2564 fn convert_array_type(&self, ty: &wasmparser::ArrayType) -> WasmResult<WasmArrayType> {
2565 Ok(WasmArrayType(self.convert_field_type(&ty.0)?))
2566 }
2567
2568 fn convert_field_type(&self, ty: &wasmparser::FieldType) -> WasmResult<WasmFieldType> {
2569 Ok(WasmFieldType {
2570 element_type: self.convert_storage_type(&ty.element_type)?,
2571 mutable: ty.mutable,
2572 })
2573 }
2574
2575 fn convert_storage_type(&self, ty: &wasmparser::StorageType) -> WasmResult<WasmStorageType> {
2576 Ok(match ty {
2577 wasmparser::StorageType::I8 => WasmStorageType::I8,
2578 wasmparser::StorageType::I16 => WasmStorageType::I16,
2579 wasmparser::StorageType::Val(v) => WasmStorageType::Val(self.convert_valtype(*v)?),
2580 })
2581 }
2582
2583 fn convert_func_type(&self, ty: &wasmparser::FuncType) -> WasmResult<WasmFuncType> {
2585 let params = ty
2586 .params()
2587 .iter()
2588 .map(|t| self.convert_valtype(*t))
2589 .collect::<WasmResult<Vec<_>>>()?;
2590 let results = ty
2591 .results()
2592 .iter()
2593 .map(|t| self.convert_valtype(*t))
2594 .collect::<WasmResult<Vec<_>>>()?;
2595 Ok(WasmFuncType::new(params, results).panic_on_oom())
2596 }
2597
2598 fn convert_valtype(&self, ty: wasmparser::ValType) -> WasmResult<WasmValType> {
2600 Ok(match ty {
2601 wasmparser::ValType::I32 => WasmValType::I32,
2602 wasmparser::ValType::I64 => WasmValType::I64,
2603 wasmparser::ValType::F32 => WasmValType::F32,
2604 wasmparser::ValType::F64 => WasmValType::F64,
2605 wasmparser::ValType::V128 => WasmValType::V128,
2606 wasmparser::ValType::Ref(t) => WasmValType::Ref(self.convert_ref_type(t)?),
2607 })
2608 }
2609
2610 fn convert_ref_type(&self, ty: wasmparser::RefType) -> WasmResult<WasmRefType> {
2612 Ok(WasmRefType {
2613 nullable: ty.is_nullable(),
2614 heap_type: self.convert_heap_type(ty.heap_type())?,
2615 })
2616 }
2617
2618 fn convert_heap_type(&self, ty: wasmparser::HeapType) -> WasmResult<WasmHeapType> {
2620 Ok(match ty {
2621 wasmparser::HeapType::Concrete(i) => self.lookup_heap_type(i),
2622 wasmparser::HeapType::Abstract { ty, shared: false } => match ty {
2623 wasmparser::AbstractHeapType::Extern => WasmHeapType::Extern,
2624 wasmparser::AbstractHeapType::NoExtern => WasmHeapType::NoExtern,
2625 wasmparser::AbstractHeapType::Func => WasmHeapType::Func,
2626 wasmparser::AbstractHeapType::NoFunc => WasmHeapType::NoFunc,
2627 wasmparser::AbstractHeapType::Any => WasmHeapType::Any,
2628 wasmparser::AbstractHeapType::Eq => WasmHeapType::Eq,
2629 wasmparser::AbstractHeapType::I31 => WasmHeapType::I31,
2630 wasmparser::AbstractHeapType::Array => WasmHeapType::Array,
2631 wasmparser::AbstractHeapType::Struct => WasmHeapType::Struct,
2632 wasmparser::AbstractHeapType::None => WasmHeapType::None,
2633 wasmparser::AbstractHeapType::Cont => WasmHeapType::Cont,
2634 wasmparser::AbstractHeapType::NoCont => WasmHeapType::NoCont,
2635 wasmparser::AbstractHeapType::Exn => WasmHeapType::Exn,
2636 wasmparser::AbstractHeapType::NoExn => WasmHeapType::NoExn,
2637 },
2638 _ => return Err(wasm_unsupported!("unsupported heap type {ty:?}")),
2639 })
2640 }
2641
2642 fn lookup_heap_type(&self, index: wasmparser::UnpackedIndex) -> WasmHeapType;
2645
2646 fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex;
2649}
2650
2651#[cfg(test)]
2652mod tests {
2653 use super::*;
2654
2655 #[test]
2656 fn wasm_func_type_new() -> Result<()> {
2657 let i32 = WasmValType::I32;
2658 let anyref = WasmValType::Ref(WasmRefType {
2659 nullable: true,
2660 heap_type: WasmHeapType::Any,
2661 });
2662 let ty = WasmFuncType::new([i32, i32, anyref, anyref], [i32, anyref])?;
2663 assert_eq!(ty.params(), &[i32, i32, anyref, anyref]);
2664 assert_eq!(ty.non_i31_gc_ref_params_count(), 2);
2665 assert_eq!(ty.results(), &[i32, anyref]);
2666 assert_eq!(ty.non_i31_gc_ref_results_count(), 1);
2667 Ok(())
2668 }
2669}