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}
1488
1489impl ConstOp {
1490    /// Convert a `wasmparser::Operator` to a `ConstOp`.
1491    pub fn from_wasmparser(op: wasmparser::Operator<'_>, offset: usize) -> WasmResult<Self> {
1492        use wasmparser::Operator as O;
1493        Ok(match op {
1494            O::I32Const { value } => Self::I32Const(value),
1495            O::I64Const { value } => Self::I64Const(value),
1496            O::F32Const { value } => Self::F32Const(value.bits()),
1497            O::F64Const { value } => Self::F64Const(value.bits()),
1498            O::V128Const { value } => Self::V128Const(u128::from_le_bytes(*value.bytes())),
1499            O::RefNull { hty: _ } => Self::RefNull,
1500            O::RefFunc { function_index } => Self::RefFunc(FuncIndex::from_u32(function_index)),
1501            O::GlobalGet { global_index } => Self::GlobalGet(GlobalIndex::from_u32(global_index)),
1502            O::RefI31 => Self::RefI31,
1503            op => {
1504                return Err(wasm_unsupported!(
1505                    "unsupported opcode in const expression at offset {offset:#x}: {op:?}",
1506                ));
1507            }
1508        })
1509    }
1510}
1511
1512/// WebAssembly table.
1513#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1514pub struct Table {
1515    /// The table elements' Wasm type.
1516    pub wasm_ty: WasmRefType,
1517    /// The minimum number of elements in the table.
1518    pub minimum: u32,
1519    /// The maximum number of elements in the table.
1520    pub maximum: Option<u32>,
1521}
1522
1523impl TypeTrace for Table {
1524    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1525    where
1526        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1527    {
1528        let Table {
1529            wasm_ty,
1530            minimum: _,
1531            maximum: _,
1532        } = self;
1533        wasm_ty.trace(func)
1534    }
1535
1536    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1537    where
1538        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1539    {
1540        let Table {
1541            wasm_ty,
1542            minimum: _,
1543            maximum: _,
1544        } = self;
1545        wasm_ty.trace_mut(func)
1546    }
1547}
1548
1549/// WebAssembly linear memory.
1550#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1551pub struct Memory {
1552    /// The minimum number of pages in the memory.
1553    pub minimum: u64,
1554    /// The maximum number of pages in the memory.
1555    pub maximum: Option<u64>,
1556    /// Whether the memory may be shared between multiple threads.
1557    pub shared: bool,
1558    /// Whether or not this is a 64-bit memory
1559    pub memory64: bool,
1560    /// The log2 of this memory's page size, in bytes.
1561    ///
1562    /// By default the page size is 64KiB (0x10000; 2**16; 1<<16; 65536) but the
1563    /// custom-page-sizes proposal allows opting into a page size of `1`.
1564    pub page_size_log2: u8,
1565}
1566
1567/// Maximum size, in bytes, of 32-bit memories (4G)
1568pub const WASM32_MAX_SIZE: u64 = 1 << 32;
1569
1570impl Memory {
1571    /// WebAssembly page sizes are 64KiB by default.
1572    pub const DEFAULT_PAGE_SIZE: u32 = 0x10000;
1573
1574    /// WebAssembly page sizes are 64KiB (or `2**16`) by default.
1575    pub const DEFAULT_PAGE_SIZE_LOG2: u8 = {
1576        let log2 = 16;
1577        assert!(1 << log2 == Memory::DEFAULT_PAGE_SIZE);
1578        log2
1579    };
1580
1581    /// Returns the minimum size, in bytes, that this memory must be.
1582    ///
1583    /// # Errors
1584    ///
1585    /// Returns an error if the calculation of the minimum size overflows the
1586    /// `u64` return type. This means that the memory can't be allocated but
1587    /// it's deferred to the caller to how to deal with that.
1588    pub fn minimum_byte_size(&self) -> Result<u64, SizeOverflow> {
1589        self.minimum
1590            .checked_mul(self.page_size())
1591            .ok_or(SizeOverflow)
1592    }
1593
1594    /// Returns the maximum size, in bytes, that this memory is allowed to be.
1595    ///
1596    /// Note that the return value here is not an `Option` despite the maximum
1597    /// size of a linear memory being optional in wasm. If a maximum size
1598    /// is not present in the memory's type then a maximum size is selected for
1599    /// it. For example the maximum size of a 32-bit memory is `1<<32`. The
1600    /// maximum size of a 64-bit linear memory is chosen to be a value that
1601    /// won't ever be allowed at runtime.
1602    ///
1603    /// # Errors
1604    ///
1605    /// Returns an error if the calculation of the maximum size overflows the
1606    /// `u64` return type. This means that the memory can't be allocated but
1607    /// it's deferred to the caller to how to deal with that.
1608    pub fn maximum_byte_size(&self) -> Result<u64, SizeOverflow> {
1609        match self.maximum {
1610            Some(max) => max.checked_mul(self.page_size()).ok_or(SizeOverflow),
1611            None => {
1612                let min = self.minimum_byte_size()?;
1613                Ok(min.max(self.max_size_based_on_index_type()))
1614            }
1615        }
1616    }
1617
1618    /// Get the size of this memory's pages, in bytes.
1619    pub fn page_size(&self) -> u64 {
1620        debug_assert!(
1621            self.page_size_log2 == 16 || self.page_size_log2 == 0,
1622            "invalid page_size_log2: {}; must be 16 or 0",
1623            self.page_size_log2
1624        );
1625        1 << self.page_size_log2
1626    }
1627
1628    /// Returns the maximum size memory is allowed to be only based on the
1629    /// index type used by this memory.
1630    ///
1631    /// For example 32-bit linear memories return `1<<32` from this method.
1632    pub fn max_size_based_on_index_type(&self) -> u64 {
1633        if self.memory64 {
1634            // Note that the true maximum size of a 64-bit linear memory, in
1635            // bytes, cannot be represented in a `u64`. That would require a u65
1636            // to store `1<<64`. Despite that no system can actually allocate a
1637            // full 64-bit linear memory so this is instead emulated as "what if
1638            // the kernel fit in a single Wasm page of linear memory". Shouldn't
1639            // ever actually be possible but it provides a number to serve as an
1640            // effective maximum.
1641            0_u64.wrapping_sub(self.page_size())
1642        } else {
1643            WASM32_MAX_SIZE
1644        }
1645    }
1646}
1647
1648#[derive(Copy, Clone, Debug)]
1649pub struct SizeOverflow;
1650
1651impl fmt::Display for SizeOverflow {
1652    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1653        f.write_str("size overflow calculating memory size")
1654    }
1655}
1656
1657#[cfg(feature = "std")]
1658impl std::error::Error for SizeOverflow {}
1659
1660impl From<wasmparser::MemoryType> for Memory {
1661    fn from(ty: wasmparser::MemoryType) -> Memory {
1662        let page_size_log2 = u8::try_from(ty.page_size_log2.unwrap_or(16)).unwrap();
1663        debug_assert!(
1664            page_size_log2 == 16 || page_size_log2 == 0,
1665            "invalid page_size_log2: {}; must be 16 or 0",
1666            page_size_log2
1667        );
1668        Memory {
1669            minimum: ty.initial,
1670            maximum: ty.maximum,
1671            shared: ty.shared,
1672            memory64: ty.memory64,
1673            page_size_log2,
1674        }
1675    }
1676}
1677
1678/// WebAssembly event.
1679#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1680pub struct Tag {
1681    /// The event signature type.
1682    pub ty: TypeIndex,
1683}
1684
1685impl From<wasmparser::TagType> for Tag {
1686    fn from(ty: wasmparser::TagType) -> Tag {
1687        match ty.kind {
1688            wasmparser::TagKind::Exception => Tag {
1689                ty: TypeIndex::from_u32(ty.func_type_idx),
1690            },
1691        }
1692    }
1693}
1694
1695/// Helpers used to convert a `wasmparser` type to a type in this crate.
1696pub trait TypeConvert {
1697    /// Converts a wasmparser table type into a wasmtime type
1698    fn convert_global_type(&self, ty: &wasmparser::GlobalType) -> Global {
1699        Global {
1700            wasm_ty: self.convert_valtype(ty.content_type),
1701            mutability: ty.mutable,
1702        }
1703    }
1704
1705    /// Converts a wasmparser table type into a wasmtime type
1706    fn convert_table_type(&self, ty: &wasmparser::TableType) -> WasmResult<Table> {
1707        if ty.table64 {
1708            return Err(wasm_unsupported!("wasm memory64: 64-bit table type"));
1709        }
1710        Ok(Table {
1711            wasm_ty: self.convert_ref_type(ty.element_type),
1712            minimum: ty.initial.try_into().unwrap(),
1713            maximum: ty.maximum.map(|i| i.try_into().unwrap()),
1714        })
1715    }
1716
1717    fn convert_sub_type(&self, ty: &wasmparser::SubType) -> WasmSubType {
1718        WasmSubType {
1719            is_final: ty.is_final,
1720            supertype: ty.supertype_idx.map(|i| self.lookup_type_index(i.unpack())),
1721            composite_type: self.convert_composite_type(&ty.composite_type),
1722        }
1723    }
1724
1725    fn convert_composite_type(&self, ty: &wasmparser::CompositeType) -> WasmCompositeType {
1726        assert!(!ty.shared);
1727        match &ty.inner {
1728            wasmparser::CompositeInnerType::Func(f) => {
1729                WasmCompositeType::Func(self.convert_func_type(f))
1730            }
1731            wasmparser::CompositeInnerType::Array(a) => {
1732                WasmCompositeType::Array(self.convert_array_type(a))
1733            }
1734            wasmparser::CompositeInnerType::Struct(s) => {
1735                WasmCompositeType::Struct(self.convert_struct_type(s))
1736            }
1737        }
1738    }
1739
1740    fn convert_struct_type(&self, ty: &wasmparser::StructType) -> WasmStructType {
1741        WasmStructType {
1742            fields: ty
1743                .fields
1744                .iter()
1745                .map(|f| self.convert_field_type(f))
1746                .collect(),
1747        }
1748    }
1749
1750    fn convert_array_type(&self, ty: &wasmparser::ArrayType) -> WasmArrayType {
1751        WasmArrayType(self.convert_field_type(&ty.0))
1752    }
1753
1754    fn convert_field_type(&self, ty: &wasmparser::FieldType) -> WasmFieldType {
1755        WasmFieldType {
1756            element_type: self.convert_storage_type(&ty.element_type),
1757            mutable: ty.mutable,
1758        }
1759    }
1760
1761    fn convert_storage_type(&self, ty: &wasmparser::StorageType) -> WasmStorageType {
1762        match ty {
1763            wasmparser::StorageType::I8 => WasmStorageType::I8,
1764            wasmparser::StorageType::I16 => WasmStorageType::I16,
1765            wasmparser::StorageType::Val(v) => WasmStorageType::Val(self.convert_valtype(*v)),
1766        }
1767    }
1768
1769    /// Converts a wasmparser function type to a wasmtime type
1770    fn convert_func_type(&self, ty: &wasmparser::FuncType) -> WasmFuncType {
1771        let params = ty
1772            .params()
1773            .iter()
1774            .map(|t| self.convert_valtype(*t))
1775            .collect();
1776        let results = ty
1777            .results()
1778            .iter()
1779            .map(|t| self.convert_valtype(*t))
1780            .collect();
1781        WasmFuncType::new(params, results)
1782    }
1783
1784    /// Converts a wasmparser value type to a wasmtime type
1785    fn convert_valtype(&self, ty: wasmparser::ValType) -> WasmValType {
1786        match ty {
1787            wasmparser::ValType::I32 => WasmValType::I32,
1788            wasmparser::ValType::I64 => WasmValType::I64,
1789            wasmparser::ValType::F32 => WasmValType::F32,
1790            wasmparser::ValType::F64 => WasmValType::F64,
1791            wasmparser::ValType::V128 => WasmValType::V128,
1792            wasmparser::ValType::Ref(t) => WasmValType::Ref(self.convert_ref_type(t)),
1793        }
1794    }
1795
1796    /// Converts a wasmparser reference type to a wasmtime type
1797    fn convert_ref_type(&self, ty: wasmparser::RefType) -> WasmRefType {
1798        WasmRefType {
1799            nullable: ty.is_nullable(),
1800            heap_type: self.convert_heap_type(ty.heap_type()),
1801        }
1802    }
1803
1804    /// Converts a wasmparser heap type to a wasmtime type
1805    fn convert_heap_type(&self, ty: wasmparser::HeapType) -> WasmHeapType {
1806        match ty {
1807            wasmparser::HeapType::Concrete(i) => self.lookup_heap_type(i),
1808            wasmparser::HeapType::Abstract { ty, shared: false } => match ty {
1809                wasmparser::AbstractHeapType::Extern => WasmHeapType::Extern,
1810                wasmparser::AbstractHeapType::NoExtern => WasmHeapType::NoExtern,
1811                wasmparser::AbstractHeapType::Func => WasmHeapType::Func,
1812                wasmparser::AbstractHeapType::NoFunc => WasmHeapType::NoFunc,
1813                wasmparser::AbstractHeapType::Any => WasmHeapType::Any,
1814                wasmparser::AbstractHeapType::Eq => WasmHeapType::Eq,
1815                wasmparser::AbstractHeapType::I31 => WasmHeapType::I31,
1816                wasmparser::AbstractHeapType::Array => WasmHeapType::Array,
1817                wasmparser::AbstractHeapType::Struct => WasmHeapType::Struct,
1818                wasmparser::AbstractHeapType::None => WasmHeapType::None,
1819
1820                wasmparser::AbstractHeapType::Exn | wasmparser::AbstractHeapType::NoExn => {
1821                    unimplemented!("unsupported heap type {ty:?}");
1822                }
1823            },
1824            _ => unimplemented!("unsupported heap type {ty:?}"),
1825        }
1826    }
1827
1828    /// Converts the specified type index from a heap type into a canonicalized
1829    /// heap type.
1830    fn lookup_heap_type(&self, index: wasmparser::UnpackedIndex) -> WasmHeapType;
1831
1832    /// Converts the specified type index from a heap type into a canonicalized
1833    /// heap type.
1834    fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex;
1835}