wasmtime_environ/
types.rs

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