wasmtime_environ/
types.rs

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
9/// A trait for things that can trace all type-to-type edges, aka all type
10/// indices within this thing.
11pub trait TypeTrace {
12    /// Visit each edge.
13    ///
14    /// The function can break out of tracing by returning `Err(E)`.
15    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
16    where
17        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>;
18
19    /// Visit each edge, mutably.
20    ///
21    /// Allows updating edges.
22    ///
23    /// The function can break out of tracing by returning `Err(E)`.
24    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
25    where
26        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>;
27
28    /// Trace all `VMSharedTypeIndex` edges, ignoring other edges.
29    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    /// Canonicalize `self` by rewriting all type references inside `self` from
40    /// module-level interned type indices to engine-level interned type
41    /// indices.
42    ///
43    /// This produces types that are suitable for usage by the runtime (only
44    /// contains `VMSharedTypeIndex` type references).
45    ///
46    /// This does not produce types that are suitable for hash consing types
47    /// (must have recgroup-relative indices for type indices referencing other
48    /// types in the same recgroup).
49    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    /// Is this type canonicalized for runtime usage?
68    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    /// Canonicalize `self` by rewriting all type references inside `self` from
77    /// module-level interned type indices to either engine-level interned type
78    /// indices or recgroup-relative indices.
79    ///
80    /// This produces types that are suitable for hash consing and deduplicating
81    /// recgroups (types may have recgroup-relative indices for references to
82    /// other types within the same recgroup).
83    ///
84    /// This does *not* produce types that are suitable for usage by the runtime
85    /// (only contain `VMSharedTypeIndex` type references).
86    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                    // Any module index within the recursion group gets
98                    // translated into a recgroup-relative index.
99                    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                    // Cross-group indices are translated directly into
105                    // `VMSharedTypeIndex`es.
106                    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    /// Is this type canonicalized for hash consing?
119    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/// WebAssembly value type -- equivalent of `wasmparser::ValType`.
129#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
130pub enum WasmValType {
131    /// I32 type
132    I32,
133    /// I64 type
134    I64,
135    /// F32 type
136    F32,
137    /// F64 type
138    F64,
139    /// V128 type
140    V128,
141    /// Reference type
142    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    /// Is this a type that is represented as a `VMGcRef`?
190    #[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    /// Is this a type that is represented as a `VMGcRef` and is additionally
199    /// not an `i31`?
200    ///
201    /// That is, is this a type that actually refers to an object allocated in a
202    /// GC heap?
203    #[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    /// Attempt to build a `WasmValType` with the passed number of bits.
226    ///
227    /// Panics if the number of bits doesn't map to a WASM int type.
228    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    /// Returns the contained reference type.
237    ///
238    /// Panics if the value type is not a vmgcref
239    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/// WebAssembly reference type -- equivalent of `wasmparser`'s RefType
248#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
249pub struct WasmRefType {
250    /// Whether or not this reference is nullable.
251    pub nullable: bool,
252    /// The heap type that this reference contains.
253    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    /// Shorthand for `externref`
274    pub const EXTERNREF: WasmRefType = WasmRefType {
275        nullable: true,
276        heap_type: WasmHeapType::Extern,
277    };
278    /// Shorthand for `funcref`
279    pub const FUNCREF: WasmRefType = WasmRefType {
280        nullable: true,
281        heap_type: WasmHeapType::Func,
282    };
283
284    /// Is this a type that is represented as a `VMGcRef`?
285    #[inline]
286    pub fn is_vmgcref_type(&self) -> bool {
287        self.heap_type.is_vmgcref_type()
288    }
289
290    /// Is this a type that is represented as a `VMGcRef` and is additionally
291    /// not an `i31`?
292    ///
293    /// That is, is this a type that actually refers to an object allocated in a
294    /// GC heap?
295    #[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/// An interned type index, either at the module or engine level.
318///
319/// Roughly equivalent to `wasmparser::UnpackedIndex`, although doesn't have to
320/// concern itself with recursion-group-local indices.
321#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
322pub enum EngineOrModuleTypeIndex {
323    /// An index within an engine, canonicalized among all modules that can
324    /// interact with each other.
325    Engine(VMSharedTypeIndex),
326
327    /// An index within the current Wasm module, canonicalized within just this
328    /// current module.
329    Module(ModuleInternedTypeIndex),
330
331    /// An index within the containing type's rec group. This is only used when
332    /// hashing and canonicalizing rec groups, and should never appear outside
333    /// of the engine's type registry.
334    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    /// Is this an engine-level type index?
370    pub fn is_engine_type_index(self) -> bool {
371        matches!(self, Self::Engine(_))
372    }
373
374    /// Get the underlying engine-level type index, if any.
375    pub fn as_engine_type_index(self) -> Option<VMSharedTypeIndex> {
376        match self {
377            Self::Engine(e) => Some(e),
378            Self::RecGroup(_) | Self::Module(_) => None,
379        }
380    }
381
382    /// Get the underlying engine-level type index, or panic.
383    #[track_caller]
384    pub fn unwrap_engine_type_index(self) -> VMSharedTypeIndex {
385        match self.as_engine_type_index() {
386            Some(x) => x,
387            None => panic!("`unwrap_engine_type_index` on {self:?}"),
388        }
389    }
390
391    /// Is this an module-level type index?
392    pub fn is_module_type_index(self) -> bool {
393        matches!(self, Self::Module(_))
394    }
395
396    /// Get the underlying module-level type index, if any.
397    pub fn as_module_type_index(self) -> Option<ModuleInternedTypeIndex> {
398        match self {
399            Self::Module(e) => Some(e),
400            Self::RecGroup(_) | Self::Engine(_) => None,
401        }
402    }
403
404    /// Get the underlying module-level type index, or panic.
405    #[track_caller]
406    pub fn unwrap_module_type_index(self) -> ModuleInternedTypeIndex {
407        match self.as_module_type_index() {
408            Some(x) => x,
409            None => panic!("`unwrap_module_type_index` on {self:?}"),
410        }
411    }
412
413    /// Is this an recgroup-level type index?
414    pub fn is_rec_group_type_index(self) -> bool {
415        matches!(self, Self::RecGroup(_))
416    }
417
418    /// Get the underlying recgroup-level type index, if any.
419    pub fn as_rec_group_type_index(self) -> Option<RecGroupRelativeTypeIndex> {
420        match self {
421            Self::RecGroup(r) => Some(r),
422            Self::Module(_) | Self::Engine(_) => None,
423        }
424    }
425
426    /// Get the underlying module-level type index, or panic.
427    #[track_caller]
428    pub fn unwrap_rec_group_type_index(self) -> RecGroupRelativeTypeIndex {
429        match self.as_rec_group_type_index() {
430            Some(x) => x,
431            None => panic!("`unwrap_rec_group_type_index` on {self:?}"),
432        }
433    }
434}
435
436/// WebAssembly heap type -- equivalent of `wasmparser`'s HeapType
437#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
438#[expect(missing_docs, reason = "self-describing variants")]
439pub enum WasmHeapType {
440    // External types.
441    Extern,
442    NoExtern,
443
444    // Function types.
445    Func,
446    ConcreteFunc(EngineOrModuleTypeIndex),
447    NoFunc,
448
449    // Continuation types.
450    Cont,
451    ConcreteCont(EngineOrModuleTypeIndex),
452    NoCont,
453
454    // Internal types.
455    Any,
456    Eq,
457    I31,
458    Array,
459    ConcreteArray(EngineOrModuleTypeIndex),
460    Struct,
461    ConcreteStruct(EngineOrModuleTypeIndex),
462    None,
463}
464
465impl From<WasmHeapTopType> for WasmHeapType {
466    #[inline]
467    fn from(value: WasmHeapTopType) -> Self {
468        match value {
469            WasmHeapTopType::Extern => Self::Extern,
470            WasmHeapTopType::Any => Self::Any,
471            WasmHeapTopType::Func => Self::Func,
472            WasmHeapTopType::Cont => Self::Cont,
473        }
474    }
475}
476
477impl From<WasmHeapBottomType> for WasmHeapType {
478    #[inline]
479    fn from(value: WasmHeapBottomType) -> Self {
480        match value {
481            WasmHeapBottomType::NoExtern => Self::NoExtern,
482            WasmHeapBottomType::None => Self::None,
483            WasmHeapBottomType::NoFunc => Self::NoFunc,
484            WasmHeapBottomType::NoCont => Self::NoCont,
485        }
486    }
487}
488
489impl fmt::Display for WasmHeapType {
490    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
491        match self {
492            Self::Extern => write!(f, "extern"),
493            Self::NoExtern => write!(f, "noextern"),
494            Self::Func => write!(f, "func"),
495            Self::ConcreteFunc(i) => write!(f, "func {i}"),
496            Self::NoFunc => write!(f, "nofunc"),
497            Self::Cont => write!(f, "cont"),
498            Self::ConcreteCont(i) => write!(f, "cont {i}"),
499            Self::NoCont => write!(f, "nocont"),
500            Self::Any => write!(f, "any"),
501            Self::Eq => write!(f, "eq"),
502            Self::I31 => write!(f, "i31"),
503            Self::Array => write!(f, "array"),
504            Self::ConcreteArray(i) => write!(f, "array {i}"),
505            Self::Struct => write!(f, "struct"),
506            Self::ConcreteStruct(i) => write!(f, "struct {i}"),
507            Self::None => write!(f, "none"),
508        }
509    }
510}
511
512impl TypeTrace for WasmHeapType {
513    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
514    where
515        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
516    {
517        match *self {
518            Self::ConcreteArray(i) => func(i),
519            Self::ConcreteFunc(i) => func(i),
520            Self::ConcreteStruct(i) => func(i),
521            Self::ConcreteCont(i) => func(i),
522            _ => Ok(()),
523        }
524    }
525
526    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
527    where
528        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
529    {
530        match self {
531            Self::ConcreteArray(i) => func(i),
532            Self::ConcreteFunc(i) => func(i),
533            Self::ConcreteStruct(i) => func(i),
534            Self::ConcreteCont(i) => func(i),
535            _ => Ok(()),
536        }
537    }
538}
539
540impl WasmHeapType {
541    /// Is this a type that is represented as a `VMGcRef`?
542    #[inline]
543    pub fn is_vmgcref_type(&self) -> bool {
544        match self.top() {
545            // All `t <: (ref null any)` and `t <: (ref null extern)` are
546            // represented as `VMGcRef`s.
547            WasmHeapTopType::Any | WasmHeapTopType::Extern => true,
548
549            // All `t <: (ref null func)` are not.
550            WasmHeapTopType::Func => false,
551            WasmHeapTopType::Cont => false,
552        }
553    }
554
555    /// Is this a type that is represented as a `VMGcRef` and is additionally
556    /// not an `i31`?
557    ///
558    /// That is, is this a type that actually refers to an object allocated in a
559    /// GC heap?
560    #[inline]
561    pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
562        self.is_vmgcref_type() && *self != Self::I31
563    }
564
565    /// Is this heap type the top of its type hierarchy?
566    #[inline]
567    pub fn is_top(&self) -> bool {
568        *self == Self::from(self.top())
569    }
570
571    /// Get this type's top type.
572    #[inline]
573    pub fn top(&self) -> WasmHeapTopType {
574        match self {
575            WasmHeapType::Extern | WasmHeapType::NoExtern => WasmHeapTopType::Extern,
576
577            WasmHeapType::Func | WasmHeapType::ConcreteFunc(_) | WasmHeapType::NoFunc => {
578                WasmHeapTopType::Func
579            }
580
581            WasmHeapType::Cont | WasmHeapType::ConcreteCont(_) | WasmHeapType::NoCont => {
582                WasmHeapTopType::Cont
583            }
584
585            WasmHeapType::Any
586            | WasmHeapType::Eq
587            | WasmHeapType::I31
588            | WasmHeapType::Array
589            | WasmHeapType::ConcreteArray(_)
590            | WasmHeapType::Struct
591            | WasmHeapType::ConcreteStruct(_)
592            | WasmHeapType::None => WasmHeapTopType::Any,
593        }
594    }
595
596    /// Is this heap type the bottom of its type hierarchy?
597    #[inline]
598    pub fn is_bottom(&self) -> bool {
599        *self == Self::from(self.bottom())
600    }
601
602    /// Get this type's bottom type.
603    #[inline]
604    pub fn bottom(&self) -> WasmHeapBottomType {
605        match self {
606            WasmHeapType::Extern | WasmHeapType::NoExtern => WasmHeapBottomType::NoExtern,
607
608            WasmHeapType::Func | WasmHeapType::ConcreteFunc(_) | WasmHeapType::NoFunc => {
609                WasmHeapBottomType::NoFunc
610            }
611
612            WasmHeapType::Cont | WasmHeapType::ConcreteCont(_) | WasmHeapType::NoCont => {
613                WasmHeapBottomType::NoCont
614            }
615
616            WasmHeapType::Any
617            | WasmHeapType::Eq
618            | WasmHeapType::I31
619            | WasmHeapType::Array
620            | WasmHeapType::ConcreteArray(_)
621            | WasmHeapType::Struct
622            | WasmHeapType::ConcreteStruct(_)
623            | WasmHeapType::None => WasmHeapBottomType::None,
624        }
625    }
626}
627
628/// A top heap type.
629#[derive(Debug, Clone, Copy, Eq, PartialEq)]
630pub enum WasmHeapTopType {
631    /// The common supertype of all external references.
632    Extern,
633    /// The common supertype of all internal references.
634    Any,
635    /// The common supertype of all function references.
636    Func,
637    /// The common supertype of all continuation references.
638    Cont,
639}
640
641/// A bottom heap type.
642#[derive(Debug, Clone, Copy, Eq, PartialEq)]
643pub enum WasmHeapBottomType {
644    /// The common subtype of all external references.
645    NoExtern,
646    /// The common subtype of all internal references.
647    None,
648    /// The common subtype of all function references.
649    NoFunc,
650    /// The common subtype of all continuation references.
651    NoCont,
652}
653
654/// WebAssembly function type -- equivalent of `wasmparser`'s FuncType.
655#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
656pub struct WasmFuncType {
657    params: Box<[WasmValType]>,
658    non_i31_gc_ref_params_count: usize,
659    returns: Box<[WasmValType]>,
660    non_i31_gc_ref_returns_count: usize,
661}
662
663impl fmt::Display for WasmFuncType {
664    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
665        write!(f, "(func")?;
666        if !self.params.is_empty() {
667            write!(f, " (param")?;
668            for p in self.params.iter() {
669                write!(f, " {p}")?;
670            }
671            write!(f, ")")?;
672        }
673        if !self.returns.is_empty() {
674            write!(f, " (result")?;
675            for r in self.returns.iter() {
676                write!(f, " {r}")?;
677            }
678            write!(f, ")")?;
679        }
680        write!(f, ")")
681    }
682}
683
684impl TypeTrace for WasmFuncType {
685    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
686    where
687        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
688    {
689        for p in self.params.iter() {
690            p.trace(func)?;
691        }
692        for r in self.returns.iter() {
693            r.trace(func)?;
694        }
695        Ok(())
696    }
697
698    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
699    where
700        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
701    {
702        for p in self.params.iter_mut() {
703            p.trace_mut(func)?;
704        }
705        for r in self.returns.iter_mut() {
706            r.trace_mut(func)?;
707        }
708        Ok(())
709    }
710}
711
712impl WasmFuncType {
713    /// Creates a new function type from the provided `params` and `returns`.
714    #[inline]
715    pub fn new(params: Box<[WasmValType]>, returns: Box<[WasmValType]>) -> Self {
716        let non_i31_gc_ref_params_count = params
717            .iter()
718            .filter(|p| p.is_vmgcref_type_and_not_i31())
719            .count();
720        let non_i31_gc_ref_returns_count = returns
721            .iter()
722            .filter(|r| r.is_vmgcref_type_and_not_i31())
723            .count();
724        WasmFuncType {
725            params,
726            non_i31_gc_ref_params_count,
727            returns,
728            non_i31_gc_ref_returns_count,
729        }
730    }
731
732    /// Function params types.
733    #[inline]
734    pub fn params(&self) -> &[WasmValType] {
735        &self.params
736    }
737
738    /// How many `externref`s are in this function's params?
739    #[inline]
740    pub fn non_i31_gc_ref_params_count(&self) -> usize {
741        self.non_i31_gc_ref_params_count
742    }
743
744    /// Returns params types.
745    #[inline]
746    pub fn returns(&self) -> &[WasmValType] {
747        &self.returns
748    }
749
750    /// How many `externref`s are in this function's returns?
751    #[inline]
752    pub fn non_i31_gc_ref_returns_count(&self) -> usize {
753        self.non_i31_gc_ref_returns_count
754    }
755
756    /// Is this function type compatible with trampoline usage in Wasmtime?
757    pub fn is_trampoline_type(&self) -> bool {
758        self.params().iter().all(|p| *p == p.trampoline_type())
759            && self.returns().iter().all(|r| *r == r.trampoline_type())
760    }
761
762    /// Get the version of this function type that is suitable for usage as a
763    /// trampoline in Wasmtime.
764    ///
765    /// If this function is suitable for trampoline usage as-is, then a borrowed
766    /// `Cow` is returned. If it must be tweaked for trampoline usage, then an
767    /// owned `Cow` is returned.
768    ///
769    /// ## What is a trampoline type?
770    ///
771    /// All reference types in parameters and results are mapped to their
772    /// nullable top type, e.g. `(ref $my_struct_type)` becomes `(ref null
773    /// any)`.
774    ///
775    /// This allows us to share trampolines between functions whose signatures
776    /// both map to the same trampoline type. It also allows the host to satisfy
777    /// a Wasm module's function import of type `S` with a function of type `T`
778    /// where `T <: S`, even when the Wasm module never defines the type `T`
779    /// (and might never even be able to!)
780    ///
781    /// The flip side is that this adds a constraint to our trampolines: they
782    /// can only pass references around (e.g. move a reference from one calling
783    /// convention's location to another's) and may not actually inspect the
784    /// references themselves (unless the trampolines start doing explicit,
785    /// fallible downcasts, but if we ever need that, then we might want to
786    /// redesign this stuff).
787    pub fn trampoline_type(&self) -> Cow<'_, Self> {
788        if self.is_trampoline_type() {
789            return Cow::Borrowed(self);
790        }
791
792        Cow::Owned(Self::new(
793            self.params().iter().map(|p| p.trampoline_type()).collect(),
794            self.returns().iter().map(|r| r.trampoline_type()).collect(),
795        ))
796    }
797}
798
799/// WebAssembly continuation type -- equivalent of `wasmparser`'s ContType.
800#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
801pub struct WasmContType(EngineOrModuleTypeIndex);
802
803impl fmt::Display for WasmContType {
804    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
805        write!(f, "(cont {})", self.0)
806    }
807}
808
809impl WasmContType {
810    /// Constructs a new continuation type.
811    pub fn new(idx: EngineOrModuleTypeIndex) -> Self {
812        WasmContType(idx)
813    }
814
815    /// Returns the (module interned) index to the underlying function type.
816    pub fn unwrap_module_type_index(self) -> ModuleInternedTypeIndex {
817        match self.0 {
818            EngineOrModuleTypeIndex::Engine(_) => panic!("not module interned"),
819            EngineOrModuleTypeIndex::Module(idx) => idx,
820            EngineOrModuleTypeIndex::RecGroup(_) => todo!(),
821        }
822    }
823}
824
825impl TypeTrace for WasmContType {
826    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
827    where
828        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
829    {
830        func(self.0)
831    }
832
833    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
834    where
835        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
836    {
837        func(&mut self.0)
838    }
839}
840
841/// Represents storage types introduced in the GC spec for array and struct fields.
842#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
843pub enum WasmStorageType {
844    /// The storage type is i8.
845    I8,
846    /// The storage type is i16.
847    I16,
848    /// The storage type is a value type.
849    Val(WasmValType),
850}
851
852impl fmt::Display for WasmStorageType {
853    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
854        match self {
855            WasmStorageType::I8 => write!(f, "i8"),
856            WasmStorageType::I16 => write!(f, "i16"),
857            WasmStorageType::Val(v) => fmt::Display::fmt(v, f),
858        }
859    }
860}
861
862impl TypeTrace for WasmStorageType {
863    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
864    where
865        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
866    {
867        match self {
868            WasmStorageType::I8 | WasmStorageType::I16 => Ok(()),
869            WasmStorageType::Val(v) => v.trace(func),
870        }
871    }
872
873    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
874    where
875        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
876    {
877        match self {
878            WasmStorageType::I8 | WasmStorageType::I16 => Ok(()),
879            WasmStorageType::Val(v) => v.trace_mut(func),
880        }
881    }
882}
883
884impl WasmStorageType {
885    /// Is this a type that is represented as a `VMGcRef` and is additionally
886    /// not an `i31`?
887    ///
888    /// That is, is this a type that actually refers to an object allocated in a
889    /// GC heap?
890    pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
891        match self {
892            WasmStorageType::I8 | WasmStorageType::I16 => false,
893            WasmStorageType::Val(v) => v.is_vmgcref_type_and_not_i31(),
894        }
895    }
896}
897
898/// The type of a struct field or array element.
899#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
900pub struct WasmFieldType {
901    /// The field's element type.
902    pub element_type: WasmStorageType,
903
904    /// Whether this field can be mutated or not.
905    pub mutable: bool,
906}
907
908impl fmt::Display for WasmFieldType {
909    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
910        if self.mutable {
911            write!(f, "(mut {})", self.element_type)
912        } else {
913            fmt::Display::fmt(&self.element_type, f)
914        }
915    }
916}
917
918impl TypeTrace for WasmFieldType {
919    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
920    where
921        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
922    {
923        self.element_type.trace(func)
924    }
925
926    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
927    where
928        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
929    {
930        self.element_type.trace_mut(func)
931    }
932}
933
934/// A concrete array type.
935#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
936pub struct WasmArrayType(pub WasmFieldType);
937
938impl fmt::Display for WasmArrayType {
939    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
940        write!(f, "(array {})", self.0)
941    }
942}
943
944impl TypeTrace for WasmArrayType {
945    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
946    where
947        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
948    {
949        self.0.trace(func)
950    }
951
952    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
953    where
954        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
955    {
956        self.0.trace_mut(func)
957    }
958}
959
960/// A concrete struct type.
961#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
962pub struct WasmStructType {
963    /// The fields that make up this struct type.
964    pub fields: Box<[WasmFieldType]>,
965}
966
967impl fmt::Display for WasmStructType {
968    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
969        write!(f, "(struct")?;
970        for ty in self.fields.iter() {
971            write!(f, " {ty}")?;
972        }
973        write!(f, ")")
974    }
975}
976
977impl TypeTrace for WasmStructType {
978    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
979    where
980        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
981    {
982        for f in self.fields.iter() {
983            f.trace(func)?;
984        }
985        Ok(())
986    }
987
988    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
989    where
990        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
991    {
992        for f in self.fields.iter_mut() {
993            f.trace_mut(func)?;
994        }
995        Ok(())
996    }
997}
998
999#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1000#[expect(missing_docs, reason = "self-describing type")]
1001pub struct WasmCompositeType {
1002    /// The type defined inside the composite type.
1003    pub inner: WasmCompositeInnerType,
1004    /// Is the composite type shared? This is part of the
1005    /// shared-everything-threads proposal.
1006    pub shared: bool,
1007}
1008
1009impl fmt::Display for WasmCompositeType {
1010    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1011        if self.shared {
1012            write!(f, "(shared ")?;
1013        }
1014        fmt::Display::fmt(&self.inner, f)?;
1015        if self.shared {
1016            write!(f, ")")?;
1017        }
1018        Ok(())
1019    }
1020}
1021
1022/// A function, array, or struct type.
1023#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1024#[expect(missing_docs, reason = "self-describing variants")]
1025pub enum WasmCompositeInnerType {
1026    Array(WasmArrayType),
1027    Func(WasmFuncType),
1028    Struct(WasmStructType),
1029    Cont(WasmContType),
1030}
1031
1032impl fmt::Display for WasmCompositeInnerType {
1033    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1034        match self {
1035            Self::Array(ty) => fmt::Display::fmt(ty, f),
1036            Self::Func(ty) => fmt::Display::fmt(ty, f),
1037            Self::Struct(ty) => fmt::Display::fmt(ty, f),
1038            Self::Cont(ty) => fmt::Display::fmt(ty, f),
1039        }
1040    }
1041}
1042
1043#[expect(missing_docs, reason = "self-describing functions")]
1044impl WasmCompositeInnerType {
1045    #[inline]
1046    pub fn is_array(&self) -> bool {
1047        matches!(self, Self::Array(_))
1048    }
1049
1050    #[inline]
1051    pub fn as_array(&self) -> Option<&WasmArrayType> {
1052        match self {
1053            Self::Array(f) => Some(f),
1054            _ => None,
1055        }
1056    }
1057
1058    #[inline]
1059    pub fn unwrap_array(&self) -> &WasmArrayType {
1060        self.as_array().unwrap()
1061    }
1062
1063    #[inline]
1064    pub fn is_func(&self) -> bool {
1065        matches!(self, Self::Func(_))
1066    }
1067
1068    #[inline]
1069    pub fn as_func(&self) -> Option<&WasmFuncType> {
1070        match self {
1071            Self::Func(f) => Some(f),
1072            _ => None,
1073        }
1074    }
1075
1076    #[inline]
1077    pub fn unwrap_func(&self) -> &WasmFuncType {
1078        self.as_func().unwrap()
1079    }
1080
1081    #[inline]
1082    pub fn is_struct(&self) -> bool {
1083        matches!(self, Self::Struct(_))
1084    }
1085
1086    #[inline]
1087    pub fn as_struct(&self) -> Option<&WasmStructType> {
1088        match self {
1089            Self::Struct(f) => Some(f),
1090            _ => None,
1091        }
1092    }
1093
1094    #[inline]
1095    pub fn unwrap_struct(&self) -> &WasmStructType {
1096        self.as_struct().unwrap()
1097    }
1098
1099    #[inline]
1100    pub fn is_cont(&self) -> bool {
1101        matches!(self, Self::Cont(_))
1102    }
1103
1104    #[inline]
1105    pub fn as_cont(&self) -> Option<&WasmContType> {
1106        match self {
1107            Self::Cont(f) => Some(f),
1108            _ => None,
1109        }
1110    }
1111
1112    #[inline]
1113    pub fn unwrap_cont(&self) -> &WasmContType {
1114        self.as_cont().unwrap()
1115    }
1116}
1117
1118impl TypeTrace for WasmCompositeType {
1119    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1120    where
1121        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1122    {
1123        match &self.inner {
1124            WasmCompositeInnerType::Array(a) => a.trace(func),
1125            WasmCompositeInnerType::Func(f) => f.trace(func),
1126            WasmCompositeInnerType::Struct(a) => a.trace(func),
1127            WasmCompositeInnerType::Cont(c) => c.trace(func),
1128        }
1129    }
1130
1131    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1132    where
1133        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1134    {
1135        match &mut self.inner {
1136            WasmCompositeInnerType::Array(a) => a.trace_mut(func),
1137            WasmCompositeInnerType::Func(f) => f.trace_mut(func),
1138            WasmCompositeInnerType::Struct(a) => a.trace_mut(func),
1139            WasmCompositeInnerType::Cont(c) => c.trace_mut(func),
1140        }
1141    }
1142}
1143
1144/// A concrete, user-defined (or host-defined) Wasm type.
1145#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1146pub struct WasmSubType {
1147    /// Whether this type is forbidden from being the supertype of any other
1148    /// type.
1149    pub is_final: bool,
1150
1151    /// This type's supertype, if any.
1152    pub supertype: Option<EngineOrModuleTypeIndex>,
1153
1154    /// The array, function, or struct that is defined.
1155    pub composite_type: WasmCompositeType,
1156}
1157
1158impl fmt::Display for WasmSubType {
1159    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1160        if self.is_final && self.supertype.is_none() {
1161            fmt::Display::fmt(&self.composite_type, f)
1162        } else {
1163            write!(f, "(sub")?;
1164            if self.is_final {
1165                write!(f, " final")?;
1166            }
1167            if let Some(sup) = self.supertype {
1168                write!(f, " {sup}")?;
1169            }
1170            write!(f, " {})", self.composite_type)
1171        }
1172    }
1173}
1174
1175/// Implicitly define all of these helper functions to handle only unshared
1176/// types; essentially, these act like `is_unshared_*` functions until shared
1177/// support is implemented.
1178#[expect(missing_docs, reason = "self-describing functions")]
1179impl WasmSubType {
1180    #[inline]
1181    pub fn is_func(&self) -> bool {
1182        self.composite_type.inner.is_func() && !self.composite_type.shared
1183    }
1184
1185    #[inline]
1186    pub fn as_func(&self) -> Option<&WasmFuncType> {
1187        if self.composite_type.shared {
1188            None
1189        } else {
1190            self.composite_type.inner.as_func()
1191        }
1192    }
1193
1194    #[inline]
1195    pub fn unwrap_func(&self) -> &WasmFuncType {
1196        assert!(!self.composite_type.shared);
1197        self.composite_type.inner.unwrap_func()
1198    }
1199
1200    #[inline]
1201    pub fn is_array(&self) -> bool {
1202        self.composite_type.inner.is_array() && !self.composite_type.shared
1203    }
1204
1205    #[inline]
1206    pub fn as_array(&self) -> Option<&WasmArrayType> {
1207        if self.composite_type.shared {
1208            None
1209        } else {
1210            self.composite_type.inner.as_array()
1211        }
1212    }
1213
1214    #[inline]
1215    pub fn unwrap_array(&self) -> &WasmArrayType {
1216        assert!(!self.composite_type.shared);
1217        self.composite_type.inner.unwrap_array()
1218    }
1219
1220    #[inline]
1221    pub fn is_struct(&self) -> bool {
1222        self.composite_type.inner.is_struct() && !self.composite_type.shared
1223    }
1224
1225    #[inline]
1226    pub fn as_struct(&self) -> Option<&WasmStructType> {
1227        if self.composite_type.shared {
1228            None
1229        } else {
1230            self.composite_type.inner.as_struct()
1231        }
1232    }
1233
1234    #[inline]
1235    pub fn unwrap_struct(&self) -> &WasmStructType {
1236        assert!(!self.composite_type.shared);
1237        self.composite_type.inner.unwrap_struct()
1238    }
1239
1240    #[inline]
1241    pub fn is_cont(&self) -> bool {
1242        self.composite_type.inner.is_cont() && !self.composite_type.shared
1243    }
1244
1245    #[inline]
1246    pub fn as_cont(&self) -> Option<&WasmContType> {
1247        if self.composite_type.shared {
1248            None
1249        } else {
1250            self.composite_type.inner.as_cont()
1251        }
1252    }
1253
1254    #[inline]
1255    pub fn unwrap_cont(&self) -> &WasmContType {
1256        assert!(!self.composite_type.shared);
1257        self.composite_type.inner.unwrap_cont()
1258    }
1259}
1260
1261impl TypeTrace for WasmSubType {
1262    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1263    where
1264        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1265    {
1266        if let Some(sup) = self.supertype {
1267            func(sup)?;
1268        }
1269        self.composite_type.trace(func)
1270    }
1271
1272    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1273    where
1274        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1275    {
1276        if let Some(sup) = self.supertype.as_mut() {
1277            func(sup)?;
1278        }
1279        self.composite_type.trace_mut(func)
1280    }
1281}
1282
1283/// A recursive type group.
1284///
1285/// Types within a recgroup can have forward references to each other, which
1286/// allows for cyclic types, for example a function `$f` that returns a
1287/// reference to a function `$g` which returns a reference to a function `$f`:
1288///
1289/// ```ignore
1290/// (rec (type (func $f (result (ref null $g))))
1291///      (type (func $g (result (ref null $f)))))
1292/// ```
1293#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1294pub struct WasmRecGroup {
1295    /// The types inside of this recgroup.
1296    pub types: Box<[WasmSubType]>,
1297}
1298
1299impl TypeTrace for WasmRecGroup {
1300    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1301    where
1302        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1303    {
1304        for ty in self.types.iter() {
1305            ty.trace(func)?;
1306        }
1307        Ok(())
1308    }
1309
1310    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1311    where
1312        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1313    {
1314        for ty in self.types.iter_mut() {
1315            ty.trace_mut(func)?;
1316        }
1317        Ok(())
1318    }
1319}
1320
1321/// Index type of a function (imported or defined) inside the WebAssembly module.
1322#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1323pub struct FuncIndex(u32);
1324entity_impl!(FuncIndex);
1325
1326/// Index type of a defined function inside the WebAssembly module.
1327#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1328pub struct DefinedFuncIndex(u32);
1329entity_impl!(DefinedFuncIndex);
1330
1331/// Index type of a defined table inside the WebAssembly module.
1332#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1333pub struct DefinedTableIndex(u32);
1334entity_impl!(DefinedTableIndex);
1335
1336/// Index type of a defined memory inside the WebAssembly module.
1337#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1338pub struct DefinedMemoryIndex(u32);
1339entity_impl!(DefinedMemoryIndex);
1340
1341/// Index type of a defined memory inside the WebAssembly module.
1342#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1343pub struct OwnedMemoryIndex(u32);
1344entity_impl!(OwnedMemoryIndex);
1345
1346/// Index type of a defined global inside the WebAssembly module.
1347#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1348pub struct DefinedGlobalIndex(u32);
1349entity_impl!(DefinedGlobalIndex);
1350
1351/// Index type of a table (imported or defined) inside the WebAssembly module.
1352#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1353pub struct TableIndex(u32);
1354entity_impl!(TableIndex);
1355
1356/// Index type of a global variable (imported or defined) inside the WebAssembly module.
1357#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1358pub struct GlobalIndex(u32);
1359entity_impl!(GlobalIndex);
1360
1361/// Index type of a linear memory (imported or defined) inside the WebAssembly module.
1362#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1363pub struct MemoryIndex(u32);
1364entity_impl!(MemoryIndex);
1365
1366/// Index type of a canonicalized recursive type group inside a WebAssembly
1367/// module (as opposed to canonicalized within the whole engine).
1368#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1369pub struct ModuleInternedRecGroupIndex(u32);
1370entity_impl!(ModuleInternedRecGroupIndex);
1371
1372/// Index type of a canonicalized recursive type group inside the whole engine
1373/// (as opposed to canonicalized within just a single Wasm module).
1374#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1375pub struct EngineInternedRecGroupIndex(u32);
1376entity_impl!(EngineInternedRecGroupIndex);
1377
1378/// Index type of a type (imported or defined) inside the WebAssembly module.
1379#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1380pub struct TypeIndex(u32);
1381entity_impl!(TypeIndex);
1382
1383/// A canonicalized type index referencing a type within a single recursion
1384/// group from another type within that same recursion group.
1385///
1386/// This is only suitable for use when hash consing and deduplicating rec
1387/// groups.
1388#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1389pub struct RecGroupRelativeTypeIndex(u32);
1390entity_impl!(RecGroupRelativeTypeIndex);
1391
1392/// A canonicalized type index for a type within a single WebAssembly module.
1393///
1394/// Note that this is deduplicated only at the level of a single WebAssembly
1395/// module, not at the level of a whole store or engine. This means that these
1396/// indices are only unique within the context of a single Wasm module, and
1397/// therefore are not suitable for runtime type checks (which, in general, may
1398/// involve entities defined in different modules).
1399#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1400pub struct ModuleInternedTypeIndex(u32);
1401entity_impl!(ModuleInternedTypeIndex);
1402
1403/// A canonicalized type index into an engine's shared type registry.
1404///
1405/// This is canonicalized/deduped at the level of a whole engine, across all the
1406/// modules loaded into that engine, not just at the level of a single
1407/// particular module. This means that `VMSharedTypeIndex` is usable for
1408/// e.g. checking that function signatures match during an indirect call
1409/// (potentially to a function defined in a different module) at runtime.
1410#[repr(transparent)] // Used directly by JIT code.
1411#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1412pub struct VMSharedTypeIndex(u32);
1413entity_impl!(VMSharedTypeIndex);
1414
1415impl VMSharedTypeIndex {
1416    /// Create a new `VMSharedTypeIndex`.
1417    #[inline]
1418    pub fn new(value: u32) -> Self {
1419        assert_ne!(
1420            value,
1421            u32::MAX,
1422            "u32::MAX is reserved for the default value"
1423        );
1424        Self(value)
1425    }
1426
1427    /// Returns the underlying bits of the index.
1428    #[inline]
1429    pub fn bits(&self) -> u32 {
1430        self.0
1431    }
1432}
1433
1434impl Default for VMSharedTypeIndex {
1435    #[inline]
1436    fn default() -> Self {
1437        Self(u32::MAX)
1438    }
1439}
1440
1441/// Index type of a passive data segment inside the WebAssembly module.
1442#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1443pub struct DataIndex(u32);
1444entity_impl!(DataIndex);
1445
1446/// Index type of a passive element segment inside the WebAssembly module.
1447#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1448pub struct ElemIndex(u32);
1449entity_impl!(ElemIndex);
1450
1451/// Index type of a defined tag inside the WebAssembly module.
1452#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1453pub struct DefinedTagIndex(u32);
1454entity_impl!(DefinedTagIndex);
1455
1456/// Index type of an event inside the WebAssembly module.
1457#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1458pub struct TagIndex(u32);
1459entity_impl!(TagIndex);
1460
1461/// Index into the global list of modules found within an entire component.
1462///
1463/// Module translations are saved on the side to get fully compiled after
1464/// the original component has finished being translated.
1465#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1466pub struct StaticModuleIndex(u32);
1467entity_impl!(StaticModuleIndex);
1468
1469/// An index of an entity.
1470#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1471pub enum EntityIndex {
1472    /// Function index.
1473    Function(FuncIndex),
1474    /// Table index.
1475    Table(TableIndex),
1476    /// Memory index.
1477    Memory(MemoryIndex),
1478    /// Global index.
1479    Global(GlobalIndex),
1480    /// Tag index.
1481    Tag(TagIndex),
1482}
1483
1484impl From<FuncIndex> for EntityIndex {
1485    fn from(idx: FuncIndex) -> EntityIndex {
1486        EntityIndex::Function(idx)
1487    }
1488}
1489
1490impl From<TableIndex> for EntityIndex {
1491    fn from(idx: TableIndex) -> EntityIndex {
1492        EntityIndex::Table(idx)
1493    }
1494}
1495
1496impl From<MemoryIndex> for EntityIndex {
1497    fn from(idx: MemoryIndex) -> EntityIndex {
1498        EntityIndex::Memory(idx)
1499    }
1500}
1501
1502impl From<GlobalIndex> for EntityIndex {
1503    fn from(idx: GlobalIndex) -> EntityIndex {
1504        EntityIndex::Global(idx)
1505    }
1506}
1507
1508impl From<TagIndex> for EntityIndex {
1509    fn from(idx: TagIndex) -> EntityIndex {
1510        EntityIndex::Tag(idx)
1511    }
1512}
1513
1514/// A type of an item in a wasm module where an item is typically something that
1515/// can be exported.
1516#[derive(Clone, Debug, Serialize, Deserialize)]
1517pub enum EntityType {
1518    /// A global variable with the specified content type
1519    Global(Global),
1520    /// A linear memory with the specified limits
1521    Memory(Memory),
1522    /// An exception and control tag definition.
1523    Tag(Tag),
1524    /// A table with the specified element type and limits
1525    Table(Table),
1526    /// A function type where the index points to the type section and records a
1527    /// function signature.
1528    Function(EngineOrModuleTypeIndex),
1529}
1530
1531impl TypeTrace for EntityType {
1532    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1533    where
1534        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1535    {
1536        match self {
1537            Self::Global(g) => g.trace(func),
1538            Self::Table(t) => t.trace(func),
1539            Self::Function(idx) => func(*idx),
1540            Self::Memory(_) => Ok(()),
1541            Self::Tag(t) => t.trace(func),
1542        }
1543    }
1544
1545    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1546    where
1547        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1548    {
1549        match self {
1550            Self::Global(g) => g.trace_mut(func),
1551            Self::Table(t) => t.trace_mut(func),
1552            Self::Function(idx) => func(idx),
1553            Self::Memory(_) => Ok(()),
1554            Self::Tag(t) => t.trace_mut(func),
1555        }
1556    }
1557}
1558
1559impl EntityType {
1560    /// Assert that this entity is a global
1561    pub fn unwrap_global(&self) -> &Global {
1562        match self {
1563            EntityType::Global(g) => g,
1564            _ => panic!("not a global"),
1565        }
1566    }
1567
1568    /// Assert that this entity is a memory
1569    pub fn unwrap_memory(&self) -> &Memory {
1570        match self {
1571            EntityType::Memory(g) => g,
1572            _ => panic!("not a memory"),
1573        }
1574    }
1575
1576    /// Assert that this entity is a tag
1577    pub fn unwrap_tag(&self) -> &Tag {
1578        match self {
1579            EntityType::Tag(g) => g,
1580            _ => panic!("not a tag"),
1581        }
1582    }
1583
1584    /// Assert that this entity is a table
1585    pub fn unwrap_table(&self) -> &Table {
1586        match self {
1587            EntityType::Table(g) => g,
1588            _ => panic!("not a table"),
1589        }
1590    }
1591
1592    /// Assert that this entity is a function
1593    pub fn unwrap_func(&self) -> EngineOrModuleTypeIndex {
1594        match self {
1595            EntityType::Function(g) => *g,
1596            _ => panic!("not a func"),
1597        }
1598    }
1599}
1600
1601/// A WebAssembly global.
1602///
1603/// Note that we record both the original Wasm type and the Cranelift IR type
1604/// used to represent it. This is because multiple different kinds of Wasm types
1605/// might be represented with the same Cranelift IR type. For example, both a
1606/// Wasm `i64` and a `funcref` might be represented with a Cranelift `i64` on
1607/// 64-bit architectures, and when GC is not required for func refs.
1608#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1609pub struct Global {
1610    /// The Wasm type of the value stored in the global.
1611    pub wasm_ty: crate::WasmValType,
1612    /// A flag indicating whether the value may change at runtime.
1613    pub mutability: bool,
1614}
1615
1616impl TypeTrace for Global {
1617    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1618    where
1619        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1620    {
1621        let Global {
1622            wasm_ty,
1623            mutability: _,
1624        } = self;
1625        wasm_ty.trace(func)
1626    }
1627
1628    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1629    where
1630        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1631    {
1632        let Global {
1633            wasm_ty,
1634            mutability: _,
1635        } = self;
1636        wasm_ty.trace_mut(func)
1637    }
1638}
1639
1640/// A constant expression.
1641///
1642/// These are used to initialize globals, table elements, etc...
1643#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1644pub struct ConstExpr {
1645    ops: SmallVec<[ConstOp; 2]>,
1646}
1647
1648impl ConstExpr {
1649    /// Create a new const expression from the given opcodes.
1650    ///
1651    /// Does not do any validation that the const expression is well-typed.
1652    ///
1653    /// Panics if given zero opcodes.
1654    pub fn new(ops: impl IntoIterator<Item = ConstOp>) -> Self {
1655        let ops = ops.into_iter().collect::<SmallVec<[ConstOp; 2]>>();
1656        assert!(!ops.is_empty());
1657        ConstExpr { ops }
1658    }
1659
1660    /// Create a new const expression from a `wasmparser` const expression.
1661    ///
1662    /// Returns the new const expression as well as the escaping function
1663    /// indices that appeared in `ref.func` instructions, if any.
1664    pub fn from_wasmparser(
1665        expr: wasmparser::ConstExpr<'_>,
1666    ) -> WasmResult<(Self, SmallVec<[FuncIndex; 1]>)> {
1667        let mut iter = expr
1668            .get_operators_reader()
1669            .into_iter_with_offsets()
1670            .peekable();
1671
1672        let mut ops = SmallVec::<[ConstOp; 2]>::new();
1673        let mut escaped = SmallVec::<[FuncIndex; 1]>::new();
1674        while let Some(res) = iter.next() {
1675            let (op, offset) = res?;
1676
1677            // If we reach an `end` instruction, and there are no more
1678            // instructions after that, then we are done reading this const
1679            // expression.
1680            if matches!(op, wasmparser::Operator::End) && iter.peek().is_none() {
1681                break;
1682            }
1683
1684            // Track any functions that appear in `ref.func` so that callers can
1685            // make sure to flag them as escaping.
1686            if let wasmparser::Operator::RefFunc { function_index } = &op {
1687                escaped.push(FuncIndex::from_u32(*function_index));
1688            }
1689
1690            ops.push(ConstOp::from_wasmparser(op, offset)?);
1691        }
1692        Ok((Self { ops }, escaped))
1693    }
1694
1695    /// Get the opcodes that make up this const expression.
1696    pub fn ops(&self) -> &[ConstOp] {
1697        &self.ops
1698    }
1699
1700    /// Is this ConstExpr a provably nonzero integer value?
1701    ///
1702    /// This must be conservative: if the expression *might* be zero,
1703    /// it must return `false`. It is always allowed to return `false`
1704    /// for some expression kind that we don't support. However, if it
1705    /// returns `true`, the expression must be actually nonzero.
1706    ///
1707    /// We use this for certain table optimizations that rely on
1708    /// knowing for sure that index 0 is not referenced.
1709    pub fn provably_nonzero_i32(&self) -> bool {
1710        assert!(self.ops.len() > 0);
1711        if self.ops.len() > 1 {
1712            // Compound expressions not yet supported: conservatively
1713            // return `false` (we can't prove nonzero).
1714            return false;
1715        }
1716        // Exactly one op at this point.
1717        match self.ops[0] {
1718            // An actual zero value -- definitely not nonzero!
1719            ConstOp::I32Const(0) => false,
1720            // Any other constant value -- provably nonzero, if above
1721            // did not match.
1722            ConstOp::I32Const(_) => true,
1723            // Anything else: we can't prove anything.
1724            _ => false,
1725        }
1726    }
1727}
1728
1729/// The subset of Wasm opcodes that are constant.
1730#[expect(missing_docs, reason = "self-describing variants")]
1731#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1732pub enum ConstOp {
1733    I32Const(i32),
1734    I64Const(i64),
1735    F32Const(u32),
1736    F64Const(u64),
1737    V128Const(u128),
1738    GlobalGet(GlobalIndex),
1739    RefI31,
1740    RefNull,
1741    RefFunc(FuncIndex),
1742    I32Add,
1743    I32Sub,
1744    I32Mul,
1745    I64Add,
1746    I64Sub,
1747    I64Mul,
1748    StructNew {
1749        struct_type_index: TypeIndex,
1750    },
1751    StructNewDefault {
1752        struct_type_index: TypeIndex,
1753    },
1754    ArrayNew {
1755        array_type_index: TypeIndex,
1756    },
1757    ArrayNewDefault {
1758        array_type_index: TypeIndex,
1759    },
1760    ArrayNewFixed {
1761        array_type_index: TypeIndex,
1762        array_size: u32,
1763    },
1764    ExternConvertAny,
1765    AnyConvertExtern,
1766}
1767
1768impl ConstOp {
1769    /// Convert a `wasmparser::Operator` to a `ConstOp`.
1770    pub fn from_wasmparser(op: wasmparser::Operator<'_>, offset: usize) -> WasmResult<Self> {
1771        use wasmparser::Operator as O;
1772        Ok(match op {
1773            O::I32Const { value } => Self::I32Const(value),
1774            O::I64Const { value } => Self::I64Const(value),
1775            O::F32Const { value } => Self::F32Const(value.bits()),
1776            O::F64Const { value } => Self::F64Const(value.bits()),
1777            O::V128Const { value } => Self::V128Const(u128::from_le_bytes(*value.bytes())),
1778            O::RefNull { hty: _ } => Self::RefNull,
1779            O::RefFunc { function_index } => Self::RefFunc(FuncIndex::from_u32(function_index)),
1780            O::GlobalGet { global_index } => Self::GlobalGet(GlobalIndex::from_u32(global_index)),
1781            O::RefI31 => Self::RefI31,
1782            O::I32Add => Self::I32Add,
1783            O::I32Sub => Self::I32Sub,
1784            O::I32Mul => Self::I32Mul,
1785            O::I64Add => Self::I64Add,
1786            O::I64Sub => Self::I64Sub,
1787            O::I64Mul => Self::I64Mul,
1788            O::StructNew { struct_type_index } => Self::StructNew {
1789                struct_type_index: TypeIndex::from_u32(struct_type_index),
1790            },
1791            O::StructNewDefault { struct_type_index } => Self::StructNewDefault {
1792                struct_type_index: TypeIndex::from_u32(struct_type_index),
1793            },
1794            O::ArrayNew { array_type_index } => Self::ArrayNew {
1795                array_type_index: TypeIndex::from_u32(array_type_index),
1796            },
1797            O::ArrayNewDefault { array_type_index } => Self::ArrayNewDefault {
1798                array_type_index: TypeIndex::from_u32(array_type_index),
1799            },
1800            O::ArrayNewFixed {
1801                array_type_index,
1802                array_size,
1803            } => Self::ArrayNewFixed {
1804                array_type_index: TypeIndex::from_u32(array_type_index),
1805                array_size,
1806            },
1807            O::ExternConvertAny => Self::ExternConvertAny,
1808            O::AnyConvertExtern => Self::AnyConvertExtern,
1809            op => {
1810                return Err(wasm_unsupported!(
1811                    "unsupported opcode in const expression at offset {offset:#x}: {op:?}",
1812                ));
1813            }
1814        })
1815    }
1816}
1817
1818/// The type that can be used to index into [Memory] and [Table].
1819#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1820#[expect(missing_docs, reason = "self-describing variants")]
1821pub enum IndexType {
1822    I32,
1823    I64,
1824}
1825
1826/// The size range of resizeable storage associated with [Memory] types and [Table] types.
1827#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1828#[expect(missing_docs, reason = "self-describing fields")]
1829pub struct Limits {
1830    pub min: u64,
1831    pub max: Option<u64>,
1832}
1833
1834/// WebAssembly table.
1835#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1836pub struct Table {
1837    /// The type of the index used to access the table.
1838    pub idx_type: IndexType,
1839    /// Tables are constrained by limits for their minimum and optionally maximum size.
1840    /// The limits are given in numbers of entries.
1841    pub limits: Limits,
1842    /// The table elements' Wasm type.
1843    pub ref_type: WasmRefType,
1844}
1845
1846impl TypeTrace for Table {
1847    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1848    where
1849        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1850    {
1851        let Table {
1852            ref_type: wasm_ty,
1853            idx_type: _,
1854            limits: _,
1855        } = self;
1856        wasm_ty.trace(func)
1857    }
1858
1859    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1860    where
1861        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1862    {
1863        let Table {
1864            ref_type: wasm_ty,
1865            idx_type: _,
1866            limits: _,
1867        } = self;
1868        wasm_ty.trace_mut(func)
1869    }
1870}
1871
1872/// WebAssembly linear memory.
1873#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1874pub struct Memory {
1875    /// The type of the index used to access the memory.
1876    pub idx_type: IndexType,
1877    /// The limits constrain the minimum and optionally the maximum size of a memory.
1878    /// The limits are given in units of page size.
1879    pub limits: Limits,
1880    /// Whether the memory may be shared between multiple threads.
1881    pub shared: bool,
1882    /// The log2 of this memory's page size, in bytes.
1883    ///
1884    /// By default the page size is 64KiB (0x10000; 2**16; 1<<16; 65536) but the
1885    /// custom-page-sizes proposal allows opting into a page size of `1`.
1886    pub page_size_log2: u8,
1887}
1888
1889/// Maximum size, in bytes, of 32-bit memories (4G)
1890pub const WASM32_MAX_SIZE: u64 = 1 << 32;
1891
1892impl Memory {
1893    /// WebAssembly page sizes are 64KiB by default.
1894    pub const DEFAULT_PAGE_SIZE: u32 = 0x10000;
1895
1896    /// WebAssembly page sizes are 64KiB (or `2**16`) by default.
1897    pub const DEFAULT_PAGE_SIZE_LOG2: u8 = {
1898        let log2 = 16;
1899        assert!(1 << log2 == Memory::DEFAULT_PAGE_SIZE);
1900        log2
1901    };
1902
1903    /// Returns the minimum size, in bytes, that this memory must be.
1904    ///
1905    /// # Errors
1906    ///
1907    /// Returns an error if the calculation of the minimum size overflows the
1908    /// `u64` return type. This means that the memory can't be allocated but
1909    /// it's deferred to the caller to how to deal with that.
1910    pub fn minimum_byte_size(&self) -> Result<u64, SizeOverflow> {
1911        self.limits
1912            .min
1913            .checked_mul(self.page_size())
1914            .ok_or(SizeOverflow)
1915    }
1916
1917    /// Returns the maximum size, in bytes, that this memory is allowed to be.
1918    ///
1919    /// Note that the return value here is not an `Option` despite the maximum
1920    /// size of a linear memory being optional in wasm. If a maximum size
1921    /// is not present in the memory's type then a maximum size is selected for
1922    /// it. For example the maximum size of a 32-bit memory is `1<<32`. The
1923    /// maximum size of a 64-bit linear memory is chosen to be a value that
1924    /// won't ever be allowed at runtime.
1925    ///
1926    /// # Errors
1927    ///
1928    /// Returns an error if the calculation of the maximum size overflows the
1929    /// `u64` return type. This means that the memory can't be allocated but
1930    /// it's deferred to the caller to how to deal with that.
1931    pub fn maximum_byte_size(&self) -> Result<u64, SizeOverflow> {
1932        match self.limits.max {
1933            Some(max) => max.checked_mul(self.page_size()).ok_or(SizeOverflow),
1934            None => {
1935                let min = self.minimum_byte_size()?;
1936                Ok(min.max(self.max_size_based_on_index_type()))
1937            }
1938        }
1939    }
1940
1941    /// Get the size of this memory's pages, in bytes.
1942    pub fn page_size(&self) -> u64 {
1943        debug_assert!(
1944            self.page_size_log2 == 16 || self.page_size_log2 == 0,
1945            "invalid page_size_log2: {}; must be 16 or 0",
1946            self.page_size_log2
1947        );
1948        1 << self.page_size_log2
1949    }
1950
1951    /// Returns the maximum size memory is allowed to be only based on the
1952    /// index type used by this memory.
1953    ///
1954    /// For example 32-bit linear memories return `1<<32` from this method.
1955    pub fn max_size_based_on_index_type(&self) -> u64 {
1956        match self.idx_type {
1957            IndexType::I64 =>
1958            // Note that the true maximum size of a 64-bit linear memory, in
1959            // bytes, cannot be represented in a `u64`. That would require a u65
1960            // to store `1<<64`. Despite that no system can actually allocate a
1961            // full 64-bit linear memory so this is instead emulated as "what if
1962            // the kernel fit in a single Wasm page of linear memory". Shouldn't
1963            // ever actually be possible but it provides a number to serve as an
1964            // effective maximum.
1965            {
1966                0_u64.wrapping_sub(self.page_size())
1967            }
1968            IndexType::I32 => WASM32_MAX_SIZE,
1969        }
1970    }
1971
1972    /// Returns whether this memory can be implemented with virtual memory on
1973    /// a host with `host_page_size_log2`.
1974    ///
1975    /// When this function returns `true` then it means that signals such as
1976    /// SIGSEGV on the host are compatible with wasm and can be used to
1977    /// represent out-of-bounds memory accesses.
1978    ///
1979    /// When this function returns `false` then it means that this memory must,
1980    /// for example, have explicit bounds checks. This additionally means that
1981    /// virtual memory traps (e.g. SIGSEGV) cannot be relied on to implement
1982    /// linear memory semantics.
1983    pub fn can_use_virtual_memory(&self, tunables: &Tunables, host_page_size_log2: u8) -> bool {
1984        tunables.signals_based_traps && self.page_size_log2 >= host_page_size_log2
1985    }
1986
1987    /// Returns whether this memory is a candidate for bounds check elision
1988    /// given the configuration and host page size.
1989    ///
1990    /// This function determines whether the given compilation configuration and
1991    /// hos enables possible bounds check elision for this memory. Bounds checks
1992    /// can only be elided if [`Memory::can_use_virtual_memory`] returns `true`
1993    /// for example but there are additionally requirements on the index size of
1994    /// this memory and the memory reservation in `tunables`.
1995    ///
1996    /// Currently the only case that supports bounds check elision is when all
1997    /// of these apply:
1998    ///
1999    /// * When [`Memory::can_use_virtual_memory`] returns `true`.
2000    /// * This is a 32-bit linear memory (e.g. not 64-bit)
2001    /// * `tunables.memory_reservation` is in excess of 4GiB
2002    ///
2003    /// In this situation all computable addresses fall within the reserved
2004    /// space (modulo static offsets factoring in guard pages) so bounds checks
2005    /// may be elidable.
2006    pub fn can_elide_bounds_check(&self, tunables: &Tunables, host_page_size_log2: u8) -> bool {
2007        self.can_use_virtual_memory(tunables, host_page_size_log2)
2008            && self.idx_type == IndexType::I32
2009            && tunables.memory_reservation >= (1 << 32)
2010    }
2011
2012    /// Returns the static size of this heap in bytes at runtime, if available.
2013    ///
2014    /// This is only computable when the minimum size equals the maximum size.
2015    pub fn static_heap_size(&self) -> Option<u64> {
2016        let min = self.minimum_byte_size().ok()?;
2017        let max = self.maximum_byte_size().ok()?;
2018        if min == max { Some(min) } else { None }
2019    }
2020
2021    /// Returns whether or not the base pointer of this memory is allowed to be
2022    /// relocated at runtime.
2023    ///
2024    /// When this function returns `false` then it means that after the initial
2025    /// allocation the base pointer is constant for the entire lifetime of a
2026    /// memory. This can enable compiler optimizations, for example.
2027    pub fn memory_may_move(&self, tunables: &Tunables) -> bool {
2028        // Shared memories cannot ever relocate their base pointer so the
2029        // settings configured in the engine must be appropriate for them ahead
2030        // of time.
2031        if self.shared {
2032            return false;
2033        }
2034
2035        // If movement is disallowed in engine configuration, then the answer is
2036        // "no".
2037        if !tunables.memory_may_move {
2038            return false;
2039        }
2040
2041        // If its minimum and maximum are the same, then the memory will never
2042        // be resized, and therefore will never move.
2043        if self.limits.max.is_some_and(|max| self.limits.min == max) {
2044            return false;
2045        }
2046
2047        // If the maximum size of this memory is above the threshold of the
2048        // initial memory reservation then the memory may move.
2049        let max = self.maximum_byte_size().unwrap_or(u64::MAX);
2050        max > tunables.memory_reservation
2051    }
2052}
2053
2054#[derive(Copy, Clone, Debug)]
2055#[expect(missing_docs, reason = "self-describing error struct")]
2056pub struct SizeOverflow;
2057
2058impl fmt::Display for SizeOverflow {
2059    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2060        f.write_str("size overflow calculating memory size")
2061    }
2062}
2063
2064impl core::error::Error for SizeOverflow {}
2065
2066impl From<wasmparser::MemoryType> for Memory {
2067    fn from(ty: wasmparser::MemoryType) -> Memory {
2068        let idx_type = match ty.memory64 {
2069            false => IndexType::I32,
2070            true => IndexType::I64,
2071        };
2072        let limits = Limits {
2073            min: ty.initial,
2074            max: ty.maximum,
2075        };
2076        let page_size_log2 = u8::try_from(ty.page_size_log2.unwrap_or(16)).unwrap();
2077        debug_assert!(
2078            page_size_log2 == 16 || page_size_log2 == 0,
2079            "invalid page_size_log2: {page_size_log2}; must be 16 or 0"
2080        );
2081        Memory {
2082            idx_type,
2083            limits,
2084            shared: ty.shared,
2085            page_size_log2,
2086        }
2087    }
2088}
2089
2090/// WebAssembly exception and control tag.
2091#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2092pub struct Tag {
2093    /// The tag signature type.
2094    pub signature: EngineOrModuleTypeIndex,
2095}
2096
2097impl TypeTrace for Tag {
2098    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
2099    where
2100        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
2101    {
2102        func(self.signature)
2103    }
2104
2105    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
2106    where
2107        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
2108    {
2109        func(&mut self.signature)
2110    }
2111}
2112
2113/// Helpers used to convert a `wasmparser` type to a type in this crate.
2114#[expect(missing_docs, reason = "self-describing functions")]
2115pub trait TypeConvert {
2116    /// Converts a wasmparser table type into a wasmtime type
2117    fn convert_global_type(&self, ty: &wasmparser::GlobalType) -> WasmResult<Global> {
2118        Ok(Global {
2119            wasm_ty: self.convert_valtype(ty.content_type)?,
2120            mutability: ty.mutable,
2121        })
2122    }
2123
2124    /// Converts a wasmparser table type into a wasmtime type
2125    fn convert_table_type(&self, ty: &wasmparser::TableType) -> WasmResult<Table> {
2126        let idx_type = match ty.table64 {
2127            false => IndexType::I32,
2128            true => IndexType::I64,
2129        };
2130        let limits = Limits {
2131            min: ty.initial,
2132            max: ty.maximum,
2133        };
2134        Ok(Table {
2135            idx_type,
2136            limits,
2137            ref_type: self.convert_ref_type(ty.element_type)?,
2138        })
2139    }
2140
2141    fn convert_sub_type(&self, ty: &wasmparser::SubType) -> WasmResult<WasmSubType> {
2142        Ok(WasmSubType {
2143            is_final: ty.is_final,
2144            supertype: ty.supertype_idx.map(|i| self.lookup_type_index(i.unpack())),
2145            composite_type: self.convert_composite_type(&ty.composite_type)?,
2146        })
2147    }
2148
2149    fn convert_composite_type(
2150        &self,
2151        ty: &wasmparser::CompositeType,
2152    ) -> WasmResult<WasmCompositeType> {
2153        let inner = match &ty.inner {
2154            wasmparser::CompositeInnerType::Func(f) => {
2155                WasmCompositeInnerType::Func(self.convert_func_type(f)?)
2156            }
2157            wasmparser::CompositeInnerType::Array(a) => {
2158                WasmCompositeInnerType::Array(self.convert_array_type(a)?)
2159            }
2160            wasmparser::CompositeInnerType::Struct(s) => {
2161                WasmCompositeInnerType::Struct(self.convert_struct_type(s)?)
2162            }
2163            wasmparser::CompositeInnerType::Cont(c) => {
2164                WasmCompositeInnerType::Cont(self.convert_cont_type(c))
2165            }
2166        };
2167        Ok(WasmCompositeType {
2168            inner,
2169            shared: ty.shared,
2170        })
2171    }
2172
2173    /// Converts a wasmparser continuation type to a wasmtime type
2174    fn convert_cont_type(&self, ty: &wasmparser::ContType) -> WasmContType {
2175        if let WasmHeapType::ConcreteFunc(sigidx) = self.lookup_heap_type(ty.0.unpack()) {
2176            WasmContType::new(sigidx)
2177        } else {
2178            panic!("Failed to extract signature index for continuation type.")
2179        }
2180    }
2181
2182    fn convert_struct_type(&self, ty: &wasmparser::StructType) -> WasmResult<WasmStructType> {
2183        Ok(WasmStructType {
2184            fields: ty
2185                .fields
2186                .iter()
2187                .map(|f| self.convert_field_type(f))
2188                .collect::<WasmResult<_>>()?,
2189        })
2190    }
2191
2192    fn convert_array_type(&self, ty: &wasmparser::ArrayType) -> WasmResult<WasmArrayType> {
2193        Ok(WasmArrayType(self.convert_field_type(&ty.0)?))
2194    }
2195
2196    fn convert_field_type(&self, ty: &wasmparser::FieldType) -> WasmResult<WasmFieldType> {
2197        Ok(WasmFieldType {
2198            element_type: self.convert_storage_type(&ty.element_type)?,
2199            mutable: ty.mutable,
2200        })
2201    }
2202
2203    fn convert_storage_type(&self, ty: &wasmparser::StorageType) -> WasmResult<WasmStorageType> {
2204        Ok(match ty {
2205            wasmparser::StorageType::I8 => WasmStorageType::I8,
2206            wasmparser::StorageType::I16 => WasmStorageType::I16,
2207            wasmparser::StorageType::Val(v) => WasmStorageType::Val(self.convert_valtype(*v)?),
2208        })
2209    }
2210
2211    /// Converts a wasmparser function type to a wasmtime type
2212    fn convert_func_type(&self, ty: &wasmparser::FuncType) -> WasmResult<WasmFuncType> {
2213        let params = ty
2214            .params()
2215            .iter()
2216            .map(|t| self.convert_valtype(*t))
2217            .collect::<WasmResult<_>>()?;
2218        let results = ty
2219            .results()
2220            .iter()
2221            .map(|t| self.convert_valtype(*t))
2222            .collect::<WasmResult<_>>()?;
2223        Ok(WasmFuncType::new(params, results))
2224    }
2225
2226    /// Converts a wasmparser value type to a wasmtime type
2227    fn convert_valtype(&self, ty: wasmparser::ValType) -> WasmResult<WasmValType> {
2228        Ok(match ty {
2229            wasmparser::ValType::I32 => WasmValType::I32,
2230            wasmparser::ValType::I64 => WasmValType::I64,
2231            wasmparser::ValType::F32 => WasmValType::F32,
2232            wasmparser::ValType::F64 => WasmValType::F64,
2233            wasmparser::ValType::V128 => WasmValType::V128,
2234            wasmparser::ValType::Ref(t) => WasmValType::Ref(self.convert_ref_type(t)?),
2235        })
2236    }
2237
2238    /// Converts a wasmparser reference type to a wasmtime type
2239    fn convert_ref_type(&self, ty: wasmparser::RefType) -> WasmResult<WasmRefType> {
2240        Ok(WasmRefType {
2241            nullable: ty.is_nullable(),
2242            heap_type: self.convert_heap_type(ty.heap_type())?,
2243        })
2244    }
2245
2246    /// Converts a wasmparser heap type to a wasmtime type
2247    fn convert_heap_type(&self, ty: wasmparser::HeapType) -> WasmResult<WasmHeapType> {
2248        Ok(match ty {
2249            wasmparser::HeapType::Concrete(i) => self.lookup_heap_type(i),
2250            wasmparser::HeapType::Abstract { ty, shared: false } => match ty {
2251                wasmparser::AbstractHeapType::Extern => WasmHeapType::Extern,
2252                wasmparser::AbstractHeapType::NoExtern => WasmHeapType::NoExtern,
2253                wasmparser::AbstractHeapType::Func => WasmHeapType::Func,
2254                wasmparser::AbstractHeapType::NoFunc => WasmHeapType::NoFunc,
2255                wasmparser::AbstractHeapType::Any => WasmHeapType::Any,
2256                wasmparser::AbstractHeapType::Eq => WasmHeapType::Eq,
2257                wasmparser::AbstractHeapType::I31 => WasmHeapType::I31,
2258                wasmparser::AbstractHeapType::Array => WasmHeapType::Array,
2259                wasmparser::AbstractHeapType::Struct => WasmHeapType::Struct,
2260                wasmparser::AbstractHeapType::None => WasmHeapType::None,
2261                wasmparser::AbstractHeapType::Cont => WasmHeapType::Cont,
2262                wasmparser::AbstractHeapType::NoCont => WasmHeapType::NoCont,
2263                wasmparser::AbstractHeapType::Exn | wasmparser::AbstractHeapType::NoExn => {
2264                    return Err(wasm_unsupported!("unsupported heap type {ty:?}"));
2265                }
2266            },
2267            _ => return Err(wasm_unsupported!("unsupported heap type {ty:?}")),
2268        })
2269    }
2270
2271    /// Converts the specified type index from a heap type into a canonicalized
2272    /// heap type.
2273    fn lookup_heap_type(&self, index: wasmparser::UnpackedIndex) -> WasmHeapType;
2274
2275    /// Converts the specified type index from a heap type into a canonicalized
2276    /// heap type.
2277    fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex;
2278}