1use crate::{Tunables, WasmResult, error::OutOfMemory, wasm_unsupported};
2use alloc::borrow::Cow;
3use alloc::boxed::Box;
4use core::{fmt, ops::Range};
5use cranelift_entity::entity_impl;
6use serde_derive::{Deserialize, Serialize};
7use smallvec::SmallVec;
8use wasmtime_core::alloc::{TryClone, TryCollect as _};
9
10pub trait TypeTrace {
13 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
17 where
18 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>;
19
20 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
26 where
27 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>;
28
29 fn trace_engine_indices<F, E>(&self, func: &mut F) -> Result<(), E>
31 where
32 F: FnMut(VMSharedTypeIndex) -> Result<(), E>,
33 {
34 self.trace(&mut |idx| match idx {
35 EngineOrModuleTypeIndex::Engine(idx) => func(idx),
36 EngineOrModuleTypeIndex::Module(_) | EngineOrModuleTypeIndex::RecGroup(_) => Ok(()),
37 })
38 }
39
40 fn canonicalize_for_runtime_usage<F>(&mut self, module_to_engine: &mut F)
51 where
52 F: FnMut(ModuleInternedTypeIndex) -> VMSharedTypeIndex,
53 {
54 self.trace_mut::<_, ()>(&mut |idx| match idx {
55 EngineOrModuleTypeIndex::Engine(_) => Ok(()),
56 EngineOrModuleTypeIndex::Module(module_index) => {
57 let engine_index = module_to_engine(*module_index);
58 *idx = EngineOrModuleTypeIndex::Engine(engine_index);
59 Ok(())
60 }
61 EngineOrModuleTypeIndex::RecGroup(_) => {
62 panic!("should not already be canonicalized for hash consing")
63 }
64 })
65 .unwrap()
66 }
67
68 fn is_canonicalized_for_runtime_usage(&self) -> bool {
70 self.trace(&mut |idx| match idx {
71 EngineOrModuleTypeIndex::Engine(_) => Ok(()),
72 EngineOrModuleTypeIndex::Module(_) | EngineOrModuleTypeIndex::RecGroup(_) => Err(()),
73 })
74 .is_ok()
75 }
76
77 fn canonicalize_for_hash_consing<F>(
88 &mut self,
89 rec_group_range: Range<ModuleInternedTypeIndex>,
90 module_to_engine: &mut F,
91 ) where
92 F: FnMut(ModuleInternedTypeIndex) -> VMSharedTypeIndex,
93 {
94 self.trace_mut::<_, ()>(&mut |idx| match *idx {
95 EngineOrModuleTypeIndex::Engine(_) => Ok(()),
96 EngineOrModuleTypeIndex::Module(module_index) => {
97 *idx = if rec_group_range.start <= module_index {
98 debug_assert!(module_index < rec_group_range.end);
101 let relative = module_index.as_u32() - rec_group_range.start.as_u32();
102 let relative = RecGroupRelativeTypeIndex::from_u32(relative);
103 EngineOrModuleTypeIndex::RecGroup(relative)
104 } else {
105 debug_assert!(module_index < rec_group_range.start);
108 EngineOrModuleTypeIndex::Engine(module_to_engine(module_index))
109 };
110 Ok(())
111 }
112 EngineOrModuleTypeIndex::RecGroup(_) => {
113 panic!("should not already be canonicalized for hash consing")
114 }
115 })
116 .unwrap()
117 }
118
119 fn is_canonicalized_for_hash_consing(&self) -> bool {
121 self.trace(&mut |idx| match idx {
122 EngineOrModuleTypeIndex::Engine(_) | EngineOrModuleTypeIndex::RecGroup(_) => Ok(()),
123 EngineOrModuleTypeIndex::Module(_) => Err(()),
124 })
125 .is_ok()
126 }
127}
128
129#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
131pub enum WasmValType {
132 I32,
134 I64,
136 F32,
138 F64,
140 V128,
142 Ref(WasmRefType),
144}
145
146impl TryClone for WasmValType {
147 fn try_clone(&self) -> Result<Self, OutOfMemory> {
148 Ok(*self)
149 }
150}
151
152impl fmt::Display for WasmValType {
153 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
154 match self {
155 WasmValType::I32 => write!(f, "i32"),
156 WasmValType::I64 => write!(f, "i64"),
157 WasmValType::F32 => write!(f, "f32"),
158 WasmValType::F64 => write!(f, "f64"),
159 WasmValType::V128 => write!(f, "v128"),
160 WasmValType::Ref(rt) => write!(f, "{rt}"),
161 }
162 }
163}
164
165impl TypeTrace for WasmValType {
166 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
167 where
168 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
169 {
170 match self {
171 WasmValType::Ref(r) => r.trace(func),
172 WasmValType::I32
173 | WasmValType::I64
174 | WasmValType::F32
175 | WasmValType::F64
176 | WasmValType::V128 => Ok(()),
177 }
178 }
179
180 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
181 where
182 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
183 {
184 match self {
185 WasmValType::Ref(r) => r.trace_mut(func),
186 WasmValType::I32
187 | WasmValType::I64
188 | WasmValType::F32
189 | WasmValType::F64
190 | WasmValType::V128 => Ok(()),
191 }
192 }
193}
194
195impl WasmValType {
196 #[inline]
198 pub fn is_vmgcref_type(&self) -> bool {
199 match self {
200 WasmValType::Ref(r) => r.is_vmgcref_type(),
201 _ => false,
202 }
203 }
204
205 #[inline]
211 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
212 match self {
213 WasmValType::Ref(r) => r.is_vmgcref_type_and_not_i31(),
214 _ => false,
215 }
216 }
217
218 fn trampoline_type(&self) -> Self {
219 match self {
220 WasmValType::Ref(r) => WasmValType::Ref(WasmRefType {
221 nullable: true,
222 heap_type: r.heap_type.top().into(),
223 }),
224 WasmValType::I32
225 | WasmValType::I64
226 | WasmValType::F32
227 | WasmValType::F64
228 | WasmValType::V128 => *self,
229 }
230 }
231
232 pub fn int_from_bits(bits: u8) -> Self {
236 match bits {
237 32 => Self::I32,
238 64 => Self::I64,
239 size => panic!("invalid int bits for WasmValType: {size}"),
240 }
241 }
242
243 pub fn unwrap_ref_type(&self) -> WasmRefType {
247 match self {
248 WasmValType::Ref(ref_type) => *ref_type,
249 _ => panic!("Called WasmValType::unwrap_ref_type on non-reference type"),
250 }
251 }
252}
253
254#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
256pub struct WasmRefType {
257 pub nullable: bool,
259 pub heap_type: WasmHeapType,
261}
262
263impl TypeTrace for WasmRefType {
264 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
265 where
266 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
267 {
268 self.heap_type.trace(func)
269 }
270
271 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
272 where
273 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
274 {
275 self.heap_type.trace_mut(func)
276 }
277}
278
279impl WasmRefType {
280 pub const EXTERNREF: WasmRefType = WasmRefType {
282 nullable: true,
283 heap_type: WasmHeapType::Extern,
284 };
285 pub const FUNCREF: WasmRefType = WasmRefType {
287 nullable: true,
288 heap_type: WasmHeapType::Func,
289 };
290
291 #[inline]
293 pub fn is_vmgcref_type(&self) -> bool {
294 self.heap_type.is_vmgcref_type()
295 }
296
297 #[inline]
303 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
304 self.heap_type.is_vmgcref_type_and_not_i31()
305 }
306}
307
308impl fmt::Display for WasmRefType {
309 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
310 match *self {
311 Self::FUNCREF => write!(f, "funcref"),
312 Self::EXTERNREF => write!(f, "externref"),
313 _ => {
314 if self.nullable {
315 write!(f, "(ref null {})", self.heap_type)
316 } else {
317 write!(f, "(ref {})", self.heap_type)
318 }
319 }
320 }
321 }
322}
323
324#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
329pub enum EngineOrModuleTypeIndex {
330 Engine(VMSharedTypeIndex),
333
334 Module(ModuleInternedTypeIndex),
337
338 RecGroup(RecGroupRelativeTypeIndex),
342}
343
344impl From<ModuleInternedTypeIndex> for EngineOrModuleTypeIndex {
345 #[inline]
346 fn from(i: ModuleInternedTypeIndex) -> Self {
347 Self::Module(i)
348 }
349}
350
351impl From<VMSharedTypeIndex> for EngineOrModuleTypeIndex {
352 #[inline]
353 fn from(i: VMSharedTypeIndex) -> Self {
354 Self::Engine(i)
355 }
356}
357
358impl From<RecGroupRelativeTypeIndex> for EngineOrModuleTypeIndex {
359 #[inline]
360 fn from(i: RecGroupRelativeTypeIndex) -> Self {
361 Self::RecGroup(i)
362 }
363}
364
365impl fmt::Display for EngineOrModuleTypeIndex {
366 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
367 match self {
368 Self::Engine(i) => write!(f, "(engine {})", i.bits()),
369 Self::Module(i) => write!(f, "(module {})", i.as_u32()),
370 Self::RecGroup(i) => write!(f, "(recgroup {})", i.as_u32()),
371 }
372 }
373}
374
375impl EngineOrModuleTypeIndex {
376 pub fn is_engine_type_index(self) -> bool {
378 matches!(self, Self::Engine(_))
379 }
380
381 #[inline]
383 pub fn as_engine_type_index(self) -> Option<VMSharedTypeIndex> {
384 match self {
385 Self::Engine(e) => Some(e),
386 Self::RecGroup(_) | Self::Module(_) => None,
387 }
388 }
389
390 #[track_caller]
392 #[inline]
393 pub fn unwrap_engine_type_index(self) -> VMSharedTypeIndex {
394 match self.as_engine_type_index() {
395 Some(x) => x,
396 None => panic!("`unwrap_engine_type_index` on {self:?}"),
397 }
398 }
399
400 pub fn is_module_type_index(self) -> bool {
402 matches!(self, Self::Module(_))
403 }
404
405 pub fn as_module_type_index(self) -> Option<ModuleInternedTypeIndex> {
407 match self {
408 Self::Module(e) => Some(e),
409 Self::RecGroup(_) | Self::Engine(_) => None,
410 }
411 }
412
413 #[track_caller]
415 pub fn unwrap_module_type_index(self) -> ModuleInternedTypeIndex {
416 match self.as_module_type_index() {
417 Some(x) => x,
418 None => panic!("`unwrap_module_type_index` on {self:?}"),
419 }
420 }
421
422 pub fn is_rec_group_type_index(self) -> bool {
424 matches!(self, Self::RecGroup(_))
425 }
426
427 pub fn as_rec_group_type_index(self) -> Option<RecGroupRelativeTypeIndex> {
429 match self {
430 Self::RecGroup(r) => Some(r),
431 Self::Module(_) | Self::Engine(_) => None,
432 }
433 }
434
435 #[track_caller]
437 pub fn unwrap_rec_group_type_index(self) -> RecGroupRelativeTypeIndex {
438 match self.as_rec_group_type_index() {
439 Some(x) => x,
440 None => panic!("`unwrap_rec_group_type_index` on {self:?}"),
441 }
442 }
443}
444
445#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
447#[expect(missing_docs, reason = "self-describing variants")]
448pub enum WasmHeapType {
449 Extern,
451 NoExtern,
452
453 Func,
455 ConcreteFunc(EngineOrModuleTypeIndex),
456 NoFunc,
457
458 Exn,
460 ConcreteExn(EngineOrModuleTypeIndex),
461 NoExn,
462
463 Cont,
465 ConcreteCont(EngineOrModuleTypeIndex),
466 NoCont,
467
468 Any,
470 Eq,
471 I31,
472 Array,
473 ConcreteArray(EngineOrModuleTypeIndex),
474 Struct,
475 ConcreteStruct(EngineOrModuleTypeIndex),
476 None,
477}
478
479impl From<WasmHeapTopType> for WasmHeapType {
480 #[inline]
481 fn from(value: WasmHeapTopType) -> Self {
482 match value {
483 WasmHeapTopType::Extern => Self::Extern,
484 WasmHeapTopType::Any => Self::Any,
485 WasmHeapTopType::Func => Self::Func,
486 WasmHeapTopType::Cont => Self::Cont,
487 WasmHeapTopType::Exn => Self::Exn,
488 }
489 }
490}
491
492impl From<WasmHeapBottomType> for WasmHeapType {
493 #[inline]
494 fn from(value: WasmHeapBottomType) -> Self {
495 match value {
496 WasmHeapBottomType::NoExtern => Self::NoExtern,
497 WasmHeapBottomType::None => Self::None,
498 WasmHeapBottomType::NoFunc => Self::NoFunc,
499 WasmHeapBottomType::NoCont => Self::NoCont,
500 WasmHeapBottomType::NoExn => Self::NoExn,
501 }
502 }
503}
504
505impl fmt::Display for WasmHeapType {
506 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
507 match self {
508 Self::Extern => write!(f, "extern"),
509 Self::NoExtern => write!(f, "noextern"),
510 Self::Func => write!(f, "func"),
511 Self::ConcreteFunc(i) => write!(f, "func {i}"),
512 Self::NoFunc => write!(f, "nofunc"),
513 Self::Cont => write!(f, "cont"),
514 Self::ConcreteCont(i) => write!(f, "cont {i}"),
515 Self::NoCont => write!(f, "nocont"),
516 Self::Any => write!(f, "any"),
517 Self::Eq => write!(f, "eq"),
518 Self::I31 => write!(f, "i31"),
519 Self::Array => write!(f, "array"),
520 Self::ConcreteArray(i) => write!(f, "array {i}"),
521 Self::Struct => write!(f, "struct"),
522 Self::ConcreteStruct(i) => write!(f, "struct {i}"),
523 Self::Exn => write!(f, "exn"),
524 Self::ConcreteExn(i) => write!(f, "exn {i}"),
525 Self::NoExn => write!(f, "noexn"),
526 Self::None => write!(f, "none"),
527 }
528 }
529}
530
531impl TypeTrace for WasmHeapType {
532 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
533 where
534 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
535 {
536 match *self {
537 Self::ConcreteArray(i) => func(i),
538 Self::ConcreteFunc(i) => func(i),
539 Self::ConcreteStruct(i) => func(i),
540 Self::ConcreteCont(i) => func(i),
541 _ => Ok(()),
542 }
543 }
544
545 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
546 where
547 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
548 {
549 match self {
550 Self::ConcreteArray(i) => func(i),
551 Self::ConcreteFunc(i) => func(i),
552 Self::ConcreteStruct(i) => func(i),
553 Self::ConcreteCont(i) => func(i),
554 _ => Ok(()),
555 }
556 }
557}
558
559impl WasmHeapType {
560 #[inline]
562 pub fn is_vmgcref_type(&self) -> bool {
563 match self.top() {
564 WasmHeapTopType::Any | WasmHeapTopType::Extern | WasmHeapTopType::Exn => true,
568
569 WasmHeapTopType::Func => false,
571 WasmHeapTopType::Cont => false,
572 }
573 }
574
575 #[inline]
581 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
582 self.is_vmgcref_type() && *self != Self::I31
583 }
584
585 #[inline]
587 pub fn is_top(&self) -> bool {
588 *self == Self::from(self.top())
589 }
590
591 #[inline]
593 pub fn top(&self) -> WasmHeapTopType {
594 match self {
595 WasmHeapType::Extern | WasmHeapType::NoExtern => WasmHeapTopType::Extern,
596
597 WasmHeapType::Func | WasmHeapType::ConcreteFunc(_) | WasmHeapType::NoFunc => {
598 WasmHeapTopType::Func
599 }
600
601 WasmHeapType::Cont | WasmHeapType::ConcreteCont(_) | WasmHeapType::NoCont => {
602 WasmHeapTopType::Cont
603 }
604
605 WasmHeapType::Exn | WasmHeapType::ConcreteExn(_) | WasmHeapType::NoExn => {
606 WasmHeapTopType::Exn
607 }
608
609 WasmHeapType::Any
610 | WasmHeapType::Eq
611 | WasmHeapType::I31
612 | WasmHeapType::Array
613 | WasmHeapType::ConcreteArray(_)
614 | WasmHeapType::Struct
615 | WasmHeapType::ConcreteStruct(_)
616 | WasmHeapType::None => WasmHeapTopType::Any,
617 }
618 }
619
620 #[inline]
622 pub fn is_bottom(&self) -> bool {
623 *self == Self::from(self.bottom())
624 }
625
626 #[inline]
628 pub fn bottom(&self) -> WasmHeapBottomType {
629 match self {
630 WasmHeapType::Extern | WasmHeapType::NoExtern => WasmHeapBottomType::NoExtern,
631
632 WasmHeapType::Func | WasmHeapType::ConcreteFunc(_) | WasmHeapType::NoFunc => {
633 WasmHeapBottomType::NoFunc
634 }
635
636 WasmHeapType::Cont | WasmHeapType::ConcreteCont(_) | WasmHeapType::NoCont => {
637 WasmHeapBottomType::NoCont
638 }
639
640 WasmHeapType::Exn | WasmHeapType::ConcreteExn(_) | WasmHeapType::NoExn => {
641 WasmHeapBottomType::NoExn
642 }
643
644 WasmHeapType::Any
645 | WasmHeapType::Eq
646 | WasmHeapType::I31
647 | WasmHeapType::Array
648 | WasmHeapType::ConcreteArray(_)
649 | WasmHeapType::Struct
650 | WasmHeapType::ConcreteStruct(_)
651 | WasmHeapType::None => WasmHeapBottomType::None,
652 }
653 }
654}
655
656#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
658pub enum WasmHeapTopType {
659 Extern,
661 Any,
663 Func,
665 Exn,
667 Cont,
669}
670
671#[derive(Debug, Clone, Copy, Eq, PartialEq)]
673pub enum WasmHeapBottomType {
674 NoExtern,
676 None,
678 NoFunc,
680 NoExn,
682 NoCont,
684}
685
686#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
688pub struct WasmFuncType {
689 params: Box<[WasmValType]>,
690 non_i31_gc_ref_params_count: usize,
691 returns: Box<[WasmValType]>,
692 non_i31_gc_ref_returns_count: usize,
693}
694
695impl TryClone for WasmFuncType {
696 fn try_clone(&self) -> Result<Self, OutOfMemory> {
697 Ok(WasmFuncType {
698 params: TryClone::try_clone(&self.params)?,
699 non_i31_gc_ref_params_count: self.non_i31_gc_ref_params_count,
700 returns: TryClone::try_clone(&self.returns)?,
701 non_i31_gc_ref_returns_count: self.non_i31_gc_ref_returns_count,
702 })
703 }
704}
705
706impl fmt::Display for WasmFuncType {
707 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
708 write!(f, "(func")?;
709 if !self.params.is_empty() {
710 write!(f, " (param")?;
711 for p in self.params.iter() {
712 write!(f, " {p}")?;
713 }
714 write!(f, ")")?;
715 }
716 if !self.returns.is_empty() {
717 write!(f, " (result")?;
718 for r in self.returns.iter() {
719 write!(f, " {r}")?;
720 }
721 write!(f, ")")?;
722 }
723 write!(f, ")")
724 }
725}
726
727impl TypeTrace for WasmFuncType {
728 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
729 where
730 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
731 {
732 for p in self.params.iter() {
733 p.trace(func)?;
734 }
735 for r in self.returns.iter() {
736 r.trace(func)?;
737 }
738 Ok(())
739 }
740
741 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
742 where
743 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
744 {
745 for p in self.params.iter_mut() {
746 p.trace_mut(func)?;
747 }
748 for r in self.returns.iter_mut() {
749 r.trace_mut(func)?;
750 }
751 Ok(())
752 }
753}
754
755impl WasmFuncType {
756 #[inline]
758 pub fn new(params: Box<[WasmValType]>, returns: Box<[WasmValType]>) -> Self {
759 let non_i31_gc_ref_params_count = params
760 .iter()
761 .filter(|p| p.is_vmgcref_type_and_not_i31())
762 .count();
763 let non_i31_gc_ref_returns_count = returns
764 .iter()
765 .filter(|r| r.is_vmgcref_type_and_not_i31())
766 .count();
767 WasmFuncType {
768 params,
769 non_i31_gc_ref_params_count,
770 returns,
771 non_i31_gc_ref_returns_count,
772 }
773 }
774
775 #[inline]
777 pub fn params(&self) -> &[WasmValType] {
778 &self.params
779 }
780
781 #[inline]
783 pub fn non_i31_gc_ref_params_count(&self) -> usize {
784 self.non_i31_gc_ref_params_count
785 }
786
787 #[inline]
789 pub fn returns(&self) -> &[WasmValType] {
790 &self.returns
791 }
792
793 #[inline]
795 pub fn non_i31_gc_ref_returns_count(&self) -> usize {
796 self.non_i31_gc_ref_returns_count
797 }
798
799 pub fn is_trampoline_type(&self) -> bool {
801 self.params().iter().all(|p| *p == p.trampoline_type())
802 && self.returns().iter().all(|r| *r == r.trampoline_type())
803 }
804
805 pub fn trampoline_type(&self) -> Result<Cow<'_, Self>, OutOfMemory> {
831 if self.is_trampoline_type() {
832 return Ok(Cow::Borrowed(self));
833 }
834
835 Ok(Cow::Owned(Self::new(
836 self.params()
837 .iter()
838 .map(|p| p.trampoline_type())
839 .try_collect()?,
840 self.returns()
841 .iter()
842 .map(|r| r.trampoline_type())
843 .try_collect()?,
844 )))
845 }
846}
847
848#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
850pub struct WasmContType(EngineOrModuleTypeIndex);
851
852impl fmt::Display for WasmContType {
853 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
854 write!(f, "(cont {})", self.0)
855 }
856}
857
858impl WasmContType {
859 pub fn new(idx: EngineOrModuleTypeIndex) -> Self {
861 WasmContType(idx)
862 }
863
864 pub fn unwrap_module_type_index(self) -> ModuleInternedTypeIndex {
866 match self.0 {
867 EngineOrModuleTypeIndex::Engine(_) => panic!("not module interned"),
868 EngineOrModuleTypeIndex::Module(idx) => idx,
869 EngineOrModuleTypeIndex::RecGroup(_) => todo!(),
870 }
871 }
872}
873
874impl TypeTrace for WasmContType {
875 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
876 where
877 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
878 {
879 func(self.0)
880 }
881
882 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
883 where
884 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
885 {
886 func(&mut self.0)
887 }
888}
889
890#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
915pub struct WasmExnType {
916 pub func_ty: EngineOrModuleTypeIndex,
920 pub fields: Box<[WasmFieldType]>,
927}
928
929impl TryClone for WasmExnType {
930 fn try_clone(&self) -> Result<Self, OutOfMemory> {
931 Ok(Self {
932 func_ty: self.func_ty,
933 fields: self.fields.try_clone()?,
934 })
935 }
936}
937
938impl fmt::Display for WasmExnType {
939 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
940 write!(f, "(exn ({})", self.func_ty)?;
941 for ty in self.fields.iter() {
942 write!(f, " {ty}")?;
943 }
944 write!(f, ")")
945 }
946}
947
948impl TypeTrace for WasmExnType {
949 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
950 where
951 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
952 {
953 func(self.func_ty)?;
954 for f in self.fields.iter() {
955 f.trace(func)?;
956 }
957 Ok(())
958 }
959
960 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
961 where
962 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
963 {
964 func(&mut self.func_ty)?;
965 for f in self.fields.iter_mut() {
966 f.trace_mut(func)?;
967 }
968 Ok(())
969 }
970}
971
972#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
974pub enum WasmStorageType {
975 I8,
977 I16,
979 Val(WasmValType),
981}
982
983impl fmt::Display for WasmStorageType {
984 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
985 match self {
986 WasmStorageType::I8 => write!(f, "i8"),
987 WasmStorageType::I16 => write!(f, "i16"),
988 WasmStorageType::Val(v) => fmt::Display::fmt(v, f),
989 }
990 }
991}
992
993impl TypeTrace for WasmStorageType {
994 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
995 where
996 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
997 {
998 match self {
999 WasmStorageType::I8 | WasmStorageType::I16 => Ok(()),
1000 WasmStorageType::Val(v) => v.trace(func),
1001 }
1002 }
1003
1004 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1005 where
1006 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1007 {
1008 match self {
1009 WasmStorageType::I8 | WasmStorageType::I16 => Ok(()),
1010 WasmStorageType::Val(v) => v.trace_mut(func),
1011 }
1012 }
1013}
1014
1015impl WasmStorageType {
1016 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
1022 match self {
1023 WasmStorageType::I8 | WasmStorageType::I16 => false,
1024 WasmStorageType::Val(v) => v.is_vmgcref_type_and_not_i31(),
1025 }
1026 }
1027}
1028
1029#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
1031pub struct WasmFieldType {
1032 pub element_type: WasmStorageType,
1034
1035 pub mutable: bool,
1037}
1038
1039impl TryClone for WasmFieldType {
1040 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1041 Ok(*self)
1042 }
1043}
1044
1045impl fmt::Display for WasmFieldType {
1046 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1047 if self.mutable {
1048 write!(f, "(mut {})", self.element_type)
1049 } else {
1050 fmt::Display::fmt(&self.element_type, f)
1051 }
1052 }
1053}
1054
1055impl TypeTrace for WasmFieldType {
1056 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1057 where
1058 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1059 {
1060 self.element_type.trace(func)
1061 }
1062
1063 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1064 where
1065 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1066 {
1067 self.element_type.trace_mut(func)
1068 }
1069}
1070
1071#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
1073pub struct WasmArrayType(pub WasmFieldType);
1074
1075impl fmt::Display for WasmArrayType {
1076 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1077 write!(f, "(array {})", self.0)
1078 }
1079}
1080
1081impl TypeTrace for WasmArrayType {
1082 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1083 where
1084 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1085 {
1086 self.0.trace(func)
1087 }
1088
1089 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1090 where
1091 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1092 {
1093 self.0.trace_mut(func)
1094 }
1095}
1096
1097#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1099pub struct WasmStructType {
1100 pub fields: Box<[WasmFieldType]>,
1102}
1103
1104impl TryClone for WasmStructType {
1105 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1106 Ok(Self {
1107 fields: self.fields.try_clone()?,
1108 })
1109 }
1110}
1111
1112impl fmt::Display for WasmStructType {
1113 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1114 write!(f, "(struct")?;
1115 for ty in self.fields.iter() {
1116 write!(f, " {ty}")?;
1117 }
1118 write!(f, ")")
1119 }
1120}
1121
1122impl TypeTrace for WasmStructType {
1123 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1124 where
1125 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1126 {
1127 for f in self.fields.iter() {
1128 f.trace(func)?;
1129 }
1130 Ok(())
1131 }
1132
1133 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1134 where
1135 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1136 {
1137 for f in self.fields.iter_mut() {
1138 f.trace_mut(func)?;
1139 }
1140 Ok(())
1141 }
1142}
1143
1144#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1145#[expect(missing_docs, reason = "self-describing type")]
1146pub struct WasmCompositeType {
1147 pub inner: WasmCompositeInnerType,
1149 pub shared: bool,
1152}
1153
1154impl TryClone for WasmCompositeType {
1155 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1156 Ok(Self {
1157 inner: self.inner.try_clone()?,
1158 shared: self.shared,
1159 })
1160 }
1161}
1162
1163impl fmt::Display for WasmCompositeType {
1164 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1165 if self.shared {
1166 write!(f, "(shared ")?;
1167 }
1168 fmt::Display::fmt(&self.inner, f)?;
1169 if self.shared {
1170 write!(f, ")")?;
1171 }
1172 Ok(())
1173 }
1174}
1175
1176#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1178#[expect(missing_docs, reason = "self-describing variants")]
1179pub enum WasmCompositeInnerType {
1180 Array(WasmArrayType),
1181 Func(WasmFuncType),
1182 Struct(WasmStructType),
1183 Cont(WasmContType),
1184 Exn(WasmExnType),
1185}
1186
1187impl TryClone for WasmCompositeInnerType {
1188 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1189 Ok(match self {
1190 Self::Array(ty) => Self::Array(*ty),
1191 Self::Func(ty) => Self::Func(ty.try_clone()?),
1192 Self::Struct(ty) => Self::Struct(ty.try_clone()?),
1193 Self::Cont(ty) => Self::Cont(*ty),
1194 Self::Exn(ty) => Self::Exn(ty.try_clone()?),
1195 })
1196 }
1197}
1198
1199impl fmt::Display for WasmCompositeInnerType {
1200 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1201 match self {
1202 Self::Array(ty) => fmt::Display::fmt(ty, f),
1203 Self::Func(ty) => fmt::Display::fmt(ty, f),
1204 Self::Struct(ty) => fmt::Display::fmt(ty, f),
1205 Self::Cont(ty) => fmt::Display::fmt(ty, f),
1206 Self::Exn(ty) => fmt::Display::fmt(ty, f),
1207 }
1208 }
1209}
1210
1211#[expect(missing_docs, reason = "self-describing functions")]
1212impl WasmCompositeInnerType {
1213 #[inline]
1214 pub fn is_array(&self) -> bool {
1215 matches!(self, Self::Array(_))
1216 }
1217
1218 #[inline]
1219 pub fn as_array(&self) -> Option<&WasmArrayType> {
1220 match self {
1221 Self::Array(f) => Some(f),
1222 _ => None,
1223 }
1224 }
1225
1226 #[inline]
1227 pub fn unwrap_array(&self) -> &WasmArrayType {
1228 self.as_array().unwrap()
1229 }
1230
1231 #[inline]
1232 pub fn is_func(&self) -> bool {
1233 matches!(self, Self::Func(_))
1234 }
1235
1236 #[inline]
1237 pub fn as_func(&self) -> Option<&WasmFuncType> {
1238 match self {
1239 Self::Func(f) => Some(f),
1240 _ => None,
1241 }
1242 }
1243
1244 #[inline]
1245 pub fn unwrap_func(&self) -> &WasmFuncType {
1246 self.as_func().unwrap()
1247 }
1248
1249 #[inline]
1250 pub fn is_struct(&self) -> bool {
1251 matches!(self, Self::Struct(_))
1252 }
1253
1254 #[inline]
1255 pub fn as_struct(&self) -> Option<&WasmStructType> {
1256 match self {
1257 Self::Struct(f) => Some(f),
1258 _ => None,
1259 }
1260 }
1261
1262 #[inline]
1263 pub fn unwrap_struct(&self) -> &WasmStructType {
1264 self.as_struct().unwrap()
1265 }
1266
1267 #[inline]
1268 pub fn is_cont(&self) -> bool {
1269 matches!(self, Self::Cont(_))
1270 }
1271
1272 #[inline]
1273 pub fn as_cont(&self) -> Option<&WasmContType> {
1274 match self {
1275 Self::Cont(f) => Some(f),
1276 _ => None,
1277 }
1278 }
1279
1280 #[inline]
1281 pub fn unwrap_cont(&self) -> &WasmContType {
1282 self.as_cont().unwrap()
1283 }
1284
1285 #[inline]
1286 pub fn is_exn(&self) -> bool {
1287 matches!(self, Self::Exn(_))
1288 }
1289
1290 #[inline]
1291 pub fn as_exn(&self) -> Option<&WasmExnType> {
1292 match self {
1293 Self::Exn(f) => Some(f),
1294 _ => None,
1295 }
1296 }
1297
1298 #[inline]
1299 pub fn unwrap_exn(&self) -> &WasmExnType {
1300 self.as_exn().unwrap()
1301 }
1302}
1303
1304impl TypeTrace for WasmCompositeType {
1305 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1306 where
1307 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1308 {
1309 match &self.inner {
1310 WasmCompositeInnerType::Array(a) => a.trace(func),
1311 WasmCompositeInnerType::Func(f) => f.trace(func),
1312 WasmCompositeInnerType::Struct(a) => a.trace(func),
1313 WasmCompositeInnerType::Cont(c) => c.trace(func),
1314 WasmCompositeInnerType::Exn(e) => e.trace(func),
1315 }
1316 }
1317
1318 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1319 where
1320 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1321 {
1322 match &mut self.inner {
1323 WasmCompositeInnerType::Array(a) => a.trace_mut(func),
1324 WasmCompositeInnerType::Func(f) => f.trace_mut(func),
1325 WasmCompositeInnerType::Struct(a) => a.trace_mut(func),
1326 WasmCompositeInnerType::Cont(c) => c.trace_mut(func),
1327 WasmCompositeInnerType::Exn(e) => e.trace_mut(func),
1328 }
1329 }
1330}
1331
1332#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1334pub struct WasmSubType {
1335 pub is_final: bool,
1338
1339 pub supertype: Option<EngineOrModuleTypeIndex>,
1341
1342 pub composite_type: WasmCompositeType,
1344}
1345
1346impl TryClone for WasmSubType {
1347 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1348 Ok(Self {
1349 is_final: self.is_final,
1350 supertype: self.supertype,
1351 composite_type: self.composite_type.try_clone()?,
1352 })
1353 }
1354}
1355
1356impl fmt::Display for WasmSubType {
1357 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1358 if self.is_final && self.supertype.is_none() {
1359 fmt::Display::fmt(&self.composite_type, f)
1360 } else {
1361 write!(f, "(sub")?;
1362 if self.is_final {
1363 write!(f, " final")?;
1364 }
1365 if let Some(sup) = self.supertype {
1366 write!(f, " {sup}")?;
1367 }
1368 write!(f, " {})", self.composite_type)
1369 }
1370 }
1371}
1372
1373#[expect(missing_docs, reason = "self-describing functions")]
1377impl WasmSubType {
1378 #[inline]
1379 pub fn is_func(&self) -> bool {
1380 self.composite_type.inner.is_func() && !self.composite_type.shared
1381 }
1382
1383 #[inline]
1384 pub fn as_func(&self) -> Option<&WasmFuncType> {
1385 if self.composite_type.shared {
1386 None
1387 } else {
1388 self.composite_type.inner.as_func()
1389 }
1390 }
1391
1392 #[inline]
1393 pub fn unwrap_func(&self) -> &WasmFuncType {
1394 assert!(!self.composite_type.shared);
1395 self.composite_type.inner.unwrap_func()
1396 }
1397
1398 #[inline]
1399 pub fn is_array(&self) -> bool {
1400 self.composite_type.inner.is_array() && !self.composite_type.shared
1401 }
1402
1403 #[inline]
1404 pub fn as_array(&self) -> Option<&WasmArrayType> {
1405 if self.composite_type.shared {
1406 None
1407 } else {
1408 self.composite_type.inner.as_array()
1409 }
1410 }
1411
1412 #[inline]
1413 pub fn unwrap_array(&self) -> &WasmArrayType {
1414 assert!(!self.composite_type.shared);
1415 self.composite_type.inner.unwrap_array()
1416 }
1417
1418 #[inline]
1419 pub fn is_struct(&self) -> bool {
1420 self.composite_type.inner.is_struct() && !self.composite_type.shared
1421 }
1422
1423 #[inline]
1424 pub fn as_struct(&self) -> Option<&WasmStructType> {
1425 if self.composite_type.shared {
1426 None
1427 } else {
1428 self.composite_type.inner.as_struct()
1429 }
1430 }
1431
1432 #[inline]
1433 pub fn unwrap_struct(&self) -> &WasmStructType {
1434 assert!(!self.composite_type.shared);
1435 self.composite_type.inner.unwrap_struct()
1436 }
1437
1438 #[inline]
1439 pub fn is_cont(&self) -> bool {
1440 self.composite_type.inner.is_cont() && !self.composite_type.shared
1441 }
1442
1443 #[inline]
1444 pub fn as_cont(&self) -> Option<&WasmContType> {
1445 if self.composite_type.shared {
1446 None
1447 } else {
1448 self.composite_type.inner.as_cont()
1449 }
1450 }
1451
1452 #[inline]
1453 pub fn unwrap_cont(&self) -> &WasmContType {
1454 assert!(!self.composite_type.shared);
1455 self.composite_type.inner.unwrap_cont()
1456 }
1457
1458 #[inline]
1459 pub fn is_exn(&self) -> bool {
1460 self.composite_type.inner.is_exn() && !self.composite_type.shared
1461 }
1462
1463 #[inline]
1464 pub fn as_exn(&self) -> Option<&WasmExnType> {
1465 if self.composite_type.shared {
1466 None
1467 } else {
1468 self.composite_type.inner.as_exn()
1469 }
1470 }
1471
1472 #[inline]
1473 pub fn unwrap_exn(&self) -> &WasmExnType {
1474 assert!(!self.composite_type.shared);
1475 self.composite_type.inner.unwrap_exn()
1476 }
1477}
1478
1479impl TypeTrace for WasmSubType {
1480 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1481 where
1482 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1483 {
1484 if let Some(sup) = self.supertype {
1485 func(sup)?;
1486 }
1487 self.composite_type.trace(func)
1488 }
1489
1490 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1491 where
1492 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1493 {
1494 if let Some(sup) = self.supertype.as_mut() {
1495 func(sup)?;
1496 }
1497 self.composite_type.trace_mut(func)
1498 }
1499}
1500
1501#[derive(Debug, Default, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1512pub struct WasmRecGroup {
1513 pub types: Box<[WasmSubType]>,
1515}
1516
1517impl TypeTrace for WasmRecGroup {
1518 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1519 where
1520 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1521 {
1522 for ty in self.types.iter() {
1523 ty.trace(func)?;
1524 }
1525 Ok(())
1526 }
1527
1528 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1529 where
1530 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1531 {
1532 for ty in self.types.iter_mut() {
1533 ty.trace_mut(func)?;
1534 }
1535 Ok(())
1536 }
1537}
1538
1539#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1541pub struct FuncIndex(u32);
1542entity_impl!(FuncIndex);
1543
1544#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1546pub struct DefinedFuncIndex(u32);
1547entity_impl!(DefinedFuncIndex);
1548
1549#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1551pub struct DefinedTableIndex(u32);
1552entity_impl!(DefinedTableIndex);
1553
1554#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1556pub struct DefinedMemoryIndex(u32);
1557entity_impl!(DefinedMemoryIndex);
1558
1559#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1561pub struct OwnedMemoryIndex(u32);
1562entity_impl!(OwnedMemoryIndex);
1563
1564#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1566pub struct DefinedGlobalIndex(u32);
1567entity_impl!(DefinedGlobalIndex);
1568
1569#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1571pub struct TableIndex(u32);
1572entity_impl!(TableIndex);
1573
1574#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1576pub struct GlobalIndex(u32);
1577entity_impl!(GlobalIndex);
1578
1579#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1581pub struct MemoryIndex(u32);
1582entity_impl!(MemoryIndex);
1583
1584#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1587pub struct ModuleInternedRecGroupIndex(u32);
1588entity_impl!(ModuleInternedRecGroupIndex);
1589
1590#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1593pub struct EngineInternedRecGroupIndex(u32);
1594entity_impl!(EngineInternedRecGroupIndex);
1595
1596#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1598pub struct TypeIndex(u32);
1599entity_impl!(TypeIndex);
1600
1601#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1607pub struct RecGroupRelativeTypeIndex(u32);
1608entity_impl!(RecGroupRelativeTypeIndex);
1609
1610#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1618pub struct ModuleInternedTypeIndex(u32);
1619entity_impl!(ModuleInternedTypeIndex);
1620
1621#[repr(transparent)] #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1630pub struct VMSharedTypeIndex(u32);
1631entity_impl!(VMSharedTypeIndex);
1632
1633impl VMSharedTypeIndex {
1634 #[inline]
1636 pub fn new(value: u32) -> Self {
1637 assert_ne!(
1638 value,
1639 u32::MAX,
1640 "u32::MAX is reserved for the default value"
1641 );
1642 Self(value)
1643 }
1644
1645 #[inline]
1647 pub fn bits(&self) -> u32 {
1648 self.0
1649 }
1650}
1651
1652impl Default for VMSharedTypeIndex {
1653 #[inline]
1654 fn default() -> Self {
1655 Self(u32::MAX)
1656 }
1657}
1658
1659#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1661pub struct DataIndex(u32);
1662entity_impl!(DataIndex);
1663
1664#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1666pub struct ElemIndex(u32);
1667entity_impl!(ElemIndex);
1668
1669#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1671pub struct DefinedTagIndex(u32);
1672entity_impl!(DefinedTagIndex);
1673
1674#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1676pub struct TagIndex(u32);
1677entity_impl!(TagIndex);
1678
1679#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1684pub struct StaticModuleIndex(u32);
1685entity_impl!(StaticModuleIndex);
1686
1687#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1689pub enum EntityIndex {
1690 Function(FuncIndex),
1692 Table(TableIndex),
1694 Memory(MemoryIndex),
1696 Global(GlobalIndex),
1698 Tag(TagIndex),
1700}
1701
1702impl From<FuncIndex> for EntityIndex {
1703 fn from(idx: FuncIndex) -> EntityIndex {
1704 EntityIndex::Function(idx)
1705 }
1706}
1707
1708impl From<TableIndex> for EntityIndex {
1709 fn from(idx: TableIndex) -> EntityIndex {
1710 EntityIndex::Table(idx)
1711 }
1712}
1713
1714impl From<MemoryIndex> for EntityIndex {
1715 fn from(idx: MemoryIndex) -> EntityIndex {
1716 EntityIndex::Memory(idx)
1717 }
1718}
1719
1720impl From<GlobalIndex> for EntityIndex {
1721 fn from(idx: GlobalIndex) -> EntityIndex {
1722 EntityIndex::Global(idx)
1723 }
1724}
1725
1726impl From<TagIndex> for EntityIndex {
1727 fn from(idx: TagIndex) -> EntityIndex {
1728 EntityIndex::Tag(idx)
1729 }
1730}
1731
1732#[derive(Clone, Debug, Serialize, Deserialize)]
1735pub enum EntityType {
1736 Global(Global),
1738 Memory(Memory),
1740 Tag(Tag),
1742 Table(Table),
1744 Function(EngineOrModuleTypeIndex),
1747}
1748
1749impl TypeTrace for EntityType {
1750 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1751 where
1752 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1753 {
1754 match self {
1755 Self::Global(g) => g.trace(func),
1756 Self::Table(t) => t.trace(func),
1757 Self::Function(idx) => func(*idx),
1758 Self::Memory(_) => Ok(()),
1759 Self::Tag(t) => t.trace(func),
1760 }
1761 }
1762
1763 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1764 where
1765 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1766 {
1767 match self {
1768 Self::Global(g) => g.trace_mut(func),
1769 Self::Table(t) => t.trace_mut(func),
1770 Self::Function(idx) => func(idx),
1771 Self::Memory(_) => Ok(()),
1772 Self::Tag(t) => t.trace_mut(func),
1773 }
1774 }
1775}
1776
1777impl EntityType {
1778 pub fn unwrap_global(&self) -> &Global {
1780 match self {
1781 EntityType::Global(g) => g,
1782 _ => panic!("not a global"),
1783 }
1784 }
1785
1786 pub fn unwrap_memory(&self) -> &Memory {
1788 match self {
1789 EntityType::Memory(g) => g,
1790 _ => panic!("not a memory"),
1791 }
1792 }
1793
1794 pub fn unwrap_tag(&self) -> &Tag {
1796 match self {
1797 EntityType::Tag(g) => g,
1798 _ => panic!("not a tag"),
1799 }
1800 }
1801
1802 pub fn unwrap_table(&self) -> &Table {
1804 match self {
1805 EntityType::Table(g) => g,
1806 _ => panic!("not a table"),
1807 }
1808 }
1809
1810 pub fn unwrap_func(&self) -> EngineOrModuleTypeIndex {
1812 match self {
1813 EntityType::Function(g) => *g,
1814 _ => panic!("not a func"),
1815 }
1816 }
1817}
1818
1819#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1827pub struct Global {
1828 pub wasm_ty: crate::WasmValType,
1830 pub mutability: bool,
1832}
1833
1834impl TypeTrace for Global {
1835 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1836 where
1837 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1838 {
1839 let Global {
1840 wasm_ty,
1841 mutability: _,
1842 } = self;
1843 wasm_ty.trace(func)
1844 }
1845
1846 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1847 where
1848 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1849 {
1850 let Global {
1851 wasm_ty,
1852 mutability: _,
1853 } = self;
1854 wasm_ty.trace_mut(func)
1855 }
1856}
1857
1858#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1862pub struct ConstExpr {
1863 ops: SmallVec<[ConstOp; 2]>,
1864}
1865
1866impl ConstExpr {
1867 pub fn new(ops: impl IntoIterator<Item = ConstOp>) -> Self {
1873 let ops = ops.into_iter().collect::<SmallVec<[ConstOp; 2]>>();
1874 assert!(!ops.is_empty());
1875 ConstExpr { ops }
1876 }
1877
1878 pub fn from_wasmparser(
1883 env: &dyn TypeConvert,
1884 expr: wasmparser::ConstExpr<'_>,
1885 ) -> WasmResult<(Self, SmallVec<[FuncIndex; 1]>)> {
1886 let mut iter = expr
1887 .get_operators_reader()
1888 .into_iter_with_offsets()
1889 .peekable();
1890
1891 let mut ops = SmallVec::<[ConstOp; 2]>::new();
1892 let mut escaped = SmallVec::<[FuncIndex; 1]>::new();
1893 while let Some(res) = iter.next() {
1894 let (op, offset) = res?;
1895
1896 if matches!(op, wasmparser::Operator::End) && iter.peek().is_none() {
1900 break;
1901 }
1902
1903 if let wasmparser::Operator::RefFunc { function_index } = &op {
1906 escaped.push(FuncIndex::from_u32(*function_index));
1907 }
1908
1909 ops.push(ConstOp::from_wasmparser(env, op, offset)?);
1910 }
1911 Ok((Self { ops }, escaped))
1912 }
1913
1914 #[inline]
1916 pub fn ops(&self) -> &[ConstOp] {
1917 &self.ops
1918 }
1919
1920 pub fn provably_nonzero_i32(&self) -> bool {
1930 match self.const_eval() {
1931 Some(GlobalConstValue::I32(x)) => x != 0,
1932
1933 _ => false,
1936 }
1937 }
1938
1939 pub fn const_eval(&self) -> Option<GlobalConstValue> {
1941 match self.ops() {
1944 [ConstOp::I32Const(x)] => Some(GlobalConstValue::I32(*x)),
1945 [ConstOp::I64Const(x)] => Some(GlobalConstValue::I64(*x)),
1946 [ConstOp::F32Const(x)] => Some(GlobalConstValue::F32(*x)),
1947 [ConstOp::F64Const(x)] => Some(GlobalConstValue::F64(*x)),
1948 [ConstOp::V128Const(x)] => Some(GlobalConstValue::V128(*x)),
1949 _ => None,
1950 }
1951 }
1952}
1953
1954#[expect(missing_docs, reason = "self-describing variants")]
1956#[derive(Clone, Copy)]
1957pub enum GlobalConstValue {
1958 I32(i32),
1959 I64(i64),
1960 F32(u32),
1961 F64(u64),
1962 V128(u128),
1963}
1964
1965#[expect(missing_docs, reason = "self-describing variants")]
1967#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1968pub enum ConstOp {
1969 I32Const(i32),
1970 I64Const(i64),
1971 F32Const(u32),
1972 F64Const(u64),
1973 V128Const(u128),
1974 GlobalGet(GlobalIndex),
1975 RefI31,
1976 RefNull(WasmHeapTopType),
1977 RefFunc(FuncIndex),
1978 I32Add,
1979 I32Sub,
1980 I32Mul,
1981 I64Add,
1982 I64Sub,
1983 I64Mul,
1984 StructNew {
1985 struct_type_index: TypeIndex,
1986 },
1987 StructNewDefault {
1988 struct_type_index: TypeIndex,
1989 },
1990 ArrayNew {
1991 array_type_index: TypeIndex,
1992 },
1993 ArrayNewDefault {
1994 array_type_index: TypeIndex,
1995 },
1996 ArrayNewFixed {
1997 array_type_index: TypeIndex,
1998 array_size: u32,
1999 },
2000 ExternConvertAny,
2001 AnyConvertExtern,
2002}
2003
2004impl ConstOp {
2005 pub fn from_wasmparser(
2007 env: &dyn TypeConvert,
2008 op: wasmparser::Operator<'_>,
2009 offset: usize,
2010 ) -> WasmResult<Self> {
2011 use wasmparser::Operator as O;
2012 Ok(match op {
2013 O::I32Const { value } => Self::I32Const(value),
2014 O::I64Const { value } => Self::I64Const(value),
2015 O::F32Const { value } => Self::F32Const(value.bits()),
2016 O::F64Const { value } => Self::F64Const(value.bits()),
2017 O::V128Const { value } => Self::V128Const(u128::from_le_bytes(*value.bytes())),
2018 O::RefNull { hty } => Self::RefNull(env.convert_heap_type(hty)?.top()),
2019 O::RefFunc { function_index } => Self::RefFunc(FuncIndex::from_u32(function_index)),
2020 O::GlobalGet { global_index } => Self::GlobalGet(GlobalIndex::from_u32(global_index)),
2021 O::RefI31 => Self::RefI31,
2022 O::I32Add => Self::I32Add,
2023 O::I32Sub => Self::I32Sub,
2024 O::I32Mul => Self::I32Mul,
2025 O::I64Add => Self::I64Add,
2026 O::I64Sub => Self::I64Sub,
2027 O::I64Mul => Self::I64Mul,
2028 O::StructNew { struct_type_index } => Self::StructNew {
2029 struct_type_index: TypeIndex::from_u32(struct_type_index),
2030 },
2031 O::StructNewDefault { struct_type_index } => Self::StructNewDefault {
2032 struct_type_index: TypeIndex::from_u32(struct_type_index),
2033 },
2034 O::ArrayNew { array_type_index } => Self::ArrayNew {
2035 array_type_index: TypeIndex::from_u32(array_type_index),
2036 },
2037 O::ArrayNewDefault { array_type_index } => Self::ArrayNewDefault {
2038 array_type_index: TypeIndex::from_u32(array_type_index),
2039 },
2040 O::ArrayNewFixed {
2041 array_type_index,
2042 array_size,
2043 } => Self::ArrayNewFixed {
2044 array_type_index: TypeIndex::from_u32(array_type_index),
2045 array_size,
2046 },
2047 O::ExternConvertAny => Self::ExternConvertAny,
2048 O::AnyConvertExtern => Self::AnyConvertExtern,
2049 op => {
2050 return Err(wasm_unsupported!(
2051 "unsupported opcode in const expression at offset {offset:#x}: {op:?}",
2052 ));
2053 }
2054 })
2055 }
2056}
2057
2058#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2060#[expect(missing_docs, reason = "self-describing variants")]
2061pub enum IndexType {
2062 I32,
2063 I64,
2064}
2065
2066#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2068#[expect(missing_docs, reason = "self-describing fields")]
2069pub struct Limits {
2070 pub min: u64,
2071 pub max: Option<u64>,
2072}
2073
2074#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2076pub struct Table {
2077 pub idx_type: IndexType,
2079 pub limits: Limits,
2082 pub ref_type: WasmRefType,
2084}
2085
2086impl TypeTrace for Table {
2087 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
2088 where
2089 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
2090 {
2091 let Table {
2092 ref_type: wasm_ty,
2093 idx_type: _,
2094 limits: _,
2095 } = self;
2096 wasm_ty.trace(func)
2097 }
2098
2099 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
2100 where
2101 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
2102 {
2103 let Table {
2104 ref_type: wasm_ty,
2105 idx_type: _,
2106 limits: _,
2107 } = self;
2108 wasm_ty.trace_mut(func)
2109 }
2110}
2111
2112#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2114pub struct Memory {
2115 pub idx_type: IndexType,
2117 pub limits: Limits,
2120 pub shared: bool,
2122 pub page_size_log2: u8,
2127}
2128
2129pub const WASM32_MAX_SIZE: u64 = 1 << 32;
2131
2132impl Memory {
2133 pub const DEFAULT_PAGE_SIZE: u32 = 0x10000;
2135
2136 pub const DEFAULT_PAGE_SIZE_LOG2: u8 = {
2138 let log2 = 16;
2139 assert!(1 << log2 == Memory::DEFAULT_PAGE_SIZE);
2140 log2
2141 };
2142
2143 pub fn minimum_byte_size(&self) -> Result<u64, SizeOverflow> {
2151 self.limits
2152 .min
2153 .checked_mul(self.page_size())
2154 .ok_or(SizeOverflow)
2155 }
2156
2157 pub fn maximum_byte_size(&self) -> Result<u64, SizeOverflow> {
2172 match self.limits.max {
2173 Some(max) => max.checked_mul(self.page_size()).ok_or(SizeOverflow),
2174 None => {
2175 let min = self.minimum_byte_size()?;
2176 Ok(min.max(self.max_size_based_on_index_type()))
2177 }
2178 }
2179 }
2180
2181 pub fn page_size(&self) -> u64 {
2183 debug_assert!(
2184 self.page_size_log2 == 16 || self.page_size_log2 == 0,
2185 "invalid page_size_log2: {}; must be 16 or 0",
2186 self.page_size_log2
2187 );
2188 1 << self.page_size_log2
2189 }
2190
2191 pub fn max_size_based_on_index_type(&self) -> u64 {
2196 match self.idx_type {
2197 IndexType::I64 =>
2198 {
2206 0_u64.wrapping_sub(self.page_size())
2207 }
2208 IndexType::I32 => WASM32_MAX_SIZE,
2209 }
2210 }
2211
2212 pub fn can_use_virtual_memory(&self, tunables: &Tunables, host_page_size_log2: u8) -> bool {
2224 tunables.signals_based_traps && self.page_size_log2 >= host_page_size_log2
2225 }
2226
2227 pub fn can_elide_bounds_check(&self, tunables: &Tunables, host_page_size_log2: u8) -> bool {
2247 self.can_use_virtual_memory(tunables, host_page_size_log2)
2248 && self.idx_type == IndexType::I32
2249 && tunables.memory_reservation + tunables.memory_guard_size >= (1 << 32)
2250 }
2251
2252 pub fn static_heap_size(&self) -> Option<u64> {
2256 let min = self.minimum_byte_size().ok()?;
2257 let max = self.maximum_byte_size().ok()?;
2258 if min == max { Some(min) } else { None }
2259 }
2260
2261 pub fn memory_may_move(&self, tunables: &Tunables) -> bool {
2268 if self.shared {
2272 return false;
2273 }
2274
2275 if !tunables.memory_may_move {
2278 return false;
2279 }
2280
2281 if self.limits.max.is_some_and(|max| self.limits.min == max) {
2284 return false;
2285 }
2286
2287 let max = self.maximum_byte_size().unwrap_or(u64::MAX);
2290 max > tunables.memory_reservation
2291 }
2292}
2293
2294#[derive(Copy, Clone, Debug)]
2295#[expect(missing_docs, reason = "self-describing error struct")]
2296pub struct SizeOverflow;
2297
2298impl fmt::Display for SizeOverflow {
2299 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2300 f.write_str("size overflow calculating memory size")
2301 }
2302}
2303
2304impl core::error::Error for SizeOverflow {}
2305
2306impl From<wasmparser::MemoryType> for Memory {
2307 fn from(ty: wasmparser::MemoryType) -> Memory {
2308 let idx_type = match ty.memory64 {
2309 false => IndexType::I32,
2310 true => IndexType::I64,
2311 };
2312 let limits = Limits {
2313 min: ty.initial,
2314 max: ty.maximum,
2315 };
2316 let page_size_log2 = u8::try_from(ty.page_size_log2.unwrap_or(16)).unwrap();
2317 debug_assert!(
2318 page_size_log2 == 16 || page_size_log2 == 0,
2319 "invalid page_size_log2: {page_size_log2}; must be 16 or 0"
2320 );
2321 Memory {
2322 idx_type,
2323 limits,
2324 shared: ty.shared,
2325 page_size_log2,
2326 }
2327 }
2328}
2329
2330#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2332pub struct Tag {
2333 pub signature: EngineOrModuleTypeIndex,
2335 pub exception: EngineOrModuleTypeIndex,
2337}
2338
2339impl TypeTrace for Tag {
2340 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
2341 where
2342 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
2343 {
2344 func(self.signature)?;
2345 func(self.exception)?;
2346 Ok(())
2347 }
2348
2349 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
2350 where
2351 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
2352 {
2353 func(&mut self.signature)?;
2354 func(&mut self.exception)?;
2355 Ok(())
2356 }
2357}
2358
2359#[expect(missing_docs, reason = "self-describing functions")]
2361pub trait TypeConvert {
2362 fn convert_global_type(&self, ty: &wasmparser::GlobalType) -> WasmResult<Global> {
2364 Ok(Global {
2365 wasm_ty: self.convert_valtype(ty.content_type)?,
2366 mutability: ty.mutable,
2367 })
2368 }
2369
2370 fn convert_table_type(&self, ty: &wasmparser::TableType) -> WasmResult<Table> {
2372 let idx_type = match ty.table64 {
2373 false => IndexType::I32,
2374 true => IndexType::I64,
2375 };
2376 let limits = Limits {
2377 min: ty.initial,
2378 max: ty.maximum,
2379 };
2380 Ok(Table {
2381 idx_type,
2382 limits,
2383 ref_type: self.convert_ref_type(ty.element_type)?,
2384 })
2385 }
2386
2387 fn convert_sub_type(&self, ty: &wasmparser::SubType) -> WasmResult<WasmSubType> {
2388 Ok(WasmSubType {
2389 is_final: ty.is_final,
2390 supertype: ty.supertype_idx.map(|i| self.lookup_type_index(i.unpack())),
2391 composite_type: self.convert_composite_type(&ty.composite_type)?,
2392 })
2393 }
2394
2395 fn convert_composite_type(
2396 &self,
2397 ty: &wasmparser::CompositeType,
2398 ) -> WasmResult<WasmCompositeType> {
2399 let inner = match &ty.inner {
2400 wasmparser::CompositeInnerType::Func(f) => {
2401 WasmCompositeInnerType::Func(self.convert_func_type(f)?)
2402 }
2403 wasmparser::CompositeInnerType::Array(a) => {
2404 WasmCompositeInnerType::Array(self.convert_array_type(a)?)
2405 }
2406 wasmparser::CompositeInnerType::Struct(s) => {
2407 WasmCompositeInnerType::Struct(self.convert_struct_type(s)?)
2408 }
2409 wasmparser::CompositeInnerType::Cont(c) => {
2410 WasmCompositeInnerType::Cont(self.convert_cont_type(c))
2411 }
2412 };
2413 Ok(WasmCompositeType {
2414 inner,
2415 shared: ty.shared,
2416 })
2417 }
2418
2419 fn convert_cont_type(&self, ty: &wasmparser::ContType) -> WasmContType {
2421 if let WasmHeapType::ConcreteFunc(sigidx) = self.lookup_heap_type(ty.0.unpack()) {
2422 WasmContType::new(sigidx)
2423 } else {
2424 panic!("Failed to extract signature index for continuation type.")
2425 }
2426 }
2427
2428 fn convert_struct_type(&self, ty: &wasmparser::StructType) -> WasmResult<WasmStructType> {
2429 Ok(WasmStructType {
2430 fields: ty
2431 .fields
2432 .iter()
2433 .map(|f| self.convert_field_type(f))
2434 .collect::<WasmResult<_>>()?,
2435 })
2436 }
2437
2438 fn convert_array_type(&self, ty: &wasmparser::ArrayType) -> WasmResult<WasmArrayType> {
2439 Ok(WasmArrayType(self.convert_field_type(&ty.0)?))
2440 }
2441
2442 fn convert_field_type(&self, ty: &wasmparser::FieldType) -> WasmResult<WasmFieldType> {
2443 Ok(WasmFieldType {
2444 element_type: self.convert_storage_type(&ty.element_type)?,
2445 mutable: ty.mutable,
2446 })
2447 }
2448
2449 fn convert_storage_type(&self, ty: &wasmparser::StorageType) -> WasmResult<WasmStorageType> {
2450 Ok(match ty {
2451 wasmparser::StorageType::I8 => WasmStorageType::I8,
2452 wasmparser::StorageType::I16 => WasmStorageType::I16,
2453 wasmparser::StorageType::Val(v) => WasmStorageType::Val(self.convert_valtype(*v)?),
2454 })
2455 }
2456
2457 fn convert_func_type(&self, ty: &wasmparser::FuncType) -> WasmResult<WasmFuncType> {
2459 let params = ty
2460 .params()
2461 .iter()
2462 .map(|t| self.convert_valtype(*t))
2463 .collect::<WasmResult<_>>()?;
2464 let results = ty
2465 .results()
2466 .iter()
2467 .map(|t| self.convert_valtype(*t))
2468 .collect::<WasmResult<_>>()?;
2469 Ok(WasmFuncType::new(params, results))
2470 }
2471
2472 fn convert_valtype(&self, ty: wasmparser::ValType) -> WasmResult<WasmValType> {
2474 Ok(match ty {
2475 wasmparser::ValType::I32 => WasmValType::I32,
2476 wasmparser::ValType::I64 => WasmValType::I64,
2477 wasmparser::ValType::F32 => WasmValType::F32,
2478 wasmparser::ValType::F64 => WasmValType::F64,
2479 wasmparser::ValType::V128 => WasmValType::V128,
2480 wasmparser::ValType::Ref(t) => WasmValType::Ref(self.convert_ref_type(t)?),
2481 })
2482 }
2483
2484 fn convert_ref_type(&self, ty: wasmparser::RefType) -> WasmResult<WasmRefType> {
2486 Ok(WasmRefType {
2487 nullable: ty.is_nullable(),
2488 heap_type: self.convert_heap_type(ty.heap_type())?,
2489 })
2490 }
2491
2492 fn convert_heap_type(&self, ty: wasmparser::HeapType) -> WasmResult<WasmHeapType> {
2494 Ok(match ty {
2495 wasmparser::HeapType::Concrete(i) => self.lookup_heap_type(i),
2496 wasmparser::HeapType::Abstract { ty, shared: false } => match ty {
2497 wasmparser::AbstractHeapType::Extern => WasmHeapType::Extern,
2498 wasmparser::AbstractHeapType::NoExtern => WasmHeapType::NoExtern,
2499 wasmparser::AbstractHeapType::Func => WasmHeapType::Func,
2500 wasmparser::AbstractHeapType::NoFunc => WasmHeapType::NoFunc,
2501 wasmparser::AbstractHeapType::Any => WasmHeapType::Any,
2502 wasmparser::AbstractHeapType::Eq => WasmHeapType::Eq,
2503 wasmparser::AbstractHeapType::I31 => WasmHeapType::I31,
2504 wasmparser::AbstractHeapType::Array => WasmHeapType::Array,
2505 wasmparser::AbstractHeapType::Struct => WasmHeapType::Struct,
2506 wasmparser::AbstractHeapType::None => WasmHeapType::None,
2507 wasmparser::AbstractHeapType::Cont => WasmHeapType::Cont,
2508 wasmparser::AbstractHeapType::NoCont => WasmHeapType::NoCont,
2509 wasmparser::AbstractHeapType::Exn => WasmHeapType::Exn,
2510 wasmparser::AbstractHeapType::NoExn => WasmHeapType::NoExn,
2511 },
2512 _ => return Err(wasm_unsupported!("unsupported heap type {ty:?}")),
2513 })
2514 }
2515
2516 fn lookup_heap_type(&self, index: wasmparser::UnpackedIndex) -> WasmHeapType;
2519
2520 fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex;
2523}