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