wasmtime_types/
lib.rs

1//! Internal dependency of Wasmtime and Cranelift that defines types for
2//! WebAssembly.
3
4#![no_std]
5
6extern crate alloc;
7#[cfg(feature = "std")]
8extern crate std;
9
10pub use wasmparser;
11
12#[doc(hidden)]
13pub use alloc::format as __format;
14
15pub mod prelude;
16
17use alloc::borrow::Cow;
18use alloc::boxed::Box;
19use core::{fmt, ops::Range};
20use cranelift_entity::entity_impl;
21use serde_derive::{Deserialize, Serialize};
22use smallvec::SmallVec;
23
24mod error;
25pub use error::*;
26
27/// A trait for things that can trace all type-to-type edges, aka all type
28/// indices within this thing.
29pub trait TypeTrace {
30    /// Visit each edge.
31    ///
32    /// The function can break out of tracing by returning `Err(E)`.
33    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
34    where
35        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>;
36
37    /// Visit each edge, mutably.
38    ///
39    /// Allows updating edges.
40    ///
41    /// The function can break out of tracing by returning `Err(E)`.
42    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
43    where
44        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>;
45
46    /// Trace all `VMSharedTypeIndex` edges, ignoring other edges.
47    fn trace_engine_indices<F, E>(&self, func: &mut F) -> Result<(), E>
48    where
49        F: FnMut(VMSharedTypeIndex) -> Result<(), E>,
50    {
51        self.trace(&mut |idx| match idx {
52            EngineOrModuleTypeIndex::Engine(idx) => func(idx),
53            EngineOrModuleTypeIndex::Module(_) | EngineOrModuleTypeIndex::RecGroup(_) => Ok(()),
54        })
55    }
56
57    /// Canonicalize `self` by rewriting all type references inside `self` from
58    /// module-level interned type indices to engine-level interned type
59    /// indices.
60    ///
61    /// This produces types that are suitable for usage by the runtime (only
62    /// contains `VMSharedTypeIndex` type references).
63    ///
64    /// This does not produce types that are suitable for hash consing types
65    /// (must have recgroup-relative indices for type indices referencing other
66    /// types in the same recgroup).
67    fn canonicalize_for_runtime_usage<F>(&mut self, module_to_engine: &mut F)
68    where
69        F: FnMut(ModuleInternedTypeIndex) -> VMSharedTypeIndex,
70    {
71        self.trace_mut::<_, ()>(&mut |idx| match idx {
72            EngineOrModuleTypeIndex::Engine(_) => Ok(()),
73            EngineOrModuleTypeIndex::Module(module_index) => {
74                let engine_index = module_to_engine(*module_index);
75                *idx = EngineOrModuleTypeIndex::Engine(engine_index);
76                Ok(())
77            }
78            EngineOrModuleTypeIndex::RecGroup(_) => {
79                panic!("should not already be canonicalized for hash consing")
80            }
81        })
82        .unwrap()
83    }
84
85    /// Is this type canonicalized for runtime usage?
86    fn is_canonicalized_for_runtime_usage(&self) -> bool {
87        self.trace(&mut |idx| match idx {
88            EngineOrModuleTypeIndex::Engine(_) => Ok(()),
89            EngineOrModuleTypeIndex::Module(_) | EngineOrModuleTypeIndex::RecGroup(_) => Err(()),
90        })
91        .is_ok()
92    }
93
94    /// Canonicalize `self` by rewriting all type references inside `self` from
95    /// module-level interned type indices to either engine-level interned type
96    /// indices or recgroup-relative indices.
97    ///
98    /// This produces types that are suitable for hash consing and deduplicating
99    /// recgroups (types may have recgroup-relative indices for references to
100    /// other types within the same recgroup).
101    ///
102    /// This does *not* produce types that are suitable for usage by the runtime
103    /// (only contain `VMSharedTypeIndex` type references).
104    fn canonicalize_for_hash_consing<F>(
105        &mut self,
106        rec_group_range: Range<ModuleInternedTypeIndex>,
107        module_to_engine: &mut F,
108    ) where
109        F: FnMut(ModuleInternedTypeIndex) -> VMSharedTypeIndex,
110    {
111        self.trace_mut::<_, ()>(&mut |idx| match *idx {
112            EngineOrModuleTypeIndex::Engine(_) => Ok(()),
113            EngineOrModuleTypeIndex::Module(module_index) => {
114                *idx = if rec_group_range.start <= module_index {
115                    // Any module index within the recursion group gets
116                    // translated into a recgroup-relative index.
117                    debug_assert!(module_index < rec_group_range.end);
118                    let relative = module_index.as_u32() - rec_group_range.start.as_u32();
119                    let relative = RecGroupRelativeTypeIndex::from_u32(relative);
120                    EngineOrModuleTypeIndex::RecGroup(relative)
121                } else {
122                    // Cross-group indices are translated directly into
123                    // `VMSharedTypeIndex`es.
124                    debug_assert!(module_index < rec_group_range.start);
125                    EngineOrModuleTypeIndex::Engine(module_to_engine(module_index))
126                };
127                Ok(())
128            }
129            EngineOrModuleTypeIndex::RecGroup(_) => {
130                panic!("should not already be canonicalized for hash consing")
131            }
132        })
133        .unwrap()
134    }
135
136    /// Is this type canonicalized for hash consing?
137    fn is_canonicalized_for_hash_consing(&self) -> bool {
138        self.trace(&mut |idx| match idx {
139            EngineOrModuleTypeIndex::Engine(_) | EngineOrModuleTypeIndex::RecGroup(_) => Ok(()),
140            EngineOrModuleTypeIndex::Module(_) => Err(()),
141        })
142        .is_ok()
143    }
144}
145
146/// WebAssembly value type -- equivalent of `wasmparser::ValType`.
147#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
148pub enum WasmValType {
149    /// I32 type
150    I32,
151    /// I64 type
152    I64,
153    /// F32 type
154    F32,
155    /// F64 type
156    F64,
157    /// V128 type
158    V128,
159    /// Reference type
160    Ref(WasmRefType),
161}
162
163impl fmt::Display for WasmValType {
164    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
165        match self {
166            WasmValType::I32 => write!(f, "i32"),
167            WasmValType::I64 => write!(f, "i64"),
168            WasmValType::F32 => write!(f, "f32"),
169            WasmValType::F64 => write!(f, "f64"),
170            WasmValType::V128 => write!(f, "v128"),
171            WasmValType::Ref(rt) => write!(f, "{rt}"),
172        }
173    }
174}
175
176impl TypeTrace for WasmValType {
177    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
178    where
179        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
180    {
181        match self {
182            WasmValType::Ref(r) => r.trace(func),
183            WasmValType::I32
184            | WasmValType::I64
185            | WasmValType::F32
186            | WasmValType::F64
187            | WasmValType::V128 => Ok(()),
188        }
189    }
190
191    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
192    where
193        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
194    {
195        match self {
196            WasmValType::Ref(r) => r.trace_mut(func),
197            WasmValType::I32
198            | WasmValType::I64
199            | WasmValType::F32
200            | WasmValType::F64
201            | WasmValType::V128 => Ok(()),
202        }
203    }
204}
205
206impl WasmValType {
207    /// Is this a type that is represented as a `VMGcRef`?
208    #[inline]
209    pub fn is_vmgcref_type(&self) -> bool {
210        match self {
211            WasmValType::Ref(r) => r.is_vmgcref_type(),
212            _ => false,
213        }
214    }
215
216    /// Is this a type that is represented as a `VMGcRef` and is additionally
217    /// not an `i31`?
218    ///
219    /// That is, is this a a type that actually refers to an object allocated in
220    /// a GC heap?
221    #[inline]
222    pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
223        match self {
224            WasmValType::Ref(r) => r.is_vmgcref_type_and_not_i31(),
225            _ => false,
226        }
227    }
228
229    fn trampoline_type(&self) -> Self {
230        match self {
231            WasmValType::Ref(r) => WasmValType::Ref(WasmRefType {
232                nullable: true,
233                heap_type: r.heap_type.top().into(),
234            }),
235            WasmValType::I32
236            | WasmValType::I64
237            | WasmValType::F32
238            | WasmValType::F64
239            | WasmValType::V128 => *self,
240        }
241    }
242}
243
244/// WebAssembly reference type -- equivalent of `wasmparser`'s RefType
245#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
246pub struct WasmRefType {
247    pub nullable: bool,
248    pub heap_type: WasmHeapType,
249}
250
251impl TypeTrace for WasmRefType {
252    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
253    where
254        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
255    {
256        self.heap_type.trace(func)
257    }
258
259    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
260    where
261        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
262    {
263        self.heap_type.trace_mut(func)
264    }
265}
266
267impl WasmRefType {
268    pub const EXTERNREF: WasmRefType = WasmRefType {
269        nullable: true,
270        heap_type: WasmHeapType::Extern,
271    };
272    pub const FUNCREF: WasmRefType = WasmRefType {
273        nullable: true,
274        heap_type: WasmHeapType::Func,
275    };
276
277    /// Is this a type that is represented as a `VMGcRef`?
278    #[inline]
279    pub fn is_vmgcref_type(&self) -> bool {
280        self.heap_type.is_vmgcref_type()
281    }
282
283    /// Is this a type that is represented as a `VMGcRef` and is additionally
284    /// not an `i31`?
285    ///
286    /// That is, is this a a type that actually refers to an object allocated in
287    /// a GC heap?
288    #[inline]
289    pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
290        self.heap_type.is_vmgcref_type_and_not_i31()
291    }
292}
293
294impl fmt::Display for WasmRefType {
295    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
296        match *self {
297            Self::FUNCREF => write!(f, "funcref"),
298            Self::EXTERNREF => write!(f, "externref"),
299            _ => {
300                if self.nullable {
301                    write!(f, "(ref null {})", self.heap_type)
302                } else {
303                    write!(f, "(ref {})", self.heap_type)
304                }
305            }
306        }
307    }
308}
309
310/// An interned type index, either at the module or engine level.
311///
312/// Roughly equivalent to `wasmparser::UnpackedIndex`, although doesn't have to
313/// concern itself with recursion-group-local indices.
314#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
315pub enum EngineOrModuleTypeIndex {
316    /// An index within an engine, canonicalized among all modules that can
317    /// interact with each other.
318    Engine(VMSharedTypeIndex),
319
320    /// An index within the current Wasm module, canonicalized within just this
321    /// current module.
322    Module(ModuleInternedTypeIndex),
323
324    /// An index within the containing type's rec group. This is only used when
325    /// hashing and canonicalizing rec groups, and should never appear outside
326    /// of the engine's type registry.
327    RecGroup(RecGroupRelativeTypeIndex),
328}
329
330impl From<ModuleInternedTypeIndex> for EngineOrModuleTypeIndex {
331    #[inline]
332    fn from(i: ModuleInternedTypeIndex) -> Self {
333        Self::Module(i)
334    }
335}
336
337impl From<VMSharedTypeIndex> for EngineOrModuleTypeIndex {
338    #[inline]
339    fn from(i: VMSharedTypeIndex) -> Self {
340        Self::Engine(i)
341    }
342}
343
344impl From<RecGroupRelativeTypeIndex> for EngineOrModuleTypeIndex {
345    #[inline]
346    fn from(i: RecGroupRelativeTypeIndex) -> Self {
347        Self::RecGroup(i)
348    }
349}
350
351impl fmt::Display for EngineOrModuleTypeIndex {
352    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
353        match self {
354            Self::Engine(i) => write!(f, "(engine {})", i.bits()),
355            Self::Module(i) => write!(f, "(module {})", i.as_u32()),
356            Self::RecGroup(i) => write!(f, "(recgroup {})", i.as_u32()),
357        }
358    }
359}
360
361impl EngineOrModuleTypeIndex {
362    /// Is this an engine-level type index?
363    pub fn is_engine_type_index(self) -> bool {
364        matches!(self, Self::Engine(_))
365    }
366
367    /// Get the underlying engine-level type index, if any.
368    pub fn as_engine_type_index(self) -> Option<VMSharedTypeIndex> {
369        match self {
370            Self::Engine(e) => Some(e),
371            Self::RecGroup(_) | Self::Module(_) => None,
372        }
373    }
374
375    /// Get the underlying engine-level type index, or panic.
376    pub fn unwrap_engine_type_index(self) -> VMSharedTypeIndex {
377        self.as_engine_type_index()
378            .unwrap_or_else(|| panic!("`unwrap_engine_type_index` on {self:?}"))
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    pub fn unwrap_module_type_index(self) -> ModuleInternedTypeIndex {
396        self.as_module_type_index()
397            .unwrap_or_else(|| panic!("`unwrap_module_type_index` on {self:?}"))
398    }
399
400    /// Is this an recgroup-level type index?
401    pub fn is_rec_group_type_index(self) -> bool {
402        matches!(self, Self::RecGroup(_))
403    }
404
405    /// Get the underlying recgroup-level type index, if any.
406    pub fn as_rec_group_type_index(self) -> Option<RecGroupRelativeTypeIndex> {
407        match self {
408            Self::RecGroup(r) => Some(r),
409            Self::Module(_) | Self::Engine(_) => None,
410        }
411    }
412
413    /// Get the underlying module-level type index, or panic.
414    pub fn unwrap_rec_group_type_index(self) -> RecGroupRelativeTypeIndex {
415        self.as_rec_group_type_index()
416            .unwrap_or_else(|| panic!("`unwrap_rec_group_type_index` on {self:?}"))
417    }
418}
419
420/// WebAssembly heap type -- equivalent of `wasmparser`'s HeapType
421#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
422pub enum WasmHeapType {
423    // External types.
424    Extern,
425    NoExtern,
426
427    // Function types.
428    Func,
429    ConcreteFunc(EngineOrModuleTypeIndex),
430    NoFunc,
431
432    // Internal types.
433    Any,
434    Eq,
435    I31,
436    Array,
437    ConcreteArray(EngineOrModuleTypeIndex),
438    Struct,
439    ConcreteStruct(EngineOrModuleTypeIndex),
440    None,
441}
442
443impl From<WasmHeapTopType> for WasmHeapType {
444    #[inline]
445    fn from(value: WasmHeapTopType) -> Self {
446        match value {
447            WasmHeapTopType::Extern => Self::Extern,
448            WasmHeapTopType::Any => Self::Any,
449            WasmHeapTopType::Func => Self::Func,
450        }
451    }
452}
453
454impl fmt::Display for WasmHeapType {
455    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
456        match self {
457            Self::Extern => write!(f, "extern"),
458            Self::NoExtern => write!(f, "noextern"),
459            Self::Func => write!(f, "func"),
460            Self::ConcreteFunc(i) => write!(f, "func {i}"),
461            Self::NoFunc => write!(f, "nofunc"),
462            Self::Any => write!(f, "any"),
463            Self::Eq => write!(f, "eq"),
464            Self::I31 => write!(f, "i31"),
465            Self::Array => write!(f, "array"),
466            Self::ConcreteArray(i) => write!(f, "array {i}"),
467            Self::Struct => write!(f, "struct"),
468            Self::ConcreteStruct(i) => write!(f, "struct {i}"),
469            Self::None => write!(f, "none"),
470        }
471    }
472}
473
474impl TypeTrace for WasmHeapType {
475    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
476    where
477        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
478    {
479        match *self {
480            Self::ConcreteArray(i) => func(i),
481            Self::ConcreteFunc(i) => func(i),
482            Self::ConcreteStruct(i) => func(i),
483            _ => Ok(()),
484        }
485    }
486
487    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
488    where
489        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
490    {
491        match self {
492            Self::ConcreteArray(i) => func(i),
493            Self::ConcreteFunc(i) => func(i),
494            Self::ConcreteStruct(i) => func(i),
495            _ => Ok(()),
496        }
497    }
498}
499
500impl WasmHeapType {
501    /// Is this a type that is represented as a `VMGcRef`?
502    #[inline]
503    pub fn is_vmgcref_type(&self) -> bool {
504        match self.top() {
505            // All `t <: (ref null any)` and `t <: (ref null extern)` are
506            // represented as `VMGcRef`s.
507            WasmHeapTopType::Any | WasmHeapTopType::Extern => true,
508
509            // All `t <: (ref null func)` are not.
510            WasmHeapTopType::Func => false,
511        }
512    }
513
514    /// Is this a type that is represented as a `VMGcRef` and is additionally
515    /// not an `i31`?
516    ///
517    /// That is, is this a a type that actually refers to an object allocated in
518    /// a GC heap?
519    #[inline]
520    pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
521        self.is_vmgcref_type() && *self != Self::I31
522    }
523
524    /// Get this type's top type.
525    #[inline]
526    pub fn top(&self) -> WasmHeapTopType {
527        match self {
528            WasmHeapType::Extern | WasmHeapType::NoExtern => WasmHeapTopType::Extern,
529
530            WasmHeapType::Func | WasmHeapType::ConcreteFunc(_) | WasmHeapType::NoFunc => {
531                WasmHeapTopType::Func
532            }
533
534            WasmHeapType::Any
535            | WasmHeapType::Eq
536            | WasmHeapType::I31
537            | WasmHeapType::Array
538            | WasmHeapType::ConcreteArray(_)
539            | WasmHeapType::Struct
540            | WasmHeapType::ConcreteStruct(_)
541            | WasmHeapType::None => WasmHeapTopType::Any,
542        }
543    }
544}
545
546/// A top heap type.
547#[derive(Debug, Clone, Copy, Eq, PartialEq)]
548pub enum WasmHeapTopType {
549    /// The common supertype of all external references.
550    Extern,
551    /// The common supertype of all internal references.
552    Any,
553    /// The common supertype of all function references.
554    Func,
555}
556
557/// WebAssembly function type -- equivalent of `wasmparser`'s FuncType.
558#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
559pub struct WasmFuncType {
560    params: Box<[WasmValType]>,
561    non_i31_gc_ref_params_count: usize,
562    returns: Box<[WasmValType]>,
563    non_i31_gc_ref_returns_count: usize,
564}
565
566impl fmt::Display for WasmFuncType {
567    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
568        write!(f, "(func")?;
569        if !self.params.is_empty() {
570            write!(f, " (param")?;
571            for p in self.params.iter() {
572                write!(f, " {p}")?;
573            }
574            write!(f, ")")?;
575        }
576        if !self.returns.is_empty() {
577            write!(f, " (result")?;
578            for r in self.returns.iter() {
579                write!(f, " {r}")?;
580            }
581            write!(f, ")")?;
582        }
583        write!(f, ")")
584    }
585}
586
587impl TypeTrace for WasmFuncType {
588    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
589    where
590        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
591    {
592        for p in self.params.iter() {
593            p.trace(func)?;
594        }
595        for r in self.returns.iter() {
596            r.trace(func)?;
597        }
598        Ok(())
599    }
600
601    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
602    where
603        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
604    {
605        for p in self.params.iter_mut() {
606            p.trace_mut(func)?;
607        }
608        for r in self.returns.iter_mut() {
609            r.trace_mut(func)?;
610        }
611        Ok(())
612    }
613}
614
615impl WasmFuncType {
616    #[inline]
617    pub fn new(params: Box<[WasmValType]>, returns: Box<[WasmValType]>) -> Self {
618        let non_i31_gc_ref_params_count = params
619            .iter()
620            .filter(|p| p.is_vmgcref_type_and_not_i31())
621            .count();
622        let non_i31_gc_ref_returns_count = returns
623            .iter()
624            .filter(|r| r.is_vmgcref_type_and_not_i31())
625            .count();
626        WasmFuncType {
627            params,
628            non_i31_gc_ref_params_count,
629            returns,
630            non_i31_gc_ref_returns_count,
631        }
632    }
633
634    /// Function params types.
635    #[inline]
636    pub fn params(&self) -> &[WasmValType] {
637        &self.params
638    }
639
640    /// How many `externref`s are in this function's params?
641    #[inline]
642    pub fn non_i31_gc_ref_params_count(&self) -> usize {
643        self.non_i31_gc_ref_params_count
644    }
645
646    /// Returns params types.
647    #[inline]
648    pub fn returns(&self) -> &[WasmValType] {
649        &self.returns
650    }
651
652    /// How many `externref`s are in this function's returns?
653    #[inline]
654    pub fn non_i31_gc_ref_returns_count(&self) -> usize {
655        self.non_i31_gc_ref_returns_count
656    }
657
658    /// Is this function type compatible with trampoline usage in Wasmtime?
659    pub fn is_trampoline_type(&self) -> bool {
660        self.params().iter().all(|p| *p == p.trampoline_type())
661            && self.returns().iter().all(|r| *r == r.trampoline_type())
662    }
663
664    /// Get the version of this function type that is suitable for usage as a
665    /// trampoline in Wasmtime.
666    ///
667    /// If this function is suitable for trampoline usage as-is, then a borrowed
668    /// `Cow` is returned. If it must be tweaked for trampoline usage, then an
669    /// owned `Cow` is returned.
670    ///
671    /// ## What is a trampoline type?
672    ///
673    /// All reference types in parameters and results are mapped to their
674    /// nullable top type, e.g. `(ref $my_struct_type)` becomes `(ref null
675    /// any)`.
676    ///
677    /// This allows us to share trampolines between functions whose signatures
678    /// both map to the same trampoline type. It also allows the host to satisfy
679    /// a Wasm module's function import of type `S` with a function of type `T`
680    /// where `T <: S`, even when the Wasm module never defines the type `T`
681    /// (and might never even be able to!)
682    ///
683    /// The flip side is that this adds a constraint to our trampolines: they
684    /// can only pass references around (e.g. move a reference from one calling
685    /// convention's location to another's) and may not actually inspect the
686    /// references themselves (unless the trampolines start doing explicit,
687    /// fallible downcasts, but if we ever need that, then we might want to
688    /// redesign this stuff).
689    pub fn trampoline_type(&self) -> Cow<'_, Self> {
690        if self.is_trampoline_type() {
691            return Cow::Borrowed(self);
692        }
693
694        Cow::Owned(Self::new(
695            self.params().iter().map(|p| p.trampoline_type()).collect(),
696            self.returns().iter().map(|r| r.trampoline_type()).collect(),
697        ))
698    }
699}
700
701/// Represents storage types introduced in the GC spec for array and struct fields.
702#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
703pub enum WasmStorageType {
704    /// The storage type is i8.
705    I8,
706    /// The storage type is i16.
707    I16,
708    /// The storage type is a value type.
709    Val(WasmValType),
710}
711
712impl fmt::Display for WasmStorageType {
713    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
714        match self {
715            WasmStorageType::I8 => write!(f, "i8"),
716            WasmStorageType::I16 => write!(f, "i16"),
717            WasmStorageType::Val(v) => fmt::Display::fmt(v, f),
718        }
719    }
720}
721
722impl TypeTrace for WasmStorageType {
723    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
724    where
725        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
726    {
727        match self {
728            WasmStorageType::I8 | WasmStorageType::I16 => Ok(()),
729            WasmStorageType::Val(v) => v.trace(func),
730        }
731    }
732
733    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
734    where
735        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
736    {
737        match self {
738            WasmStorageType::I8 | WasmStorageType::I16 => Ok(()),
739            WasmStorageType::Val(v) => v.trace_mut(func),
740        }
741    }
742}
743
744/// The type of a struct field or array element.
745#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
746pub struct WasmFieldType {
747    /// The field's element type.
748    pub element_type: WasmStorageType,
749
750    /// Whether this field can be mutated or not.
751    pub mutable: bool,
752}
753
754impl fmt::Display for WasmFieldType {
755    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
756        if self.mutable {
757            write!(f, "(mut {})", self.element_type)
758        } else {
759            fmt::Display::fmt(&self.element_type, f)
760        }
761    }
762}
763
764impl TypeTrace for WasmFieldType {
765    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
766    where
767        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
768    {
769        self.element_type.trace(func)
770    }
771
772    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
773    where
774        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
775    {
776        self.element_type.trace_mut(func)
777    }
778}
779
780/// A concrete array type.
781#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
782pub struct WasmArrayType(pub WasmFieldType);
783
784impl fmt::Display for WasmArrayType {
785    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
786        write!(f, "(array {})", self.0)
787    }
788}
789
790impl TypeTrace for WasmArrayType {
791    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
792    where
793        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
794    {
795        self.0.trace(func)
796    }
797
798    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
799    where
800        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
801    {
802        self.0.trace_mut(func)
803    }
804}
805
806/// A concrete struct type.
807#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
808pub struct WasmStructType {
809    pub fields: Box<[WasmFieldType]>,
810}
811
812impl fmt::Display for WasmStructType {
813    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
814        write!(f, "(struct")?;
815        for ty in self.fields.iter() {
816            write!(f, " {ty}")?;
817        }
818        write!(f, ")")
819    }
820}
821
822impl TypeTrace for WasmStructType {
823    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
824    where
825        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
826    {
827        for f in self.fields.iter() {
828            f.trace(func)?;
829        }
830        Ok(())
831    }
832
833    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
834    where
835        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
836    {
837        for f in self.fields.iter_mut() {
838            f.trace_mut(func)?;
839        }
840        Ok(())
841    }
842}
843
844/// A function, array, or struct type.
845#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
846pub enum WasmCompositeType {
847    Array(WasmArrayType),
848    Func(WasmFuncType),
849    Struct(WasmStructType),
850}
851
852impl fmt::Display for WasmCompositeType {
853    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
854        match self {
855            WasmCompositeType::Array(ty) => fmt::Display::fmt(ty, f),
856            WasmCompositeType::Func(ty) => fmt::Display::fmt(ty, f),
857            WasmCompositeType::Struct(ty) => fmt::Display::fmt(ty, f),
858        }
859    }
860}
861
862impl WasmCompositeType {
863    #[inline]
864    pub fn is_array(&self) -> bool {
865        matches!(self, Self::Array(_))
866    }
867
868    #[inline]
869    pub fn as_array(&self) -> Option<&WasmArrayType> {
870        match self {
871            WasmCompositeType::Array(f) => Some(f),
872            _ => None,
873        }
874    }
875
876    #[inline]
877    pub fn unwrap_array(&self) -> &WasmArrayType {
878        self.as_array().unwrap()
879    }
880
881    #[inline]
882    pub fn is_func(&self) -> bool {
883        matches!(self, Self::Func(_))
884    }
885
886    #[inline]
887    pub fn as_func(&self) -> Option<&WasmFuncType> {
888        match self {
889            WasmCompositeType::Func(f) => Some(f),
890            _ => None,
891        }
892    }
893
894    #[inline]
895    pub fn unwrap_func(&self) -> &WasmFuncType {
896        self.as_func().unwrap()
897    }
898
899    #[inline]
900    pub fn is_struct(&self) -> bool {
901        matches!(self, Self::Struct(_))
902    }
903
904    #[inline]
905    pub fn as_struct(&self) -> Option<&WasmStructType> {
906        match self {
907            WasmCompositeType::Struct(f) => Some(f),
908            _ => None,
909        }
910    }
911
912    #[inline]
913    pub fn unwrap_struct(&self) -> &WasmStructType {
914        self.as_struct().unwrap()
915    }
916}
917
918impl TypeTrace for WasmCompositeType {
919    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
920    where
921        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
922    {
923        match self {
924            WasmCompositeType::Array(a) => a.trace(func),
925            WasmCompositeType::Func(f) => f.trace(func),
926            WasmCompositeType::Struct(a) => a.trace(func),
927        }
928    }
929
930    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
931    where
932        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
933    {
934        match self {
935            WasmCompositeType::Array(a) => a.trace_mut(func),
936            WasmCompositeType::Func(f) => f.trace_mut(func),
937            WasmCompositeType::Struct(a) => a.trace_mut(func),
938        }
939    }
940}
941
942/// A concrete, user-defined (or host-defined) Wasm type.
943#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
944pub struct WasmSubType {
945    /// Whether this type is forbidden from being the supertype of any other
946    /// type.
947    pub is_final: bool,
948
949    /// This type's supertype, if any.
950    pub supertype: Option<EngineOrModuleTypeIndex>,
951
952    /// The array, function, or struct that is defined.
953    pub composite_type: WasmCompositeType,
954}
955
956impl fmt::Display for WasmSubType {
957    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
958        if self.is_final && self.supertype.is_none() {
959            fmt::Display::fmt(&self.composite_type, f)
960        } else {
961            write!(f, "(sub")?;
962            if self.is_final {
963                write!(f, " final")?;
964            }
965            if let Some(sup) = self.supertype {
966                write!(f, " {sup}")?;
967            }
968            write!(f, " {})", self.composite_type)
969        }
970    }
971}
972
973impl WasmSubType {
974    #[inline]
975    pub fn is_func(&self) -> bool {
976        self.composite_type.is_func()
977    }
978
979    #[inline]
980    pub fn as_func(&self) -> Option<&WasmFuncType> {
981        self.composite_type.as_func()
982    }
983
984    #[inline]
985    pub fn unwrap_func(&self) -> &WasmFuncType {
986        self.composite_type.unwrap_func()
987    }
988
989    #[inline]
990    pub fn is_array(&self) -> bool {
991        self.composite_type.is_array()
992    }
993
994    #[inline]
995    pub fn as_array(&self) -> Option<&WasmArrayType> {
996        self.composite_type.as_array()
997    }
998
999    #[inline]
1000    pub fn unwrap_array(&self) -> &WasmArrayType {
1001        self.composite_type.unwrap_array()
1002    }
1003
1004    #[inline]
1005    pub fn is_struct(&self) -> bool {
1006        self.composite_type.is_struct()
1007    }
1008
1009    #[inline]
1010    pub fn as_struct(&self) -> Option<&WasmStructType> {
1011        self.composite_type.as_struct()
1012    }
1013
1014    #[inline]
1015    pub fn unwrap_struct(&self) -> &WasmStructType {
1016        self.composite_type.unwrap_struct()
1017    }
1018}
1019
1020impl TypeTrace for WasmSubType {
1021    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1022    where
1023        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1024    {
1025        if let Some(sup) = self.supertype {
1026            func(sup)?;
1027        }
1028        self.composite_type.trace(func)
1029    }
1030
1031    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1032    where
1033        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1034    {
1035        if let Some(sup) = self.supertype.as_mut() {
1036            func(sup)?;
1037        }
1038        self.composite_type.trace_mut(func)
1039    }
1040}
1041
1042/// A recursive type group.
1043///
1044/// Types within a recgroup can have forward references to each other, which
1045/// allows for cyclic types, for example a function `$f` that returns a
1046/// reference to a function `$g` which returns a reference to a function `$f`:
1047///
1048/// ```ignore
1049/// (rec (type (func $f (result (ref null $g))))
1050///      (type (func $g (result (ref null $f)))))
1051/// ```
1052#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1053pub struct WasmRecGroup {
1054    /// The types inside of this recgroup.
1055    pub types: Box<[WasmSubType]>,
1056}
1057
1058impl TypeTrace for WasmRecGroup {
1059    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1060    where
1061        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1062    {
1063        for ty in self.types.iter() {
1064            ty.trace(func)?;
1065        }
1066        Ok(())
1067    }
1068
1069    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1070    where
1071        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1072    {
1073        for ty in self.types.iter_mut() {
1074            ty.trace_mut(func)?;
1075        }
1076        Ok(())
1077    }
1078}
1079
1080/// Index type of a function (imported or defined) inside the WebAssembly module.
1081#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1082pub struct FuncIndex(u32);
1083entity_impl!(FuncIndex);
1084
1085/// Index type of a defined function inside the WebAssembly module.
1086#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1087pub struct DefinedFuncIndex(u32);
1088entity_impl!(DefinedFuncIndex);
1089
1090/// Index type of a defined table inside the WebAssembly module.
1091#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1092pub struct DefinedTableIndex(u32);
1093entity_impl!(DefinedTableIndex);
1094
1095/// Index type of a defined memory inside the WebAssembly module.
1096#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1097pub struct DefinedMemoryIndex(u32);
1098entity_impl!(DefinedMemoryIndex);
1099
1100/// Index type of a defined memory inside the WebAssembly module.
1101#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1102pub struct OwnedMemoryIndex(u32);
1103entity_impl!(OwnedMemoryIndex);
1104
1105/// Index type of a defined global inside the WebAssembly module.
1106#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1107pub struct DefinedGlobalIndex(u32);
1108entity_impl!(DefinedGlobalIndex);
1109
1110/// Index type of a table (imported or defined) inside the WebAssembly module.
1111#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1112pub struct TableIndex(u32);
1113entity_impl!(TableIndex);
1114
1115/// Index type of a global variable (imported or defined) inside the WebAssembly module.
1116#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1117pub struct GlobalIndex(u32);
1118entity_impl!(GlobalIndex);
1119
1120/// Index type of a linear memory (imported or defined) inside the WebAssembly module.
1121#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1122pub struct MemoryIndex(u32);
1123entity_impl!(MemoryIndex);
1124
1125/// Index type of a canonicalized recursive type group inside a WebAssembly
1126/// module (as opposed to canonicalized within the whole engine).
1127#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1128pub struct ModuleInternedRecGroupIndex(u32);
1129entity_impl!(ModuleInternedRecGroupIndex);
1130
1131/// Index type of a canonicalized recursive type group inside the whole engine
1132/// (as opposed to canonicalized within just a single Wasm module).
1133#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1134pub struct EngineInternedRecGroupIndex(u32);
1135entity_impl!(EngineInternedRecGroupIndex);
1136
1137/// Index type of a type (imported or defined) inside the WebAssembly module.
1138#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1139pub struct TypeIndex(u32);
1140entity_impl!(TypeIndex);
1141
1142/// A canonicalized type index referencing a type within a single recursion
1143/// group from another type within that same recursion group.
1144///
1145/// This is only suitable for use when hash consing and deduplicating rec
1146/// groups.
1147#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1148pub struct RecGroupRelativeTypeIndex(u32);
1149entity_impl!(RecGroupRelativeTypeIndex);
1150
1151/// A canonicalized type index for a type within a single WebAssembly module.
1152///
1153/// Note that this is deduplicated only at the level of a single WebAssembly
1154/// module, not at the level of a whole store or engine. This means that these
1155/// indices are only unique within the context of a single Wasm module, and
1156/// therefore are not suitable for runtime type checks (which, in general, may
1157/// involve entities defined in different modules).
1158#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1159pub struct ModuleInternedTypeIndex(u32);
1160entity_impl!(ModuleInternedTypeIndex);
1161
1162/// A canonicalized type index into an engine's shared type registry.
1163///
1164/// This is canonicalized/deduped at the level of a whole engine, across all the
1165/// modules loaded into that engine, not just at the level of a single
1166/// particular module. This means that `VMSharedTypeIndex` is usable for
1167/// e.g. checking that function signatures match during an indirect call
1168/// (potentially to a function defined in a different module) at runtime.
1169#[repr(transparent)] // Used directly by JIT code.
1170#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1171pub struct VMSharedTypeIndex(u32);
1172entity_impl!(VMSharedTypeIndex);
1173
1174impl VMSharedTypeIndex {
1175    /// Create a new `VMSharedTypeIndex`.
1176    #[inline]
1177    pub fn new(value: u32) -> Self {
1178        assert_ne!(
1179            value,
1180            u32::MAX,
1181            "u32::MAX is reserved for the default value"
1182        );
1183        Self(value)
1184    }
1185
1186    /// Returns the underlying bits of the index.
1187    #[inline]
1188    pub fn bits(&self) -> u32 {
1189        self.0
1190    }
1191}
1192
1193impl Default for VMSharedTypeIndex {
1194    #[inline]
1195    fn default() -> Self {
1196        Self(u32::MAX)
1197    }
1198}
1199
1200/// Index type of a passive data segment inside the WebAssembly module.
1201#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1202pub struct DataIndex(u32);
1203entity_impl!(DataIndex);
1204
1205/// Index type of a passive element segment inside the WebAssembly module.
1206#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1207pub struct ElemIndex(u32);
1208entity_impl!(ElemIndex);
1209
1210/// Index type of an event inside the WebAssembly module.
1211#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1212pub struct TagIndex(u32);
1213entity_impl!(TagIndex);
1214
1215/// Index into the global list of modules found within an entire component.
1216///
1217/// Module translations are saved on the side to get fully compiled after
1218/// the original component has finished being translated.
1219#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1220pub struct StaticModuleIndex(u32);
1221entity_impl!(StaticModuleIndex);
1222
1223/// An index of an entity.
1224#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1225pub enum EntityIndex {
1226    /// Function index.
1227    Function(FuncIndex),
1228    /// Table index.
1229    Table(TableIndex),
1230    /// Memory index.
1231    Memory(MemoryIndex),
1232    /// Global index.
1233    Global(GlobalIndex),
1234}
1235
1236impl From<FuncIndex> for EntityIndex {
1237    fn from(idx: FuncIndex) -> EntityIndex {
1238        EntityIndex::Function(idx)
1239    }
1240}
1241
1242impl From<TableIndex> for EntityIndex {
1243    fn from(idx: TableIndex) -> EntityIndex {
1244        EntityIndex::Table(idx)
1245    }
1246}
1247
1248impl From<MemoryIndex> for EntityIndex {
1249    fn from(idx: MemoryIndex) -> EntityIndex {
1250        EntityIndex::Memory(idx)
1251    }
1252}
1253
1254impl From<GlobalIndex> for EntityIndex {
1255    fn from(idx: GlobalIndex) -> EntityIndex {
1256        EntityIndex::Global(idx)
1257    }
1258}
1259
1260/// A type of an item in a wasm module where an item is typically something that
1261/// can be exported.
1262#[allow(missing_docs)]
1263#[derive(Clone, Debug, Serialize, Deserialize)]
1264pub enum EntityType {
1265    /// A global variable with the specified content type
1266    Global(Global),
1267    /// A linear memory with the specified limits
1268    Memory(Memory),
1269    /// An event definition.
1270    Tag(Tag),
1271    /// A table with the specified element type and limits
1272    Table(Table),
1273    /// A function type where the index points to the type section and records a
1274    /// function signature.
1275    Function(EngineOrModuleTypeIndex),
1276}
1277
1278impl TypeTrace for EntityType {
1279    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1280    where
1281        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1282    {
1283        match self {
1284            Self::Global(g) => g.trace(func),
1285            Self::Table(t) => t.trace(func),
1286            Self::Function(idx) => func(*idx),
1287            Self::Memory(_) | Self::Tag(_) => Ok(()),
1288        }
1289    }
1290
1291    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1292    where
1293        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1294    {
1295        match self {
1296            Self::Global(g) => g.trace_mut(func),
1297            Self::Table(t) => t.trace_mut(func),
1298            Self::Function(idx) => func(idx),
1299            Self::Memory(_) | Self::Tag(_) => Ok(()),
1300        }
1301    }
1302}
1303
1304impl EntityType {
1305    /// Assert that this entity is a global
1306    pub fn unwrap_global(&self) -> &Global {
1307        match self {
1308            EntityType::Global(g) => g,
1309            _ => panic!("not a global"),
1310        }
1311    }
1312
1313    /// Assert that this entity is a memory
1314    pub fn unwrap_memory(&self) -> &Memory {
1315        match self {
1316            EntityType::Memory(g) => g,
1317            _ => panic!("not a memory"),
1318        }
1319    }
1320
1321    /// Assert that this entity is a tag
1322    pub fn unwrap_tag(&self) -> &Tag {
1323        match self {
1324            EntityType::Tag(g) => g,
1325            _ => panic!("not a tag"),
1326        }
1327    }
1328
1329    /// Assert that this entity is a table
1330    pub fn unwrap_table(&self) -> &Table {
1331        match self {
1332            EntityType::Table(g) => g,
1333            _ => panic!("not a table"),
1334        }
1335    }
1336
1337    /// Assert that this entity is a function
1338    pub fn unwrap_func(&self) -> EngineOrModuleTypeIndex {
1339        match self {
1340            EntityType::Function(g) => *g,
1341            _ => panic!("not a func"),
1342        }
1343    }
1344}
1345
1346/// A WebAssembly global.
1347///
1348/// Note that we record both the original Wasm type and the Cranelift IR type
1349/// used to represent it. This is because multiple different kinds of Wasm types
1350/// might be represented with the same Cranelift IR type. For example, both a
1351/// Wasm `i64` and a `funcref` might be represented with a Cranelift `i64` on
1352/// 64-bit architectures, and when GC is not required for func refs.
1353#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1354pub struct Global {
1355    /// The Wasm type of the value stored in the global.
1356    pub wasm_ty: crate::WasmValType,
1357    /// A flag indicating whether the value may change at runtime.
1358    pub mutability: bool,
1359}
1360
1361impl TypeTrace for Global {
1362    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1363    where
1364        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1365    {
1366        let Global {
1367            wasm_ty,
1368            mutability: _,
1369        } = self;
1370        wasm_ty.trace(func)
1371    }
1372
1373    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1374    where
1375        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1376    {
1377        let Global {
1378            wasm_ty,
1379            mutability: _,
1380        } = self;
1381        wasm_ty.trace_mut(func)
1382    }
1383}
1384
1385/// A constant expression.
1386///
1387/// These are used to initialize globals, table elements, etc...
1388#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1389pub struct ConstExpr {
1390    ops: SmallVec<[ConstOp; 2]>,
1391}
1392
1393impl ConstExpr {
1394    /// Create a new const expression from the given opcodes.
1395    ///
1396    /// Does not do any validation that the const expression is well-typed.
1397    ///
1398    /// Panics if given zero opcodes.
1399    pub fn new(ops: impl IntoIterator<Item = ConstOp>) -> Self {
1400        let ops = ops.into_iter().collect::<SmallVec<[ConstOp; 2]>>();
1401        assert!(!ops.is_empty());
1402        ConstExpr { ops }
1403    }
1404
1405    /// Create a new const expression from a `wasmparser` const expression.
1406    ///
1407    /// Returns the new const expression as well as the escaping function
1408    /// indices that appeared in `ref.func` instructions, if any.
1409    pub fn from_wasmparser(
1410        expr: wasmparser::ConstExpr<'_>,
1411    ) -> WasmResult<(Self, SmallVec<[FuncIndex; 1]>)> {
1412        let mut iter = expr
1413            .get_operators_reader()
1414            .into_iter_with_offsets()
1415            .peekable();
1416
1417        let mut ops = SmallVec::<[ConstOp; 2]>::new();
1418        let mut escaped = SmallVec::<[FuncIndex; 1]>::new();
1419        while let Some(res) = iter.next() {
1420            let (op, offset) = res?;
1421
1422            // If we reach an `end` instruction, and there are no more
1423            // instructions after that, then we are done reading this const
1424            // expression.
1425            if matches!(op, wasmparser::Operator::End) && iter.peek().is_none() {
1426                break;
1427            }
1428
1429            // Track any functions that appear in `ref.func` so that callers can
1430            // make sure to flag them as escaping.
1431            if let wasmparser::Operator::RefFunc { function_index } = &op {
1432                escaped.push(FuncIndex::from_u32(*function_index));
1433            }
1434
1435            ops.push(ConstOp::from_wasmparser(op, offset)?);
1436        }
1437        Ok((Self { ops }, escaped))
1438    }
1439
1440    /// Get the opcodes that make up this const expression.
1441    pub fn ops(&self) -> &[ConstOp] {
1442        &self.ops
1443    }
1444
1445    /// Is this ConstExpr a provably nonzero integer value?
1446    ///
1447    /// This must be conservative: if the expression *might* be zero,
1448    /// it must return `false`. It is always allowed to return `false`
1449    /// for some expression kind that we don't support. However, if it
1450    /// returns `true`, the expression must be actually nonzero.
1451    ///
1452    /// We use this for certain table optimizations that rely on
1453    /// knowing for sure that index 0 is not referenced.
1454    pub fn provably_nonzero_i32(&self) -> bool {
1455        assert!(self.ops.len() > 0);
1456        if self.ops.len() > 1 {
1457            // Compound expressions not yet supported: conservatively
1458            // return `false` (we can't prove nonzero).
1459            return false;
1460        }
1461        // Exactly one op at this point.
1462        match self.ops[0] {
1463            // An actual zero value -- definitely not nonzero!
1464            ConstOp::I32Const(0) => false,
1465            // Any other constant value -- provably nonzero, if above
1466            // did not match.
1467            ConstOp::I32Const(_) => true,
1468            // Anything else: we can't prove anything.
1469            _ => false,
1470        }
1471    }
1472}
1473
1474/// The subset of Wasm opcodes that are constant.
1475#[allow(missing_docs)]
1476#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1477pub enum ConstOp {
1478    I32Const(i32),
1479    I64Const(i64),
1480    F32Const(u32),
1481    F64Const(u64),
1482    V128Const(u128),
1483    GlobalGet(GlobalIndex),
1484    RefI31,
1485    RefNull,
1486    RefFunc(FuncIndex),
1487    I32Add,
1488    I32Sub,
1489    I32Mul,
1490    I64Add,
1491    I64Sub,
1492    I64Mul,
1493}
1494
1495impl ConstOp {
1496    /// Convert a `wasmparser::Operator` to a `ConstOp`.
1497    pub fn from_wasmparser(op: wasmparser::Operator<'_>, offset: usize) -> WasmResult<Self> {
1498        use wasmparser::Operator as O;
1499        Ok(match op {
1500            O::I32Const { value } => Self::I32Const(value),
1501            O::I64Const { value } => Self::I64Const(value),
1502            O::F32Const { value } => Self::F32Const(value.bits()),
1503            O::F64Const { value } => Self::F64Const(value.bits()),
1504            O::V128Const { value } => Self::V128Const(u128::from_le_bytes(*value.bytes())),
1505            O::RefNull { hty: _ } => Self::RefNull,
1506            O::RefFunc { function_index } => Self::RefFunc(FuncIndex::from_u32(function_index)),
1507            O::GlobalGet { global_index } => Self::GlobalGet(GlobalIndex::from_u32(global_index)),
1508            O::RefI31 => Self::RefI31,
1509            O::I32Add => Self::I32Add,
1510            O::I32Sub => Self::I32Sub,
1511            O::I32Mul => Self::I32Mul,
1512            O::I64Add => Self::I64Add,
1513            O::I64Sub => Self::I64Sub,
1514            O::I64Mul => Self::I64Mul,
1515            op => {
1516                return Err(wasm_unsupported!(
1517                    "unsupported opcode in const expression at offset {offset:#x}: {op:?}",
1518                ));
1519            }
1520        })
1521    }
1522}
1523
1524/// WebAssembly table.
1525#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1526pub struct Table {
1527    /// The table elements' Wasm type.
1528    pub wasm_ty: WasmRefType,
1529    /// The minimum number of elements in the table.
1530    pub minimum: u32,
1531    /// The maximum number of elements in the table.
1532    pub maximum: Option<u32>,
1533}
1534
1535impl TypeTrace for Table {
1536    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1537    where
1538        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1539    {
1540        let Table {
1541            wasm_ty,
1542            minimum: _,
1543            maximum: _,
1544        } = self;
1545        wasm_ty.trace(func)
1546    }
1547
1548    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1549    where
1550        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1551    {
1552        let Table {
1553            wasm_ty,
1554            minimum: _,
1555            maximum: _,
1556        } = self;
1557        wasm_ty.trace_mut(func)
1558    }
1559}
1560
1561/// WebAssembly linear memory.
1562#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1563pub struct Memory {
1564    /// The minimum number of pages in the memory.
1565    pub minimum: u64,
1566    /// The maximum number of pages in the memory.
1567    pub maximum: Option<u64>,
1568    /// Whether the memory may be shared between multiple threads.
1569    pub shared: bool,
1570    /// Whether or not this is a 64-bit memory
1571    pub memory64: bool,
1572    /// The log2 of this memory's page size, in bytes.
1573    ///
1574    /// By default the page size is 64KiB (0x10000; 2**16; 1<<16; 65536) but the
1575    /// custom-page-sizes proposal allows opting into a page size of `1`.
1576    pub page_size_log2: u8,
1577}
1578
1579/// Maximum size, in bytes, of 32-bit memories (4G)
1580pub const WASM32_MAX_SIZE: u64 = 1 << 32;
1581
1582impl Memory {
1583    /// WebAssembly page sizes are 64KiB by default.
1584    pub const DEFAULT_PAGE_SIZE: u32 = 0x10000;
1585
1586    /// WebAssembly page sizes are 64KiB (or `2**16`) by default.
1587    pub const DEFAULT_PAGE_SIZE_LOG2: u8 = {
1588        let log2 = 16;
1589        assert!(1 << log2 == Memory::DEFAULT_PAGE_SIZE);
1590        log2
1591    };
1592
1593    /// Returns the minimum size, in bytes, that this memory must be.
1594    ///
1595    /// # Errors
1596    ///
1597    /// Returns an error if the calculation of the minimum size overflows the
1598    /// `u64` return type. This means that the memory can't be allocated but
1599    /// it's deferred to the caller to how to deal with that.
1600    pub fn minimum_byte_size(&self) -> Result<u64, SizeOverflow> {
1601        self.minimum
1602            .checked_mul(self.page_size())
1603            .ok_or(SizeOverflow)
1604    }
1605
1606    /// Returns the maximum size, in bytes, that this memory is allowed to be.
1607    ///
1608    /// Note that the return value here is not an `Option` despite the maximum
1609    /// size of a linear memory being optional in wasm. If a maximum size
1610    /// is not present in the memory's type then a maximum size is selected for
1611    /// it. For example the maximum size of a 32-bit memory is `1<<32`. The
1612    /// maximum size of a 64-bit linear memory is chosen to be a value that
1613    /// won't ever be allowed at runtime.
1614    ///
1615    /// # Errors
1616    ///
1617    /// Returns an error if the calculation of the maximum size overflows the
1618    /// `u64` return type. This means that the memory can't be allocated but
1619    /// it's deferred to the caller to how to deal with that.
1620    pub fn maximum_byte_size(&self) -> Result<u64, SizeOverflow> {
1621        match self.maximum {
1622            Some(max) => max.checked_mul(self.page_size()).ok_or(SizeOverflow),
1623            None => {
1624                let min = self.minimum_byte_size()?;
1625                Ok(min.max(self.max_size_based_on_index_type()))
1626            }
1627        }
1628    }
1629
1630    /// Get the size of this memory's pages, in bytes.
1631    pub fn page_size(&self) -> u64 {
1632        debug_assert!(
1633            self.page_size_log2 == 16 || self.page_size_log2 == 0,
1634            "invalid page_size_log2: {}; must be 16 or 0",
1635            self.page_size_log2
1636        );
1637        1 << self.page_size_log2
1638    }
1639
1640    /// Returns the maximum size memory is allowed to be only based on the
1641    /// index type used by this memory.
1642    ///
1643    /// For example 32-bit linear memories return `1<<32` from this method.
1644    pub fn max_size_based_on_index_type(&self) -> u64 {
1645        if self.memory64 {
1646            // Note that the true maximum size of a 64-bit linear memory, in
1647            // bytes, cannot be represented in a `u64`. That would require a u65
1648            // to store `1<<64`. Despite that no system can actually allocate a
1649            // full 64-bit linear memory so this is instead emulated as "what if
1650            // the kernel fit in a single Wasm page of linear memory". Shouldn't
1651            // ever actually be possible but it provides a number to serve as an
1652            // effective maximum.
1653            0_u64.wrapping_sub(self.page_size())
1654        } else {
1655            WASM32_MAX_SIZE
1656        }
1657    }
1658}
1659
1660#[derive(Copy, Clone, Debug)]
1661pub struct SizeOverflow;
1662
1663impl fmt::Display for SizeOverflow {
1664    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1665        f.write_str("size overflow calculating memory size")
1666    }
1667}
1668
1669#[cfg(feature = "std")]
1670impl std::error::Error for SizeOverflow {}
1671
1672impl From<wasmparser::MemoryType> for Memory {
1673    fn from(ty: wasmparser::MemoryType) -> Memory {
1674        let page_size_log2 = u8::try_from(ty.page_size_log2.unwrap_or(16)).unwrap();
1675        debug_assert!(
1676            page_size_log2 == 16 || page_size_log2 == 0,
1677            "invalid page_size_log2: {page_size_log2}; must be 16 or 0"
1678        );
1679        Memory {
1680            minimum: ty.initial,
1681            maximum: ty.maximum,
1682            shared: ty.shared,
1683            memory64: ty.memory64,
1684            page_size_log2,
1685        }
1686    }
1687}
1688
1689/// WebAssembly event.
1690#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1691pub struct Tag {
1692    /// The event signature type.
1693    pub ty: TypeIndex,
1694}
1695
1696impl From<wasmparser::TagType> for Tag {
1697    fn from(ty: wasmparser::TagType) -> Tag {
1698        match ty.kind {
1699            wasmparser::TagKind::Exception => Tag {
1700                ty: TypeIndex::from_u32(ty.func_type_idx),
1701            },
1702        }
1703    }
1704}
1705
1706/// Helpers used to convert a `wasmparser` type to a type in this crate.
1707pub trait TypeConvert {
1708    /// Converts a wasmparser table type into a wasmtime type
1709    fn convert_global_type(&self, ty: &wasmparser::GlobalType) -> Global {
1710        Global {
1711            wasm_ty: self.convert_valtype(ty.content_type),
1712            mutability: ty.mutable,
1713        }
1714    }
1715
1716    /// Converts a wasmparser table type into a wasmtime type
1717    fn convert_table_type(&self, ty: &wasmparser::TableType) -> WasmResult<Table> {
1718        if ty.table64 {
1719            return Err(wasm_unsupported!("wasm memory64: 64-bit table type"));
1720        }
1721        Ok(Table {
1722            wasm_ty: self.convert_ref_type(ty.element_type),
1723            minimum: ty.initial.try_into().unwrap(),
1724            maximum: ty.maximum.map(|i| i.try_into().unwrap()),
1725        })
1726    }
1727
1728    fn convert_sub_type(&self, ty: &wasmparser::SubType) -> WasmSubType {
1729        WasmSubType {
1730            is_final: ty.is_final,
1731            supertype: ty.supertype_idx.map(|i| self.lookup_type_index(i.unpack())),
1732            composite_type: self.convert_composite_type(&ty.composite_type),
1733        }
1734    }
1735
1736    fn convert_composite_type(&self, ty: &wasmparser::CompositeType) -> WasmCompositeType {
1737        assert!(!ty.shared);
1738        match &ty.inner {
1739            wasmparser::CompositeInnerType::Func(f) => {
1740                WasmCompositeType::Func(self.convert_func_type(f))
1741            }
1742            wasmparser::CompositeInnerType::Array(a) => {
1743                WasmCompositeType::Array(self.convert_array_type(a))
1744            }
1745            wasmparser::CompositeInnerType::Struct(s) => {
1746                WasmCompositeType::Struct(self.convert_struct_type(s))
1747            }
1748        }
1749    }
1750
1751    fn convert_struct_type(&self, ty: &wasmparser::StructType) -> WasmStructType {
1752        WasmStructType {
1753            fields: ty
1754                .fields
1755                .iter()
1756                .map(|f| self.convert_field_type(f))
1757                .collect(),
1758        }
1759    }
1760
1761    fn convert_array_type(&self, ty: &wasmparser::ArrayType) -> WasmArrayType {
1762        WasmArrayType(self.convert_field_type(&ty.0))
1763    }
1764
1765    fn convert_field_type(&self, ty: &wasmparser::FieldType) -> WasmFieldType {
1766        WasmFieldType {
1767            element_type: self.convert_storage_type(&ty.element_type),
1768            mutable: ty.mutable,
1769        }
1770    }
1771
1772    fn convert_storage_type(&self, ty: &wasmparser::StorageType) -> WasmStorageType {
1773        match ty {
1774            wasmparser::StorageType::I8 => WasmStorageType::I8,
1775            wasmparser::StorageType::I16 => WasmStorageType::I16,
1776            wasmparser::StorageType::Val(v) => WasmStorageType::Val(self.convert_valtype(*v)),
1777        }
1778    }
1779
1780    /// Converts a wasmparser function type to a wasmtime type
1781    fn convert_func_type(&self, ty: &wasmparser::FuncType) -> WasmFuncType {
1782        let params = ty
1783            .params()
1784            .iter()
1785            .map(|t| self.convert_valtype(*t))
1786            .collect();
1787        let results = ty
1788            .results()
1789            .iter()
1790            .map(|t| self.convert_valtype(*t))
1791            .collect();
1792        WasmFuncType::new(params, results)
1793    }
1794
1795    /// Converts a wasmparser value type to a wasmtime type
1796    fn convert_valtype(&self, ty: wasmparser::ValType) -> WasmValType {
1797        match ty {
1798            wasmparser::ValType::I32 => WasmValType::I32,
1799            wasmparser::ValType::I64 => WasmValType::I64,
1800            wasmparser::ValType::F32 => WasmValType::F32,
1801            wasmparser::ValType::F64 => WasmValType::F64,
1802            wasmparser::ValType::V128 => WasmValType::V128,
1803            wasmparser::ValType::Ref(t) => WasmValType::Ref(self.convert_ref_type(t)),
1804        }
1805    }
1806
1807    /// Converts a wasmparser reference type to a wasmtime type
1808    fn convert_ref_type(&self, ty: wasmparser::RefType) -> WasmRefType {
1809        WasmRefType {
1810            nullable: ty.is_nullable(),
1811            heap_type: self.convert_heap_type(ty.heap_type()),
1812        }
1813    }
1814
1815    /// Converts a wasmparser heap type to a wasmtime type
1816    fn convert_heap_type(&self, ty: wasmparser::HeapType) -> WasmHeapType {
1817        match ty {
1818            wasmparser::HeapType::Concrete(i) => self.lookup_heap_type(i),
1819            wasmparser::HeapType::Abstract { ty, shared: false } => match ty {
1820                wasmparser::AbstractHeapType::Extern => WasmHeapType::Extern,
1821                wasmparser::AbstractHeapType::NoExtern => WasmHeapType::NoExtern,
1822                wasmparser::AbstractHeapType::Func => WasmHeapType::Func,
1823                wasmparser::AbstractHeapType::NoFunc => WasmHeapType::NoFunc,
1824                wasmparser::AbstractHeapType::Any => WasmHeapType::Any,
1825                wasmparser::AbstractHeapType::Eq => WasmHeapType::Eq,
1826                wasmparser::AbstractHeapType::I31 => WasmHeapType::I31,
1827                wasmparser::AbstractHeapType::Array => WasmHeapType::Array,
1828                wasmparser::AbstractHeapType::Struct => WasmHeapType::Struct,
1829                wasmparser::AbstractHeapType::None => WasmHeapType::None,
1830
1831                wasmparser::AbstractHeapType::Exn | wasmparser::AbstractHeapType::NoExn => {
1832                    unimplemented!("unsupported heap type {ty:?}");
1833                }
1834            },
1835            _ => unimplemented!("unsupported heap type {ty:?}"),
1836        }
1837    }
1838
1839    /// Converts the specified type index from a heap type into a canonicalized
1840    /// heap type.
1841    fn lookup_heap_type(&self, index: wasmparser::UnpackedIndex) -> WasmHeapType;
1842
1843    /// Converts the specified type index from a heap type into a canonicalized
1844    /// heap type.
1845    fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex;
1846}