Skip to main content

wasmtime_environ/
types.rs

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