1use crate::{Tunables, WasmResult, 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;
8
9pub trait TypeTrace {
12    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
16    where
17        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>;
18
19    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
25    where
26        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>;
27
28    fn trace_engine_indices<F, E>(&self, func: &mut F) -> Result<(), E>
30    where
31        F: FnMut(VMSharedTypeIndex) -> Result<(), E>,
32    {
33        self.trace(&mut |idx| match idx {
34            EngineOrModuleTypeIndex::Engine(idx) => func(idx),
35            EngineOrModuleTypeIndex::Module(_) | EngineOrModuleTypeIndex::RecGroup(_) => Ok(()),
36        })
37    }
38
39    fn canonicalize_for_runtime_usage<F>(&mut self, module_to_engine: &mut F)
50    where
51        F: FnMut(ModuleInternedTypeIndex) -> VMSharedTypeIndex,
52    {
53        self.trace_mut::<_, ()>(&mut |idx| match idx {
54            EngineOrModuleTypeIndex::Engine(_) => Ok(()),
55            EngineOrModuleTypeIndex::Module(module_index) => {
56                let engine_index = module_to_engine(*module_index);
57                *idx = EngineOrModuleTypeIndex::Engine(engine_index);
58                Ok(())
59            }
60            EngineOrModuleTypeIndex::RecGroup(_) => {
61                panic!("should not already be canonicalized for hash consing")
62            }
63        })
64        .unwrap()
65    }
66
67    fn is_canonicalized_for_runtime_usage(&self) -> bool {
69        self.trace(&mut |idx| match idx {
70            EngineOrModuleTypeIndex::Engine(_) => Ok(()),
71            EngineOrModuleTypeIndex::Module(_) | EngineOrModuleTypeIndex::RecGroup(_) => Err(()),
72        })
73        .is_ok()
74    }
75
76    fn canonicalize_for_hash_consing<F>(
87        &mut self,
88        rec_group_range: Range<ModuleInternedTypeIndex>,
89        module_to_engine: &mut F,
90    ) where
91        F: FnMut(ModuleInternedTypeIndex) -> VMSharedTypeIndex,
92    {
93        self.trace_mut::<_, ()>(&mut |idx| match *idx {
94            EngineOrModuleTypeIndex::Engine(_) => Ok(()),
95            EngineOrModuleTypeIndex::Module(module_index) => {
96                *idx = if rec_group_range.start <= module_index {
97                    debug_assert!(module_index < rec_group_range.end);
100                    let relative = module_index.as_u32() - rec_group_range.start.as_u32();
101                    let relative = RecGroupRelativeTypeIndex::from_u32(relative);
102                    EngineOrModuleTypeIndex::RecGroup(relative)
103                } else {
104                    debug_assert!(module_index < rec_group_range.start);
107                    EngineOrModuleTypeIndex::Engine(module_to_engine(module_index))
108                };
109                Ok(())
110            }
111            EngineOrModuleTypeIndex::RecGroup(_) => {
112                panic!("should not already be canonicalized for hash consing")
113            }
114        })
115        .unwrap()
116    }
117
118    fn is_canonicalized_for_hash_consing(&self) -> bool {
120        self.trace(&mut |idx| match idx {
121            EngineOrModuleTypeIndex::Engine(_) | EngineOrModuleTypeIndex::RecGroup(_) => Ok(()),
122            EngineOrModuleTypeIndex::Module(_) => Err(()),
123        })
124        .is_ok()
125    }
126}
127
128#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
130pub enum WasmValType {
131    I32,
133    I64,
135    F32,
137    F64,
139    V128,
141    Ref(WasmRefType),
143}
144
145impl fmt::Display for WasmValType {
146    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
147        match self {
148            WasmValType::I32 => write!(f, "i32"),
149            WasmValType::I64 => write!(f, "i64"),
150            WasmValType::F32 => write!(f, "f32"),
151            WasmValType::F64 => write!(f, "f64"),
152            WasmValType::V128 => write!(f, "v128"),
153            WasmValType::Ref(rt) => write!(f, "{rt}"),
154        }
155    }
156}
157
158impl TypeTrace for WasmValType {
159    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
160    where
161        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
162    {
163        match self {
164            WasmValType::Ref(r) => r.trace(func),
165            WasmValType::I32
166            | WasmValType::I64
167            | WasmValType::F32
168            | WasmValType::F64
169            | WasmValType::V128 => Ok(()),
170        }
171    }
172
173    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
174    where
175        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
176    {
177        match self {
178            WasmValType::Ref(r) => r.trace_mut(func),
179            WasmValType::I32
180            | WasmValType::I64
181            | WasmValType::F32
182            | WasmValType::F64
183            | WasmValType::V128 => Ok(()),
184        }
185    }
186}
187
188impl WasmValType {
189    #[inline]
191    pub fn is_vmgcref_type(&self) -> bool {
192        match self {
193            WasmValType::Ref(r) => r.is_vmgcref_type(),
194            _ => false,
195        }
196    }
197
198    #[inline]
204    pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
205        match self {
206            WasmValType::Ref(r) => r.is_vmgcref_type_and_not_i31(),
207            _ => false,
208        }
209    }
210
211    fn trampoline_type(&self) -> Self {
212        match self {
213            WasmValType::Ref(r) => WasmValType::Ref(WasmRefType {
214                nullable: true,
215                heap_type: r.heap_type.top().into(),
216            }),
217            WasmValType::I32
218            | WasmValType::I64
219            | WasmValType::F32
220            | WasmValType::F64
221            | WasmValType::V128 => *self,
222        }
223    }
224
225    pub fn int_from_bits(bits: u8) -> Self {
229        match bits {
230            32 => Self::I32,
231            64 => Self::I64,
232            size => panic!("invalid int bits for WasmValType: {size}"),
233        }
234    }
235
236    pub fn unwrap_ref_type(&self) -> WasmRefType {
240        match self {
241            WasmValType::Ref(ref_type) => *ref_type,
242            _ => panic!("Called WasmValType::unwrap_ref_type on non-reference type"),
243        }
244    }
245}
246
247#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
249pub struct WasmRefType {
250    pub nullable: bool,
252    pub heap_type: WasmHeapType,
254}
255
256impl TypeTrace for WasmRefType {
257    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
258    where
259        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
260    {
261        self.heap_type.trace(func)
262    }
263
264    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
265    where
266        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
267    {
268        self.heap_type.trace_mut(func)
269    }
270}
271
272impl WasmRefType {
273    pub const EXTERNREF: WasmRefType = WasmRefType {
275        nullable: true,
276        heap_type: WasmHeapType::Extern,
277    };
278    pub const FUNCREF: WasmRefType = WasmRefType {
280        nullable: true,
281        heap_type: WasmHeapType::Func,
282    };
283
284    #[inline]
286    pub fn is_vmgcref_type(&self) -> bool {
287        self.heap_type.is_vmgcref_type()
288    }
289
290    #[inline]
296    pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
297        self.heap_type.is_vmgcref_type_and_not_i31()
298    }
299}
300
301impl fmt::Display for WasmRefType {
302    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
303        match *self {
304            Self::FUNCREF => write!(f, "funcref"),
305            Self::EXTERNREF => write!(f, "externref"),
306            _ => {
307                if self.nullable {
308                    write!(f, "(ref null {})", self.heap_type)
309                } else {
310                    write!(f, "(ref {})", self.heap_type)
311                }
312            }
313        }
314    }
315}
316
317#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
322pub enum EngineOrModuleTypeIndex {
323    Engine(VMSharedTypeIndex),
326
327    Module(ModuleInternedTypeIndex),
330
331    RecGroup(RecGroupRelativeTypeIndex),
335}
336
337impl From<ModuleInternedTypeIndex> for EngineOrModuleTypeIndex {
338    #[inline]
339    fn from(i: ModuleInternedTypeIndex) -> Self {
340        Self::Module(i)
341    }
342}
343
344impl From<VMSharedTypeIndex> for EngineOrModuleTypeIndex {
345    #[inline]
346    fn from(i: VMSharedTypeIndex) -> Self {
347        Self::Engine(i)
348    }
349}
350
351impl From<RecGroupRelativeTypeIndex> for EngineOrModuleTypeIndex {
352    #[inline]
353    fn from(i: RecGroupRelativeTypeIndex) -> Self {
354        Self::RecGroup(i)
355    }
356}
357
358impl fmt::Display for EngineOrModuleTypeIndex {
359    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
360        match self {
361            Self::Engine(i) => write!(f, "(engine {})", i.bits()),
362            Self::Module(i) => write!(f, "(module {})", i.as_u32()),
363            Self::RecGroup(i) => write!(f, "(recgroup {})", i.as_u32()),
364        }
365    }
366}
367
368impl EngineOrModuleTypeIndex {
369    pub fn is_engine_type_index(self) -> bool {
371        matches!(self, Self::Engine(_))
372    }
373
374    #[inline]
376    pub fn as_engine_type_index(self) -> Option<VMSharedTypeIndex> {
377        match self {
378            Self::Engine(e) => Some(e),
379            Self::RecGroup(_) | Self::Module(_) => None,
380        }
381    }
382
383    #[track_caller]
385    #[inline]
386    pub fn unwrap_engine_type_index(self) -> VMSharedTypeIndex {
387        match self.as_engine_type_index() {
388            Some(x) => x,
389            None => panic!("`unwrap_engine_type_index` on {self:?}"),
390        }
391    }
392
393    pub fn is_module_type_index(self) -> bool {
395        matches!(self, Self::Module(_))
396    }
397
398    pub fn as_module_type_index(self) -> Option<ModuleInternedTypeIndex> {
400        match self {
401            Self::Module(e) => Some(e),
402            Self::RecGroup(_) | Self::Engine(_) => None,
403        }
404    }
405
406    #[track_caller]
408    pub fn unwrap_module_type_index(self) -> ModuleInternedTypeIndex {
409        match self.as_module_type_index() {
410            Some(x) => x,
411            None => panic!("`unwrap_module_type_index` on {self:?}"),
412        }
413    }
414
415    pub fn is_rec_group_type_index(self) -> bool {
417        matches!(self, Self::RecGroup(_))
418    }
419
420    pub fn as_rec_group_type_index(self) -> Option<RecGroupRelativeTypeIndex> {
422        match self {
423            Self::RecGroup(r) => Some(r),
424            Self::Module(_) | Self::Engine(_) => None,
425        }
426    }
427
428    #[track_caller]
430    pub fn unwrap_rec_group_type_index(self) -> RecGroupRelativeTypeIndex {
431        match self.as_rec_group_type_index() {
432            Some(x) => x,
433            None => panic!("`unwrap_rec_group_type_index` on {self:?}"),
434        }
435    }
436}
437
438#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
440#[expect(missing_docs, reason = "self-describing variants")]
441pub enum WasmHeapType {
442    Extern,
444    NoExtern,
445
446    Func,
448    ConcreteFunc(EngineOrModuleTypeIndex),
449    NoFunc,
450
451    Exn,
453    ConcreteExn(EngineOrModuleTypeIndex),
454    NoExn,
455
456    Cont,
458    ConcreteCont(EngineOrModuleTypeIndex),
459    NoCont,
460
461    Any,
463    Eq,
464    I31,
465    Array,
466    ConcreteArray(EngineOrModuleTypeIndex),
467    Struct,
468    ConcreteStruct(EngineOrModuleTypeIndex),
469    None,
470}
471
472impl From<WasmHeapTopType> for WasmHeapType {
473    #[inline]
474    fn from(value: WasmHeapTopType) -> Self {
475        match value {
476            WasmHeapTopType::Extern => Self::Extern,
477            WasmHeapTopType::Any => Self::Any,
478            WasmHeapTopType::Func => Self::Func,
479            WasmHeapTopType::Cont => Self::Cont,
480            WasmHeapTopType::Exn => Self::Exn,
481        }
482    }
483}
484
485impl From<WasmHeapBottomType> for WasmHeapType {
486    #[inline]
487    fn from(value: WasmHeapBottomType) -> Self {
488        match value {
489            WasmHeapBottomType::NoExtern => Self::NoExtern,
490            WasmHeapBottomType::None => Self::None,
491            WasmHeapBottomType::NoFunc => Self::NoFunc,
492            WasmHeapBottomType::NoCont => Self::NoCont,
493            WasmHeapBottomType::NoExn => Self::NoExn,
494        }
495    }
496}
497
498impl fmt::Display for WasmHeapType {
499    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
500        match self {
501            Self::Extern => write!(f, "extern"),
502            Self::NoExtern => write!(f, "noextern"),
503            Self::Func => write!(f, "func"),
504            Self::ConcreteFunc(i) => write!(f, "func {i}"),
505            Self::NoFunc => write!(f, "nofunc"),
506            Self::Cont => write!(f, "cont"),
507            Self::ConcreteCont(i) => write!(f, "cont {i}"),
508            Self::NoCont => write!(f, "nocont"),
509            Self::Any => write!(f, "any"),
510            Self::Eq => write!(f, "eq"),
511            Self::I31 => write!(f, "i31"),
512            Self::Array => write!(f, "array"),
513            Self::ConcreteArray(i) => write!(f, "array {i}"),
514            Self::Struct => write!(f, "struct"),
515            Self::ConcreteStruct(i) => write!(f, "struct {i}"),
516            Self::Exn => write!(f, "exn"),
517            Self::ConcreteExn(i) => write!(f, "exn {i}"),
518            Self::NoExn => write!(f, "noexn"),
519            Self::None => write!(f, "none"),
520        }
521    }
522}
523
524impl TypeTrace for WasmHeapType {
525    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
526    where
527        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
528    {
529        match *self {
530            Self::ConcreteArray(i) => func(i),
531            Self::ConcreteFunc(i) => func(i),
532            Self::ConcreteStruct(i) => func(i),
533            Self::ConcreteCont(i) => func(i),
534            _ => Ok(()),
535        }
536    }
537
538    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
539    where
540        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
541    {
542        match self {
543            Self::ConcreteArray(i) => func(i),
544            Self::ConcreteFunc(i) => func(i),
545            Self::ConcreteStruct(i) => func(i),
546            Self::ConcreteCont(i) => func(i),
547            _ => Ok(()),
548        }
549    }
550}
551
552impl WasmHeapType {
553    #[inline]
555    pub fn is_vmgcref_type(&self) -> bool {
556        match self.top() {
557            WasmHeapTopType::Any | WasmHeapTopType::Extern | WasmHeapTopType::Exn => true,
561
562            WasmHeapTopType::Func => false,
564            WasmHeapTopType::Cont => false,
565        }
566    }
567
568    #[inline]
574    pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
575        self.is_vmgcref_type() && *self != Self::I31
576    }
577
578    #[inline]
580    pub fn is_top(&self) -> bool {
581        *self == Self::from(self.top())
582    }
583
584    #[inline]
586    pub fn top(&self) -> WasmHeapTopType {
587        match self {
588            WasmHeapType::Extern | WasmHeapType::NoExtern => WasmHeapTopType::Extern,
589
590            WasmHeapType::Func | WasmHeapType::ConcreteFunc(_) | WasmHeapType::NoFunc => {
591                WasmHeapTopType::Func
592            }
593
594            WasmHeapType::Cont | WasmHeapType::ConcreteCont(_) | WasmHeapType::NoCont => {
595                WasmHeapTopType::Cont
596            }
597
598            WasmHeapType::Exn | WasmHeapType::ConcreteExn(_) | WasmHeapType::NoExn => {
599                WasmHeapTopType::Exn
600            }
601
602            WasmHeapType::Any
603            | WasmHeapType::Eq
604            | WasmHeapType::I31
605            | WasmHeapType::Array
606            | WasmHeapType::ConcreteArray(_)
607            | WasmHeapType::Struct
608            | WasmHeapType::ConcreteStruct(_)
609            | WasmHeapType::None => WasmHeapTopType::Any,
610        }
611    }
612
613    #[inline]
615    pub fn is_bottom(&self) -> bool {
616        *self == Self::from(self.bottom())
617    }
618
619    #[inline]
621    pub fn bottom(&self) -> WasmHeapBottomType {
622        match self {
623            WasmHeapType::Extern | WasmHeapType::NoExtern => WasmHeapBottomType::NoExtern,
624
625            WasmHeapType::Func | WasmHeapType::ConcreteFunc(_) | WasmHeapType::NoFunc => {
626                WasmHeapBottomType::NoFunc
627            }
628
629            WasmHeapType::Cont | WasmHeapType::ConcreteCont(_) | WasmHeapType::NoCont => {
630                WasmHeapBottomType::NoCont
631            }
632
633            WasmHeapType::Exn | WasmHeapType::ConcreteExn(_) | WasmHeapType::NoExn => {
634                WasmHeapBottomType::NoExn
635            }
636
637            WasmHeapType::Any
638            | WasmHeapType::Eq
639            | WasmHeapType::I31
640            | WasmHeapType::Array
641            | WasmHeapType::ConcreteArray(_)
642            | WasmHeapType::Struct
643            | WasmHeapType::ConcreteStruct(_)
644            | WasmHeapType::None => WasmHeapBottomType::None,
645        }
646    }
647}
648
649#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
651pub enum WasmHeapTopType {
652    Extern,
654    Any,
656    Func,
658    Exn,
660    Cont,
662}
663
664#[derive(Debug, Clone, Copy, Eq, PartialEq)]
666pub enum WasmHeapBottomType {
667    NoExtern,
669    None,
671    NoFunc,
673    NoExn,
675    NoCont,
677}
678
679#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
681pub struct WasmFuncType {
682    params: Box<[WasmValType]>,
683    non_i31_gc_ref_params_count: usize,
684    returns: Box<[WasmValType]>,
685    non_i31_gc_ref_returns_count: usize,
686}
687
688impl fmt::Display for WasmFuncType {
689    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
690        write!(f, "(func")?;
691        if !self.params.is_empty() {
692            write!(f, " (param")?;
693            for p in self.params.iter() {
694                write!(f, " {p}")?;
695            }
696            write!(f, ")")?;
697        }
698        if !self.returns.is_empty() {
699            write!(f, " (result")?;
700            for r in self.returns.iter() {
701                write!(f, " {r}")?;
702            }
703            write!(f, ")")?;
704        }
705        write!(f, ")")
706    }
707}
708
709impl TypeTrace for WasmFuncType {
710    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
711    where
712        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
713    {
714        for p in self.params.iter() {
715            p.trace(func)?;
716        }
717        for r in self.returns.iter() {
718            r.trace(func)?;
719        }
720        Ok(())
721    }
722
723    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
724    where
725        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
726    {
727        for p in self.params.iter_mut() {
728            p.trace_mut(func)?;
729        }
730        for r in self.returns.iter_mut() {
731            r.trace_mut(func)?;
732        }
733        Ok(())
734    }
735}
736
737impl WasmFuncType {
738    #[inline]
740    pub fn new(params: Box<[WasmValType]>, returns: Box<[WasmValType]>) -> Self {
741        let non_i31_gc_ref_params_count = params
742            .iter()
743            .filter(|p| p.is_vmgcref_type_and_not_i31())
744            .count();
745        let non_i31_gc_ref_returns_count = returns
746            .iter()
747            .filter(|r| r.is_vmgcref_type_and_not_i31())
748            .count();
749        WasmFuncType {
750            params,
751            non_i31_gc_ref_params_count,
752            returns,
753            non_i31_gc_ref_returns_count,
754        }
755    }
756
757    #[inline]
759    pub fn params(&self) -> &[WasmValType] {
760        &self.params
761    }
762
763    #[inline]
765    pub fn non_i31_gc_ref_params_count(&self) -> usize {
766        self.non_i31_gc_ref_params_count
767    }
768
769    #[inline]
771    pub fn returns(&self) -> &[WasmValType] {
772        &self.returns
773    }
774
775    #[inline]
777    pub fn non_i31_gc_ref_returns_count(&self) -> usize {
778        self.non_i31_gc_ref_returns_count
779    }
780
781    pub fn is_trampoline_type(&self) -> bool {
783        self.params().iter().all(|p| *p == p.trampoline_type())
784            && self.returns().iter().all(|r| *r == r.trampoline_type())
785    }
786
787    pub fn trampoline_type(&self) -> Cow<'_, Self> {
813        if self.is_trampoline_type() {
814            return Cow::Borrowed(self);
815        }
816
817        Cow::Owned(Self::new(
818            self.params().iter().map(|p| p.trampoline_type()).collect(),
819            self.returns().iter().map(|r| r.trampoline_type()).collect(),
820        ))
821    }
822}
823
824#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
826pub struct WasmContType(EngineOrModuleTypeIndex);
827
828impl fmt::Display for WasmContType {
829    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
830        write!(f, "(cont {})", self.0)
831    }
832}
833
834impl WasmContType {
835    pub fn new(idx: EngineOrModuleTypeIndex) -> Self {
837        WasmContType(idx)
838    }
839
840    pub fn unwrap_module_type_index(self) -> ModuleInternedTypeIndex {
842        match self.0 {
843            EngineOrModuleTypeIndex::Engine(_) => panic!("not module interned"),
844            EngineOrModuleTypeIndex::Module(idx) => idx,
845            EngineOrModuleTypeIndex::RecGroup(_) => todo!(),
846        }
847    }
848}
849
850impl TypeTrace for WasmContType {
851    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
852    where
853        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
854    {
855        func(self.0)
856    }
857
858    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
859    where
860        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
861    {
862        func(&mut self.0)
863    }
864}
865
866#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
891pub struct WasmExnType {
892    pub func_ty: EngineOrModuleTypeIndex,
896    pub fields: Box<[WasmFieldType]>,
903}
904
905impl fmt::Display for WasmExnType {
906    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
907        write!(f, "(exn ({})", self.func_ty)?;
908        for ty in self.fields.iter() {
909            write!(f, " {ty}")?;
910        }
911        write!(f, ")")
912    }
913}
914
915impl TypeTrace for WasmExnType {
916    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
917    where
918        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
919    {
920        func(self.func_ty)?;
921        for f in self.fields.iter() {
922            f.trace(func)?;
923        }
924        Ok(())
925    }
926
927    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
928    where
929        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
930    {
931        func(&mut self.func_ty)?;
932        for f in self.fields.iter_mut() {
933            f.trace_mut(func)?;
934        }
935        Ok(())
936    }
937}
938
939#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
941pub enum WasmStorageType {
942    I8,
944    I16,
946    Val(WasmValType),
948}
949
950impl fmt::Display for WasmStorageType {
951    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
952        match self {
953            WasmStorageType::I8 => write!(f, "i8"),
954            WasmStorageType::I16 => write!(f, "i16"),
955            WasmStorageType::Val(v) => fmt::Display::fmt(v, f),
956        }
957    }
958}
959
960impl TypeTrace for WasmStorageType {
961    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
962    where
963        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
964    {
965        match self {
966            WasmStorageType::I8 | WasmStorageType::I16 => Ok(()),
967            WasmStorageType::Val(v) => v.trace(func),
968        }
969    }
970
971    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
972    where
973        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
974    {
975        match self {
976            WasmStorageType::I8 | WasmStorageType::I16 => Ok(()),
977            WasmStorageType::Val(v) => v.trace_mut(func),
978        }
979    }
980}
981
982impl WasmStorageType {
983    pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
989        match self {
990            WasmStorageType::I8 | WasmStorageType::I16 => false,
991            WasmStorageType::Val(v) => v.is_vmgcref_type_and_not_i31(),
992        }
993    }
994}
995
996#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
998pub struct WasmFieldType {
999    pub element_type: WasmStorageType,
1001
1002    pub mutable: bool,
1004}
1005
1006impl fmt::Display for WasmFieldType {
1007    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1008        if self.mutable {
1009            write!(f, "(mut {})", self.element_type)
1010        } else {
1011            fmt::Display::fmt(&self.element_type, f)
1012        }
1013    }
1014}
1015
1016impl TypeTrace for WasmFieldType {
1017    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1018    where
1019        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1020    {
1021        self.element_type.trace(func)
1022    }
1023
1024    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1025    where
1026        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1027    {
1028        self.element_type.trace_mut(func)
1029    }
1030}
1031
1032#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1034pub struct WasmArrayType(pub WasmFieldType);
1035
1036impl fmt::Display for WasmArrayType {
1037    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1038        write!(f, "(array {})", self.0)
1039    }
1040}
1041
1042impl TypeTrace for WasmArrayType {
1043    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1044    where
1045        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1046    {
1047        self.0.trace(func)
1048    }
1049
1050    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1051    where
1052        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1053    {
1054        self.0.trace_mut(func)
1055    }
1056}
1057
1058#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1060pub struct WasmStructType {
1061    pub fields: Box<[WasmFieldType]>,
1063}
1064
1065impl fmt::Display for WasmStructType {
1066    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1067        write!(f, "(struct")?;
1068        for ty in self.fields.iter() {
1069            write!(f, " {ty}")?;
1070        }
1071        write!(f, ")")
1072    }
1073}
1074
1075impl TypeTrace for WasmStructType {
1076    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1077    where
1078        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1079    {
1080        for f in self.fields.iter() {
1081            f.trace(func)?;
1082        }
1083        Ok(())
1084    }
1085
1086    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1087    where
1088        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1089    {
1090        for f in self.fields.iter_mut() {
1091            f.trace_mut(func)?;
1092        }
1093        Ok(())
1094    }
1095}
1096
1097#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1098#[expect(missing_docs, reason = "self-describing type")]
1099pub struct WasmCompositeType {
1100    pub inner: WasmCompositeInnerType,
1102    pub shared: bool,
1105}
1106
1107impl fmt::Display for WasmCompositeType {
1108    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1109        if self.shared {
1110            write!(f, "(shared ")?;
1111        }
1112        fmt::Display::fmt(&self.inner, f)?;
1113        if self.shared {
1114            write!(f, ")")?;
1115        }
1116        Ok(())
1117    }
1118}
1119
1120#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1122#[expect(missing_docs, reason = "self-describing variants")]
1123pub enum WasmCompositeInnerType {
1124    Array(WasmArrayType),
1125    Func(WasmFuncType),
1126    Struct(WasmStructType),
1127    Cont(WasmContType),
1128    Exn(WasmExnType),
1129}
1130
1131impl fmt::Display for WasmCompositeInnerType {
1132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1133        match self {
1134            Self::Array(ty) => fmt::Display::fmt(ty, f),
1135            Self::Func(ty) => fmt::Display::fmt(ty, f),
1136            Self::Struct(ty) => fmt::Display::fmt(ty, f),
1137            Self::Cont(ty) => fmt::Display::fmt(ty, f),
1138            Self::Exn(ty) => fmt::Display::fmt(ty, f),
1139        }
1140    }
1141}
1142
1143#[expect(missing_docs, reason = "self-describing functions")]
1144impl WasmCompositeInnerType {
1145    #[inline]
1146    pub fn is_array(&self) -> bool {
1147        matches!(self, Self::Array(_))
1148    }
1149
1150    #[inline]
1151    pub fn as_array(&self) -> Option<&WasmArrayType> {
1152        match self {
1153            Self::Array(f) => Some(f),
1154            _ => None,
1155        }
1156    }
1157
1158    #[inline]
1159    pub fn unwrap_array(&self) -> &WasmArrayType {
1160        self.as_array().unwrap()
1161    }
1162
1163    #[inline]
1164    pub fn is_func(&self) -> bool {
1165        matches!(self, Self::Func(_))
1166    }
1167
1168    #[inline]
1169    pub fn as_func(&self) -> Option<&WasmFuncType> {
1170        match self {
1171            Self::Func(f) => Some(f),
1172            _ => None,
1173        }
1174    }
1175
1176    #[inline]
1177    pub fn unwrap_func(&self) -> &WasmFuncType {
1178        self.as_func().unwrap()
1179    }
1180
1181    #[inline]
1182    pub fn is_struct(&self) -> bool {
1183        matches!(self, Self::Struct(_))
1184    }
1185
1186    #[inline]
1187    pub fn as_struct(&self) -> Option<&WasmStructType> {
1188        match self {
1189            Self::Struct(f) => Some(f),
1190            _ => None,
1191        }
1192    }
1193
1194    #[inline]
1195    pub fn unwrap_struct(&self) -> &WasmStructType {
1196        self.as_struct().unwrap()
1197    }
1198
1199    #[inline]
1200    pub fn is_cont(&self) -> bool {
1201        matches!(self, Self::Cont(_))
1202    }
1203
1204    #[inline]
1205    pub fn as_cont(&self) -> Option<&WasmContType> {
1206        match self {
1207            Self::Cont(f) => Some(f),
1208            _ => None,
1209        }
1210    }
1211
1212    #[inline]
1213    pub fn unwrap_cont(&self) -> &WasmContType {
1214        self.as_cont().unwrap()
1215    }
1216
1217    #[inline]
1218    pub fn is_exn(&self) -> bool {
1219        matches!(self, Self::Exn(_))
1220    }
1221
1222    #[inline]
1223    pub fn as_exn(&self) -> Option<&WasmExnType> {
1224        match self {
1225            Self::Exn(f) => Some(f),
1226            _ => None,
1227        }
1228    }
1229
1230    #[inline]
1231    pub fn unwrap_exn(&self) -> &WasmExnType {
1232        self.as_exn().unwrap()
1233    }
1234}
1235
1236impl TypeTrace for WasmCompositeType {
1237    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1238    where
1239        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1240    {
1241        match &self.inner {
1242            WasmCompositeInnerType::Array(a) => a.trace(func),
1243            WasmCompositeInnerType::Func(f) => f.trace(func),
1244            WasmCompositeInnerType::Struct(a) => a.trace(func),
1245            WasmCompositeInnerType::Cont(c) => c.trace(func),
1246            WasmCompositeInnerType::Exn(e) => e.trace(func),
1247        }
1248    }
1249
1250    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1251    where
1252        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1253    {
1254        match &mut self.inner {
1255            WasmCompositeInnerType::Array(a) => a.trace_mut(func),
1256            WasmCompositeInnerType::Func(f) => f.trace_mut(func),
1257            WasmCompositeInnerType::Struct(a) => a.trace_mut(func),
1258            WasmCompositeInnerType::Cont(c) => c.trace_mut(func),
1259            WasmCompositeInnerType::Exn(e) => e.trace_mut(func),
1260        }
1261    }
1262}
1263
1264#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1266pub struct WasmSubType {
1267    pub is_final: bool,
1270
1271    pub supertype: Option<EngineOrModuleTypeIndex>,
1273
1274    pub composite_type: WasmCompositeType,
1276}
1277
1278impl fmt::Display for WasmSubType {
1279    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1280        if self.is_final && self.supertype.is_none() {
1281            fmt::Display::fmt(&self.composite_type, f)
1282        } else {
1283            write!(f, "(sub")?;
1284            if self.is_final {
1285                write!(f, " final")?;
1286            }
1287            if let Some(sup) = self.supertype {
1288                write!(f, " {sup}")?;
1289            }
1290            write!(f, " {})", self.composite_type)
1291        }
1292    }
1293}
1294
1295#[expect(missing_docs, reason = "self-describing functions")]
1299impl WasmSubType {
1300    #[inline]
1301    pub fn is_func(&self) -> bool {
1302        self.composite_type.inner.is_func() && !self.composite_type.shared
1303    }
1304
1305    #[inline]
1306    pub fn as_func(&self) -> Option<&WasmFuncType> {
1307        if self.composite_type.shared {
1308            None
1309        } else {
1310            self.composite_type.inner.as_func()
1311        }
1312    }
1313
1314    #[inline]
1315    pub fn unwrap_func(&self) -> &WasmFuncType {
1316        assert!(!self.composite_type.shared);
1317        self.composite_type.inner.unwrap_func()
1318    }
1319
1320    #[inline]
1321    pub fn is_array(&self) -> bool {
1322        self.composite_type.inner.is_array() && !self.composite_type.shared
1323    }
1324
1325    #[inline]
1326    pub fn as_array(&self) -> Option<&WasmArrayType> {
1327        if self.composite_type.shared {
1328            None
1329        } else {
1330            self.composite_type.inner.as_array()
1331        }
1332    }
1333
1334    #[inline]
1335    pub fn unwrap_array(&self) -> &WasmArrayType {
1336        assert!(!self.composite_type.shared);
1337        self.composite_type.inner.unwrap_array()
1338    }
1339
1340    #[inline]
1341    pub fn is_struct(&self) -> bool {
1342        self.composite_type.inner.is_struct() && !self.composite_type.shared
1343    }
1344
1345    #[inline]
1346    pub fn as_struct(&self) -> Option<&WasmStructType> {
1347        if self.composite_type.shared {
1348            None
1349        } else {
1350            self.composite_type.inner.as_struct()
1351        }
1352    }
1353
1354    #[inline]
1355    pub fn unwrap_struct(&self) -> &WasmStructType {
1356        assert!(!self.composite_type.shared);
1357        self.composite_type.inner.unwrap_struct()
1358    }
1359
1360    #[inline]
1361    pub fn is_cont(&self) -> bool {
1362        self.composite_type.inner.is_cont() && !self.composite_type.shared
1363    }
1364
1365    #[inline]
1366    pub fn as_cont(&self) -> Option<&WasmContType> {
1367        if self.composite_type.shared {
1368            None
1369        } else {
1370            self.composite_type.inner.as_cont()
1371        }
1372    }
1373
1374    #[inline]
1375    pub fn unwrap_cont(&self) -> &WasmContType {
1376        assert!(!self.composite_type.shared);
1377        self.composite_type.inner.unwrap_cont()
1378    }
1379
1380    #[inline]
1381    pub fn is_exn(&self) -> bool {
1382        self.composite_type.inner.is_exn() && !self.composite_type.shared
1383    }
1384
1385    #[inline]
1386    pub fn as_exn(&self) -> Option<&WasmExnType> {
1387        if self.composite_type.shared {
1388            None
1389        } else {
1390            self.composite_type.inner.as_exn()
1391        }
1392    }
1393
1394    #[inline]
1395    pub fn unwrap_exn(&self) -> &WasmExnType {
1396        assert!(!self.composite_type.shared);
1397        self.composite_type.inner.unwrap_exn()
1398    }
1399}
1400
1401impl TypeTrace for WasmSubType {
1402    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1403    where
1404        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1405    {
1406        if let Some(sup) = self.supertype {
1407            func(sup)?;
1408        }
1409        self.composite_type.trace(func)
1410    }
1411
1412    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1413    where
1414        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1415    {
1416        if let Some(sup) = self.supertype.as_mut() {
1417            func(sup)?;
1418        }
1419        self.composite_type.trace_mut(func)
1420    }
1421}
1422
1423#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1434pub struct WasmRecGroup {
1435    pub types: Box<[WasmSubType]>,
1437}
1438
1439impl TypeTrace for WasmRecGroup {
1440    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1441    where
1442        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1443    {
1444        for ty in self.types.iter() {
1445            ty.trace(func)?;
1446        }
1447        Ok(())
1448    }
1449
1450    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1451    where
1452        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1453    {
1454        for ty in self.types.iter_mut() {
1455            ty.trace_mut(func)?;
1456        }
1457        Ok(())
1458    }
1459}
1460
1461#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1463pub struct FuncIndex(u32);
1464entity_impl!(FuncIndex);
1465
1466#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1468pub struct DefinedFuncIndex(u32);
1469entity_impl!(DefinedFuncIndex);
1470
1471#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1473pub struct DefinedTableIndex(u32);
1474entity_impl!(DefinedTableIndex);
1475
1476#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1478pub struct DefinedMemoryIndex(u32);
1479entity_impl!(DefinedMemoryIndex);
1480
1481#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1483pub struct OwnedMemoryIndex(u32);
1484entity_impl!(OwnedMemoryIndex);
1485
1486#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1488pub struct DefinedGlobalIndex(u32);
1489entity_impl!(DefinedGlobalIndex);
1490
1491#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1493pub struct TableIndex(u32);
1494entity_impl!(TableIndex);
1495
1496#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1498pub struct GlobalIndex(u32);
1499entity_impl!(GlobalIndex);
1500
1501#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1503pub struct MemoryIndex(u32);
1504entity_impl!(MemoryIndex);
1505
1506#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1509pub struct ModuleInternedRecGroupIndex(u32);
1510entity_impl!(ModuleInternedRecGroupIndex);
1511
1512#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1515pub struct EngineInternedRecGroupIndex(u32);
1516entity_impl!(EngineInternedRecGroupIndex);
1517
1518#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1520pub struct TypeIndex(u32);
1521entity_impl!(TypeIndex);
1522
1523#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1529pub struct RecGroupRelativeTypeIndex(u32);
1530entity_impl!(RecGroupRelativeTypeIndex);
1531
1532#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1540pub struct ModuleInternedTypeIndex(u32);
1541entity_impl!(ModuleInternedTypeIndex);
1542
1543#[repr(transparent)] #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1552pub struct VMSharedTypeIndex(u32);
1553entity_impl!(VMSharedTypeIndex);
1554
1555impl VMSharedTypeIndex {
1556    #[inline]
1558    pub fn new(value: u32) -> Self {
1559        assert_ne!(
1560            value,
1561            u32::MAX,
1562            "u32::MAX is reserved for the default value"
1563        );
1564        Self(value)
1565    }
1566
1567    #[inline]
1569    pub fn bits(&self) -> u32 {
1570        self.0
1571    }
1572}
1573
1574impl Default for VMSharedTypeIndex {
1575    #[inline]
1576    fn default() -> Self {
1577        Self(u32::MAX)
1578    }
1579}
1580
1581#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1583pub struct DataIndex(u32);
1584entity_impl!(DataIndex);
1585
1586#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1588pub struct ElemIndex(u32);
1589entity_impl!(ElemIndex);
1590
1591#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1593pub struct DefinedTagIndex(u32);
1594entity_impl!(DefinedTagIndex);
1595
1596#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1598pub struct TagIndex(u32);
1599entity_impl!(TagIndex);
1600
1601#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1606pub struct StaticModuleIndex(u32);
1607entity_impl!(StaticModuleIndex);
1608
1609#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1611pub enum EntityIndex {
1612    Function(FuncIndex),
1614    Table(TableIndex),
1616    Memory(MemoryIndex),
1618    Global(GlobalIndex),
1620    Tag(TagIndex),
1622}
1623
1624impl From<FuncIndex> for EntityIndex {
1625    fn from(idx: FuncIndex) -> EntityIndex {
1626        EntityIndex::Function(idx)
1627    }
1628}
1629
1630impl From<TableIndex> for EntityIndex {
1631    fn from(idx: TableIndex) -> EntityIndex {
1632        EntityIndex::Table(idx)
1633    }
1634}
1635
1636impl From<MemoryIndex> for EntityIndex {
1637    fn from(idx: MemoryIndex) -> EntityIndex {
1638        EntityIndex::Memory(idx)
1639    }
1640}
1641
1642impl From<GlobalIndex> for EntityIndex {
1643    fn from(idx: GlobalIndex) -> EntityIndex {
1644        EntityIndex::Global(idx)
1645    }
1646}
1647
1648impl From<TagIndex> for EntityIndex {
1649    fn from(idx: TagIndex) -> EntityIndex {
1650        EntityIndex::Tag(idx)
1651    }
1652}
1653
1654#[derive(Clone, Debug, Serialize, Deserialize)]
1657pub enum EntityType {
1658    Global(Global),
1660    Memory(Memory),
1662    Tag(Tag),
1664    Table(Table),
1666    Function(EngineOrModuleTypeIndex),
1669}
1670
1671impl TypeTrace for EntityType {
1672    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1673    where
1674        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1675    {
1676        match self {
1677            Self::Global(g) => g.trace(func),
1678            Self::Table(t) => t.trace(func),
1679            Self::Function(idx) => func(*idx),
1680            Self::Memory(_) => Ok(()),
1681            Self::Tag(t) => t.trace(func),
1682        }
1683    }
1684
1685    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1686    where
1687        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1688    {
1689        match self {
1690            Self::Global(g) => g.trace_mut(func),
1691            Self::Table(t) => t.trace_mut(func),
1692            Self::Function(idx) => func(idx),
1693            Self::Memory(_) => Ok(()),
1694            Self::Tag(t) => t.trace_mut(func),
1695        }
1696    }
1697}
1698
1699impl EntityType {
1700    pub fn unwrap_global(&self) -> &Global {
1702        match self {
1703            EntityType::Global(g) => g,
1704            _ => panic!("not a global"),
1705        }
1706    }
1707
1708    pub fn unwrap_memory(&self) -> &Memory {
1710        match self {
1711            EntityType::Memory(g) => g,
1712            _ => panic!("not a memory"),
1713        }
1714    }
1715
1716    pub fn unwrap_tag(&self) -> &Tag {
1718        match self {
1719            EntityType::Tag(g) => g,
1720            _ => panic!("not a tag"),
1721        }
1722    }
1723
1724    pub fn unwrap_table(&self) -> &Table {
1726        match self {
1727            EntityType::Table(g) => g,
1728            _ => panic!("not a table"),
1729        }
1730    }
1731
1732    pub fn unwrap_func(&self) -> EngineOrModuleTypeIndex {
1734        match self {
1735            EntityType::Function(g) => *g,
1736            _ => panic!("not a func"),
1737        }
1738    }
1739}
1740
1741#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1749pub struct Global {
1750    pub wasm_ty: crate::WasmValType,
1752    pub mutability: bool,
1754}
1755
1756impl TypeTrace for Global {
1757    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1758    where
1759        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1760    {
1761        let Global {
1762            wasm_ty,
1763            mutability: _,
1764        } = self;
1765        wasm_ty.trace(func)
1766    }
1767
1768    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1769    where
1770        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1771    {
1772        let Global {
1773            wasm_ty,
1774            mutability: _,
1775        } = self;
1776        wasm_ty.trace_mut(func)
1777    }
1778}
1779
1780#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1784pub struct ConstExpr {
1785    ops: SmallVec<[ConstOp; 2]>,
1786}
1787
1788impl ConstExpr {
1789    pub fn new(ops: impl IntoIterator<Item = ConstOp>) -> Self {
1795        let ops = ops.into_iter().collect::<SmallVec<[ConstOp; 2]>>();
1796        assert!(!ops.is_empty());
1797        ConstExpr { ops }
1798    }
1799
1800    pub fn from_wasmparser(
1805        env: &dyn TypeConvert,
1806        expr: wasmparser::ConstExpr<'_>,
1807    ) -> WasmResult<(Self, SmallVec<[FuncIndex; 1]>)> {
1808        let mut iter = expr
1809            .get_operators_reader()
1810            .into_iter_with_offsets()
1811            .peekable();
1812
1813        let mut ops = SmallVec::<[ConstOp; 2]>::new();
1814        let mut escaped = SmallVec::<[FuncIndex; 1]>::new();
1815        while let Some(res) = iter.next() {
1816            let (op, offset) = res?;
1817
1818            if matches!(op, wasmparser::Operator::End) && iter.peek().is_none() {
1822                break;
1823            }
1824
1825            if let wasmparser::Operator::RefFunc { function_index } = &op {
1828                escaped.push(FuncIndex::from_u32(*function_index));
1829            }
1830
1831            ops.push(ConstOp::from_wasmparser(env, op, offset)?);
1832        }
1833        Ok((Self { ops }, escaped))
1834    }
1835
1836    #[inline]
1838    pub fn ops(&self) -> &[ConstOp] {
1839        &self.ops
1840    }
1841
1842    pub fn provably_nonzero_i32(&self) -> bool {
1852        assert!(self.ops.len() > 0);
1853        if self.ops.len() > 1 {
1854            return false;
1857        }
1858        match self.ops[0] {
1860            ConstOp::I32Const(0) => false,
1862            ConstOp::I32Const(_) => true,
1865            _ => false,
1867        }
1868    }
1869}
1870
1871#[expect(missing_docs, reason = "self-describing variants")]
1873#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1874pub enum ConstOp {
1875    I32Const(i32),
1876    I64Const(i64),
1877    F32Const(u32),
1878    F64Const(u64),
1879    V128Const(u128),
1880    GlobalGet(GlobalIndex),
1881    RefI31,
1882    RefNull(WasmHeapTopType),
1883    RefFunc(FuncIndex),
1884    I32Add,
1885    I32Sub,
1886    I32Mul,
1887    I64Add,
1888    I64Sub,
1889    I64Mul,
1890    StructNew {
1891        struct_type_index: TypeIndex,
1892    },
1893    StructNewDefault {
1894        struct_type_index: TypeIndex,
1895    },
1896    ArrayNew {
1897        array_type_index: TypeIndex,
1898    },
1899    ArrayNewDefault {
1900        array_type_index: TypeIndex,
1901    },
1902    ArrayNewFixed {
1903        array_type_index: TypeIndex,
1904        array_size: u32,
1905    },
1906    ExternConvertAny,
1907    AnyConvertExtern,
1908}
1909
1910impl ConstOp {
1911    pub fn from_wasmparser(
1913        env: &dyn TypeConvert,
1914        op: wasmparser::Operator<'_>,
1915        offset: usize,
1916    ) -> WasmResult<Self> {
1917        use wasmparser::Operator as O;
1918        Ok(match op {
1919            O::I32Const { value } => Self::I32Const(value),
1920            O::I64Const { value } => Self::I64Const(value),
1921            O::F32Const { value } => Self::F32Const(value.bits()),
1922            O::F64Const { value } => Self::F64Const(value.bits()),
1923            O::V128Const { value } => Self::V128Const(u128::from_le_bytes(*value.bytes())),
1924            O::RefNull { hty } => Self::RefNull(env.convert_heap_type(hty)?.top()),
1925            O::RefFunc { function_index } => Self::RefFunc(FuncIndex::from_u32(function_index)),
1926            O::GlobalGet { global_index } => Self::GlobalGet(GlobalIndex::from_u32(global_index)),
1927            O::RefI31 => Self::RefI31,
1928            O::I32Add => Self::I32Add,
1929            O::I32Sub => Self::I32Sub,
1930            O::I32Mul => Self::I32Mul,
1931            O::I64Add => Self::I64Add,
1932            O::I64Sub => Self::I64Sub,
1933            O::I64Mul => Self::I64Mul,
1934            O::StructNew { struct_type_index } => Self::StructNew {
1935                struct_type_index: TypeIndex::from_u32(struct_type_index),
1936            },
1937            O::StructNewDefault { struct_type_index } => Self::StructNewDefault {
1938                struct_type_index: TypeIndex::from_u32(struct_type_index),
1939            },
1940            O::ArrayNew { array_type_index } => Self::ArrayNew {
1941                array_type_index: TypeIndex::from_u32(array_type_index),
1942            },
1943            O::ArrayNewDefault { array_type_index } => Self::ArrayNewDefault {
1944                array_type_index: TypeIndex::from_u32(array_type_index),
1945            },
1946            O::ArrayNewFixed {
1947                array_type_index,
1948                array_size,
1949            } => Self::ArrayNewFixed {
1950                array_type_index: TypeIndex::from_u32(array_type_index),
1951                array_size,
1952            },
1953            O::ExternConvertAny => Self::ExternConvertAny,
1954            O::AnyConvertExtern => Self::AnyConvertExtern,
1955            op => {
1956                return Err(wasm_unsupported!(
1957                    "unsupported opcode in const expression at offset {offset:#x}: {op:?}",
1958                ));
1959            }
1960        })
1961    }
1962}
1963
1964#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1966#[expect(missing_docs, reason = "self-describing variants")]
1967pub enum IndexType {
1968    I32,
1969    I64,
1970}
1971
1972#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1974#[expect(missing_docs, reason = "self-describing fields")]
1975pub struct Limits {
1976    pub min: u64,
1977    pub max: Option<u64>,
1978}
1979
1980#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1982pub struct Table {
1983    pub idx_type: IndexType,
1985    pub limits: Limits,
1988    pub ref_type: WasmRefType,
1990}
1991
1992impl TypeTrace for Table {
1993    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1994    where
1995        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1996    {
1997        let Table {
1998            ref_type: wasm_ty,
1999            idx_type: _,
2000            limits: _,
2001        } = self;
2002        wasm_ty.trace(func)
2003    }
2004
2005    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
2006    where
2007        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
2008    {
2009        let Table {
2010            ref_type: wasm_ty,
2011            idx_type: _,
2012            limits: _,
2013        } = self;
2014        wasm_ty.trace_mut(func)
2015    }
2016}
2017
2018#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2020pub struct Memory {
2021    pub idx_type: IndexType,
2023    pub limits: Limits,
2026    pub shared: bool,
2028    pub page_size_log2: u8,
2033}
2034
2035pub const WASM32_MAX_SIZE: u64 = 1 << 32;
2037
2038impl Memory {
2039    pub const DEFAULT_PAGE_SIZE: u32 = 0x10000;
2041
2042    pub const DEFAULT_PAGE_SIZE_LOG2: u8 = {
2044        let log2 = 16;
2045        assert!(1 << log2 == Memory::DEFAULT_PAGE_SIZE);
2046        log2
2047    };
2048
2049    pub fn minimum_byte_size(&self) -> Result<u64, SizeOverflow> {
2057        self.limits
2058            .min
2059            .checked_mul(self.page_size())
2060            .ok_or(SizeOverflow)
2061    }
2062
2063    pub fn maximum_byte_size(&self) -> Result<u64, SizeOverflow> {
2078        match self.limits.max {
2079            Some(max) => max.checked_mul(self.page_size()).ok_or(SizeOverflow),
2080            None => {
2081                let min = self.minimum_byte_size()?;
2082                Ok(min.max(self.max_size_based_on_index_type()))
2083            }
2084        }
2085    }
2086
2087    pub fn page_size(&self) -> u64 {
2089        debug_assert!(
2090            self.page_size_log2 == 16 || self.page_size_log2 == 0,
2091            "invalid page_size_log2: {}; must be 16 or 0",
2092            self.page_size_log2
2093        );
2094        1 << self.page_size_log2
2095    }
2096
2097    pub fn max_size_based_on_index_type(&self) -> u64 {
2102        match self.idx_type {
2103            IndexType::I64 =>
2104            {
2112                0_u64.wrapping_sub(self.page_size())
2113            }
2114            IndexType::I32 => WASM32_MAX_SIZE,
2115        }
2116    }
2117
2118    pub fn can_use_virtual_memory(&self, tunables: &Tunables, host_page_size_log2: u8) -> bool {
2130        tunables.signals_based_traps && self.page_size_log2 >= host_page_size_log2
2131    }
2132
2133    pub fn can_elide_bounds_check(&self, tunables: &Tunables, host_page_size_log2: u8) -> bool {
2153        self.can_use_virtual_memory(tunables, host_page_size_log2)
2154            && self.idx_type == IndexType::I32
2155            && tunables.memory_reservation >= (1 << 32)
2156    }
2157
2158    pub fn static_heap_size(&self) -> Option<u64> {
2162        let min = self.minimum_byte_size().ok()?;
2163        let max = self.maximum_byte_size().ok()?;
2164        if min == max { Some(min) } else { None }
2165    }
2166
2167    pub fn memory_may_move(&self, tunables: &Tunables) -> bool {
2174        if self.shared {
2178            return false;
2179        }
2180
2181        if !tunables.memory_may_move {
2184            return false;
2185        }
2186
2187        if self.limits.max.is_some_and(|max| self.limits.min == max) {
2190            return false;
2191        }
2192
2193        let max = self.maximum_byte_size().unwrap_or(u64::MAX);
2196        max > tunables.memory_reservation
2197    }
2198}
2199
2200#[derive(Copy, Clone, Debug)]
2201#[expect(missing_docs, reason = "self-describing error struct")]
2202pub struct SizeOverflow;
2203
2204impl fmt::Display for SizeOverflow {
2205    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2206        f.write_str("size overflow calculating memory size")
2207    }
2208}
2209
2210impl core::error::Error for SizeOverflow {}
2211
2212impl From<wasmparser::MemoryType> for Memory {
2213    fn from(ty: wasmparser::MemoryType) -> Memory {
2214        let idx_type = match ty.memory64 {
2215            false => IndexType::I32,
2216            true => IndexType::I64,
2217        };
2218        let limits = Limits {
2219            min: ty.initial,
2220            max: ty.maximum,
2221        };
2222        let page_size_log2 = u8::try_from(ty.page_size_log2.unwrap_or(16)).unwrap();
2223        debug_assert!(
2224            page_size_log2 == 16 || page_size_log2 == 0,
2225            "invalid page_size_log2: {page_size_log2}; must be 16 or 0"
2226        );
2227        Memory {
2228            idx_type,
2229            limits,
2230            shared: ty.shared,
2231            page_size_log2,
2232        }
2233    }
2234}
2235
2236#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2238pub struct Tag {
2239    pub signature: EngineOrModuleTypeIndex,
2241    pub exception: EngineOrModuleTypeIndex,
2243}
2244
2245impl TypeTrace for Tag {
2246    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
2247    where
2248        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
2249    {
2250        func(self.signature)?;
2251        func(self.exception)?;
2252        Ok(())
2253    }
2254
2255    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
2256    where
2257        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
2258    {
2259        func(&mut self.signature)?;
2260        func(&mut self.exception)?;
2261        Ok(())
2262    }
2263}
2264
2265#[expect(missing_docs, reason = "self-describing functions")]
2267pub trait TypeConvert {
2268    fn convert_global_type(&self, ty: &wasmparser::GlobalType) -> WasmResult<Global> {
2270        Ok(Global {
2271            wasm_ty: self.convert_valtype(ty.content_type)?,
2272            mutability: ty.mutable,
2273        })
2274    }
2275
2276    fn convert_table_type(&self, ty: &wasmparser::TableType) -> WasmResult<Table> {
2278        let idx_type = match ty.table64 {
2279            false => IndexType::I32,
2280            true => IndexType::I64,
2281        };
2282        let limits = Limits {
2283            min: ty.initial,
2284            max: ty.maximum,
2285        };
2286        Ok(Table {
2287            idx_type,
2288            limits,
2289            ref_type: self.convert_ref_type(ty.element_type)?,
2290        })
2291    }
2292
2293    fn convert_sub_type(&self, ty: &wasmparser::SubType) -> WasmResult<WasmSubType> {
2294        Ok(WasmSubType {
2295            is_final: ty.is_final,
2296            supertype: ty.supertype_idx.map(|i| self.lookup_type_index(i.unpack())),
2297            composite_type: self.convert_composite_type(&ty.composite_type)?,
2298        })
2299    }
2300
2301    fn convert_composite_type(
2302        &self,
2303        ty: &wasmparser::CompositeType,
2304    ) -> WasmResult<WasmCompositeType> {
2305        let inner = match &ty.inner {
2306            wasmparser::CompositeInnerType::Func(f) => {
2307                WasmCompositeInnerType::Func(self.convert_func_type(f)?)
2308            }
2309            wasmparser::CompositeInnerType::Array(a) => {
2310                WasmCompositeInnerType::Array(self.convert_array_type(a)?)
2311            }
2312            wasmparser::CompositeInnerType::Struct(s) => {
2313                WasmCompositeInnerType::Struct(self.convert_struct_type(s)?)
2314            }
2315            wasmparser::CompositeInnerType::Cont(c) => {
2316                WasmCompositeInnerType::Cont(self.convert_cont_type(c))
2317            }
2318        };
2319        Ok(WasmCompositeType {
2320            inner,
2321            shared: ty.shared,
2322        })
2323    }
2324
2325    fn convert_cont_type(&self, ty: &wasmparser::ContType) -> WasmContType {
2327        if let WasmHeapType::ConcreteFunc(sigidx) = self.lookup_heap_type(ty.0.unpack()) {
2328            WasmContType::new(sigidx)
2329        } else {
2330            panic!("Failed to extract signature index for continuation type.")
2331        }
2332    }
2333
2334    fn convert_struct_type(&self, ty: &wasmparser::StructType) -> WasmResult<WasmStructType> {
2335        Ok(WasmStructType {
2336            fields: ty
2337                .fields
2338                .iter()
2339                .map(|f| self.convert_field_type(f))
2340                .collect::<WasmResult<_>>()?,
2341        })
2342    }
2343
2344    fn convert_array_type(&self, ty: &wasmparser::ArrayType) -> WasmResult<WasmArrayType> {
2345        Ok(WasmArrayType(self.convert_field_type(&ty.0)?))
2346    }
2347
2348    fn convert_field_type(&self, ty: &wasmparser::FieldType) -> WasmResult<WasmFieldType> {
2349        Ok(WasmFieldType {
2350            element_type: self.convert_storage_type(&ty.element_type)?,
2351            mutable: ty.mutable,
2352        })
2353    }
2354
2355    fn convert_storage_type(&self, ty: &wasmparser::StorageType) -> WasmResult<WasmStorageType> {
2356        Ok(match ty {
2357            wasmparser::StorageType::I8 => WasmStorageType::I8,
2358            wasmparser::StorageType::I16 => WasmStorageType::I16,
2359            wasmparser::StorageType::Val(v) => WasmStorageType::Val(self.convert_valtype(*v)?),
2360        })
2361    }
2362
2363    fn convert_func_type(&self, ty: &wasmparser::FuncType) -> WasmResult<WasmFuncType> {
2365        let params = ty
2366            .params()
2367            .iter()
2368            .map(|t| self.convert_valtype(*t))
2369            .collect::<WasmResult<_>>()?;
2370        let results = ty
2371            .results()
2372            .iter()
2373            .map(|t| self.convert_valtype(*t))
2374            .collect::<WasmResult<_>>()?;
2375        Ok(WasmFuncType::new(params, results))
2376    }
2377
2378    fn convert_valtype(&self, ty: wasmparser::ValType) -> WasmResult<WasmValType> {
2380        Ok(match ty {
2381            wasmparser::ValType::I32 => WasmValType::I32,
2382            wasmparser::ValType::I64 => WasmValType::I64,
2383            wasmparser::ValType::F32 => WasmValType::F32,
2384            wasmparser::ValType::F64 => WasmValType::F64,
2385            wasmparser::ValType::V128 => WasmValType::V128,
2386            wasmparser::ValType::Ref(t) => WasmValType::Ref(self.convert_ref_type(t)?),
2387        })
2388    }
2389
2390    fn convert_ref_type(&self, ty: wasmparser::RefType) -> WasmResult<WasmRefType> {
2392        Ok(WasmRefType {
2393            nullable: ty.is_nullable(),
2394            heap_type: self.convert_heap_type(ty.heap_type())?,
2395        })
2396    }
2397
2398    fn convert_heap_type(&self, ty: wasmparser::HeapType) -> WasmResult<WasmHeapType> {
2400        Ok(match ty {
2401            wasmparser::HeapType::Concrete(i) => self.lookup_heap_type(i),
2402            wasmparser::HeapType::Abstract { ty, shared: false } => match ty {
2403                wasmparser::AbstractHeapType::Extern => WasmHeapType::Extern,
2404                wasmparser::AbstractHeapType::NoExtern => WasmHeapType::NoExtern,
2405                wasmparser::AbstractHeapType::Func => WasmHeapType::Func,
2406                wasmparser::AbstractHeapType::NoFunc => WasmHeapType::NoFunc,
2407                wasmparser::AbstractHeapType::Any => WasmHeapType::Any,
2408                wasmparser::AbstractHeapType::Eq => WasmHeapType::Eq,
2409                wasmparser::AbstractHeapType::I31 => WasmHeapType::I31,
2410                wasmparser::AbstractHeapType::Array => WasmHeapType::Array,
2411                wasmparser::AbstractHeapType::Struct => WasmHeapType::Struct,
2412                wasmparser::AbstractHeapType::None => WasmHeapType::None,
2413                wasmparser::AbstractHeapType::Cont => WasmHeapType::Cont,
2414                wasmparser::AbstractHeapType::NoCont => WasmHeapType::NoCont,
2415                wasmparser::AbstractHeapType::Exn => WasmHeapType::Exn,
2416                wasmparser::AbstractHeapType::NoExn => WasmHeapType::NoExn,
2417            },
2418            _ => return Err(wasm_unsupported!("unsupported heap type {ty:?}")),
2419        })
2420    }
2421
2422    fn lookup_heap_type(&self, index: wasmparser::UnpackedIndex) -> WasmHeapType;
2425
2426    fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex;
2429}