1 use crate::error::OutOfMemory;
2 use crate::prelude::*;
3 use crate::runtime::externals::Global as RuntimeGlobal;
4 use crate::runtime::externals::Table as RuntimeTable;
5 use crate::runtime::externals::Tag as RuntimeTag;
6 use crate::{AsContextMut, Extern, Func, Val};
7 use crate::{Engine, type_registry::RegisteredType};
8 use core::fmt::{self, Display, Write};
9 use wasmtime_environ::WasmExnType;
10 use wasmtime_environ::{
11     EngineOrModuleTypeIndex, EntityType, Global, IndexType, Limits, Memory, ModuleTypes,
12     PanicOnOom as _, Table, Tag, TypeTrace, VMSharedTypeIndex, WasmArrayType,
13     WasmCompositeInnerType, WasmCompositeType, WasmFieldType, WasmFuncType, WasmHeapType,
14     WasmRefType, WasmStorageType, WasmStructType, WasmSubType, WasmValType,
15 };
16 
17 pub(crate) mod matching;
18 
19 // Type Representations
20 
21 // Type attributes
22 
23 /// Indicator of whether a global value, struct's field, or array type's
24 /// elements are mutable or not.
25 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
26 pub enum Mutability {
27     /// The global value, struct field, or array elements are constant and the
28     /// value does not change.
29     Const,
30     /// The value of the global, struct field, or array elements can change over
31     /// time.
32     Var,
33 }
34 
35 impl Mutability {
36     /// Is this constant?
37     #[inline]
is_const(&self) -> bool38     pub fn is_const(&self) -> bool {
39         *self == Self::Const
40     }
41 
42     /// Is this variable?
43     #[inline]
is_var(&self) -> bool44     pub fn is_var(&self) -> bool {
45         *self == Self::Var
46     }
47 }
48 
49 /// Indicator of whether a type is final or not.
50 ///
51 /// Final types may not be the supertype of other types.
52 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
53 pub enum Finality {
54     /// The associated type is final.
55     Final,
56     /// The associated type is not final.
57     NonFinal,
58 }
59 
60 impl Finality {
61     /// Is this final?
62     #[inline]
is_final(&self) -> bool63     pub fn is_final(&self) -> bool {
64         *self == Self::Final
65     }
66 
67     /// Is this non-final?
68     #[inline]
is_non_final(&self) -> bool69     pub fn is_non_final(&self) -> bool {
70         *self == Self::NonFinal
71     }
72 }
73 
74 // Value Types
75 
76 /// A list of all possible value types in WebAssembly.
77 ///
78 /// # Subtyping and Equality
79 ///
80 /// `ValType` does not implement `Eq`, because reference types have a subtyping
81 /// relationship, and so 99.99% of the time you actually want to check whether
82 /// one type matches (i.e. is a subtype of) another type. You can use the
83 /// [`ValType::matches`] and [`Val::matches_ty`][crate::Val::matches_ty] methods
84 /// to perform these types of checks. If, however, you are in that 0.01%
85 /// scenario where you need to check precise equality between types, you can use
86 /// the [`ValType::eq`] method.
87 #[derive(Clone, Hash)]
88 pub enum ValType {
89     // NB: the ordering of variants here is intended to match the ordering in
90     // `wasmtime_environ::WasmType` to help improve codegen when converting.
91     //
92     /// Signed 32 bit integer.
93     I32,
94     /// Signed 64 bit integer.
95     I64,
96     /// Floating point 32 bit integer.
97     F32,
98     /// Floating point 64 bit integer.
99     F64,
100     /// A 128 bit number.
101     V128,
102     /// An opaque reference to some type on the heap.
103     Ref(RefType),
104 }
105 
106 impl fmt::Debug for ValType {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result107     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108         fmt::Display::fmt(self, f)
109     }
110 }
111 
112 impl Display for ValType {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result113     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
114         match self {
115             ValType::I32 => write!(f, "i32"),
116             ValType::I64 => write!(f, "i64"),
117             ValType::F32 => write!(f, "f32"),
118             ValType::F64 => write!(f, "f64"),
119             ValType::V128 => write!(f, "v128"),
120             ValType::Ref(r) => Display::fmt(r, f),
121         }
122     }
123 }
124 
125 impl From<RefType> for ValType {
126     #[inline]
from(r: RefType) -> Self127     fn from(r: RefType) -> Self {
128         ValType::Ref(r)
129     }
130 }
131 
132 impl ValType {
133     /// The `externref` type, aka `(ref null extern)`.
134     pub const EXTERNREF: Self = ValType::Ref(RefType::EXTERNREF);
135 
136     /// The `nullexternref` type, aka `(ref null noextern)`.
137     pub const NULLEXTERNREF: Self = ValType::Ref(RefType::NULLEXTERNREF);
138 
139     /// The `funcref` type, aka `(ref null func)`.
140     pub const FUNCREF: Self = ValType::Ref(RefType::FUNCREF);
141 
142     /// The `nullfuncref` type, aka `(ref null nofunc)`.
143     pub const NULLFUNCREF: Self = ValType::Ref(RefType::NULLFUNCREF);
144 
145     /// The `anyref` type, aka `(ref null any)`.
146     pub const ANYREF: Self = ValType::Ref(RefType::ANYREF);
147 
148     /// The `eqref` type, aka `(ref null eq)`.
149     pub const EQREF: Self = ValType::Ref(RefType::EQREF);
150 
151     /// The `i31ref` type, aka `(ref null i31)`.
152     pub const I31REF: Self = ValType::Ref(RefType::I31REF);
153 
154     /// The `arrayref` type, aka `(ref null array)`.
155     pub const ARRAYREF: Self = ValType::Ref(RefType::ARRAYREF);
156 
157     /// The `structref` type, aka `(ref null struct)`.
158     pub const STRUCTREF: Self = ValType::Ref(RefType::STRUCTREF);
159 
160     /// The `nullref` type, aka `(ref null none)`.
161     pub const NULLREF: Self = ValType::Ref(RefType::NULLREF);
162 
163     /// The `contref` type, aka `(ref null cont)`.
164     pub const CONTREF: Self = ValType::Ref(RefType::CONTREF);
165 
166     /// The `nullcontref` type, aka. `(ref null nocont)`.
167     pub const NULLCONTREF: Self = ValType::Ref(RefType::NULLCONTREF);
168 
169     /// The `exnref` type, aka `(ref null exn)`.
170     pub const EXNREF: Self = ValType::Ref(RefType::EXNREF);
171 
172     /// The `nullexnref` type, aka `(ref null noexn)`.
173     pub const NULLEXNREF: Self = ValType::Ref(RefType::NULLEXNREF);
174 
175     /// Returns true if `ValType` matches any of the numeric types. (e.g. `I32`,
176     /// `I64`, `F32`, `F64`).
177     #[inline]
is_num(&self) -> bool178     pub fn is_num(&self) -> bool {
179         match self {
180             ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 => true,
181             _ => false,
182         }
183     }
184 
185     /// Is this the `i32` type?
186     #[inline]
is_i32(&self) -> bool187     pub fn is_i32(&self) -> bool {
188         matches!(self, ValType::I32)
189     }
190 
191     /// Is this the `i64` type?
192     #[inline]
is_i64(&self) -> bool193     pub fn is_i64(&self) -> bool {
194         matches!(self, ValType::I64)
195     }
196 
197     /// Is this the `f32` type?
198     #[inline]
is_f32(&self) -> bool199     pub fn is_f32(&self) -> bool {
200         matches!(self, ValType::F32)
201     }
202 
203     /// Is this the `f64` type?
204     #[inline]
is_f64(&self) -> bool205     pub fn is_f64(&self) -> bool {
206         matches!(self, ValType::F64)
207     }
208 
209     /// Is this the `v128` type?
210     #[inline]
is_v128(&self) -> bool211     pub fn is_v128(&self) -> bool {
212         matches!(self, ValType::V128)
213     }
214 
215     /// Returns true if `ValType` is any kind of reference type.
216     #[inline]
is_ref(&self) -> bool217     pub fn is_ref(&self) -> bool {
218         matches!(self, ValType::Ref(_))
219     }
220 
221     /// Is this the `funcref` (aka `(ref null func)`) type?
222     #[inline]
is_funcref(&self) -> bool223     pub fn is_funcref(&self) -> bool {
224         matches!(
225             self,
226             ValType::Ref(RefType {
227                 is_nullable: true,
228                 heap_type: HeapType::Func
229             })
230         )
231     }
232 
233     /// Is this the `externref` (aka `(ref null extern)`) type?
234     #[inline]
is_externref(&self) -> bool235     pub fn is_externref(&self) -> bool {
236         matches!(
237             self,
238             ValType::Ref(RefType {
239                 is_nullable: true,
240                 heap_type: HeapType::Extern
241             })
242         )
243     }
244 
245     /// Is this the `anyref` (aka `(ref null any)`) type?
246     #[inline]
is_anyref(&self) -> bool247     pub fn is_anyref(&self) -> bool {
248         matches!(
249             self,
250             ValType::Ref(RefType {
251                 is_nullable: true,
252                 heap_type: HeapType::Any
253             })
254         )
255     }
256 
257     /// Is this the `contref` (aka `(ref null cont)`) type?
258     #[inline]
is_contref(&self) -> bool259     pub fn is_contref(&self) -> bool {
260         matches!(
261             self,
262             ValType::Ref(RefType {
263                 is_nullable: true,
264                 heap_type: HeapType::Cont
265             })
266         )
267     }
268 
269     /// Get the underlying reference type, if this value type is a reference
270     /// type.
271     #[inline]
as_ref(&self) -> Option<&RefType>272     pub fn as_ref(&self) -> Option<&RefType> {
273         match self {
274             ValType::Ref(r) => Some(r),
275             _ => None,
276         }
277     }
278 
279     /// Get the underlying reference type, panicking if this value type is not a
280     /// reference type.
281     #[inline]
unwrap_ref(&self) -> &RefType282     pub fn unwrap_ref(&self) -> &RefType {
283         self.as_ref()
284             .expect("ValType::unwrap_ref on a non-reference type")
285     }
286 
287     /// Does this value type match the other type?
288     ///
289     /// That is, is this value type a subtype of the other?
290     ///
291     /// # Panics
292     ///
293     /// Panics if either type is associated with a different engine from the
294     /// other.
matches(&self, other: &ValType) -> bool295     pub fn matches(&self, other: &ValType) -> bool {
296         match (self, other) {
297             (Self::I32, Self::I32) => true,
298             (Self::I64, Self::I64) => true,
299             (Self::F32, Self::F32) => true,
300             (Self::F64, Self::F64) => true,
301             (Self::V128, Self::V128) => true,
302             (Self::Ref(a), Self::Ref(b)) => a.matches(b),
303             (Self::I32, _)
304             | (Self::I64, _)
305             | (Self::F32, _)
306             | (Self::F64, _)
307             | (Self::V128, _)
308             | (Self::Ref(_), _) => false,
309         }
310     }
311 
312     /// Is value type `a` precisely equal to value type `b`?
313     ///
314     /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
315     /// are not exactly the same value type.
316     ///
317     /// # Panics
318     ///
319     /// Panics if either type is associated with a different engine.
eq(a: &Self, b: &Self) -> bool320     pub fn eq(a: &Self, b: &Self) -> bool {
321         a.matches(b) && b.matches(a)
322     }
323 
324     /// Is this a `VMGcRef` type that is not i31 and is not an uninhabited
325     /// bottom type?
326     #[inline]
is_vmgcref_type_and_points_to_object(&self) -> bool327     pub(crate) fn is_vmgcref_type_and_points_to_object(&self) -> bool {
328         match self {
329             ValType::Ref(r) => r.is_vmgcref_type_and_points_to_object(),
330             ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => false,
331         }
332     }
333 
ensure_matches(&self, engine: &Engine, other: &ValType) -> Result<()>334     pub(crate) fn ensure_matches(&self, engine: &Engine, other: &ValType) -> Result<()> {
335         if !self.comes_from_same_engine(engine) || !other.comes_from_same_engine(engine) {
336             bail!("type used with wrong engine");
337         }
338         if self.matches(other) {
339             Ok(())
340         } else {
341             bail!("type mismatch: expected {other}, found {self}")
342         }
343     }
344 
comes_from_same_engine(&self, engine: &Engine) -> bool345     pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
346         match self {
347             Self::I32 | Self::I64 | Self::F32 | Self::F64 | Self::V128 => true,
348             Self::Ref(r) => r.comes_from_same_engine(engine),
349         }
350     }
351 
to_wasm_type(&self) -> WasmValType352     pub(crate) fn to_wasm_type(&self) -> WasmValType {
353         match self {
354             Self::I32 => WasmValType::I32,
355             Self::I64 => WasmValType::I64,
356             Self::F32 => WasmValType::F32,
357             Self::F64 => WasmValType::F64,
358             Self::V128 => WasmValType::V128,
359             Self::Ref(r) => WasmValType::Ref(r.to_wasm_type()),
360         }
361     }
362 
363     #[inline]
from_wasm_type(engine: &Engine, ty: &WasmValType) -> Self364     pub(crate) fn from_wasm_type(engine: &Engine, ty: &WasmValType) -> Self {
365         match ty {
366             WasmValType::I32 => Self::I32,
367             WasmValType::I64 => Self::I64,
368             WasmValType::F32 => Self::F32,
369             WasmValType::F64 => Self::F64,
370             WasmValType::V128 => Self::V128,
371             WasmValType::Ref(r) => Self::Ref(RefType::from_wasm_type(engine, r)),
372         }
373     }
374     /// Construct a default value. Returns None for non-nullable Ref types, which have no default.
default_value(&self) -> Option<Val>375     pub fn default_value(&self) -> Option<Val> {
376         match self {
377             ValType::I32 => Some(Val::I32(0)),
378             ValType::I64 => Some(Val::I64(0)),
379             ValType::F32 => Some(Val::F32(0)),
380             ValType::F64 => Some(Val::F64(0)),
381             ValType::V128 => Some(Val::V128(0.into())),
382             ValType::Ref(r) => {
383                 if r.is_nullable() {
384                     Some(Val::null_ref(r.heap_type()))
385                 } else {
386                     None
387                 }
388             }
389         }
390     }
391 
into_registered_type(self) -> Option<RegisteredType>392     pub(crate) fn into_registered_type(self) -> Option<RegisteredType> {
393         match self {
394             ValType::Ref(ty) => ty.into_registered_type(),
395             _ => None,
396         }
397     }
398 }
399 
400 /// Opaque references to data in the Wasm heap or to host data.
401 ///
402 /// # Subtyping and Equality
403 ///
404 /// `RefType` does not implement `Eq`, because reference types have a subtyping
405 /// relationship, and so 99.99% of the time you actually want to check whether
406 /// one type matches (i.e. is a subtype of) another type. You can use the
407 /// [`RefType::matches`] and [`Ref::matches_ty`][crate::Ref::matches_ty] methods
408 /// to perform these types of checks. If, however, you are in that 0.01%
409 /// scenario where you need to check precise equality between types, you can use
410 /// the [`RefType::eq`] method.
411 #[derive(Clone, Hash)]
412 pub struct RefType {
413     is_nullable: bool,
414     heap_type: HeapType,
415 }
416 
417 impl fmt::Debug for RefType {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result418     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
419         Display::fmt(self, f)
420     }
421 }
422 
423 impl fmt::Display for RefType {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result424     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
425         write!(f, "(ref ")?;
426         if self.is_nullable() {
427             write!(f, "null ")?;
428         }
429         write!(f, "{})", self.heap_type())
430     }
431 }
432 
433 impl RefType {
434     /// The `externref` type, aka `(ref null extern)`.
435     pub const EXTERNREF: Self = RefType {
436         is_nullable: true,
437         heap_type: HeapType::Extern,
438     };
439 
440     /// The `nullexternref` type, aka `(ref null noextern)`.
441     pub const NULLEXTERNREF: Self = RefType {
442         is_nullable: true,
443         heap_type: HeapType::NoExtern,
444     };
445 
446     /// The `funcref` type, aka `(ref null func)`.
447     pub const FUNCREF: Self = RefType {
448         is_nullable: true,
449         heap_type: HeapType::Func,
450     };
451 
452     /// The `nullfuncref` type, aka `(ref null nofunc)`.
453     pub const NULLFUNCREF: Self = RefType {
454         is_nullable: true,
455         heap_type: HeapType::NoFunc,
456     };
457 
458     /// The `anyref` type, aka `(ref null any)`.
459     pub const ANYREF: Self = RefType {
460         is_nullable: true,
461         heap_type: HeapType::Any,
462     };
463 
464     /// The `eqref` type, aka `(ref null eq)`.
465     pub const EQREF: Self = RefType {
466         is_nullable: true,
467         heap_type: HeapType::Eq,
468     };
469 
470     /// The `i31ref` type, aka `(ref null i31)`.
471     pub const I31REF: Self = RefType {
472         is_nullable: true,
473         heap_type: HeapType::I31,
474     };
475 
476     /// The `arrayref` type, aka `(ref null array)`.
477     pub const ARRAYREF: Self = RefType {
478         is_nullable: true,
479         heap_type: HeapType::Array,
480     };
481 
482     /// The `structref` type, aka `(ref null struct)`.
483     pub const STRUCTREF: Self = RefType {
484         is_nullable: true,
485         heap_type: HeapType::Struct,
486     };
487 
488     /// The `nullref` type, aka `(ref null none)`.
489     pub const NULLREF: Self = RefType {
490         is_nullable: true,
491         heap_type: HeapType::None,
492     };
493 
494     /// The `contref` type, aka `(ref null cont)`.
495     pub const CONTREF: Self = RefType {
496         is_nullable: true,
497         heap_type: HeapType::Cont,
498     };
499 
500     /// The `nullcontref` type, aka `(ref null nocont)`.
501     pub const NULLCONTREF: Self = RefType {
502         is_nullable: true,
503         heap_type: HeapType::NoCont,
504     };
505 
506     /// The `exnref` type, aka `(ref null exn)`.
507     pub const EXNREF: Self = RefType {
508         is_nullable: true,
509         heap_type: HeapType::Exn,
510     };
511 
512     /// The `nullexnref` type, aka `(ref null noexn)`.
513     pub const NULLEXNREF: Self = RefType {
514         is_nullable: true,
515         heap_type: HeapType::NoExn,
516     };
517 
518     /// Construct a new reference type.
new(is_nullable: bool, heap_type: HeapType) -> RefType519     pub fn new(is_nullable: bool, heap_type: HeapType) -> RefType {
520         RefType {
521             is_nullable,
522             heap_type,
523         }
524     }
525 
526     /// Can this type of reference be null?
is_nullable(&self) -> bool527     pub fn is_nullable(&self) -> bool {
528         self.is_nullable
529     }
530 
531     /// The heap type that this is a reference to.
532     #[inline]
heap_type(&self) -> &HeapType533     pub fn heap_type(&self) -> &HeapType {
534         &self.heap_type
535     }
536 
537     /// Does this reference type match the other?
538     ///
539     /// That is, is this reference type a subtype of the other?
540     ///
541     /// # Panics
542     ///
543     /// Panics if either type is associated with a different engine from the
544     /// other.
matches(&self, other: &RefType) -> bool545     pub fn matches(&self, other: &RefType) -> bool {
546         if self.is_nullable() && !other.is_nullable() {
547             return false;
548         }
549         self.heap_type().matches(other.heap_type())
550     }
551 
552     /// Is reference type `a` precisely equal to reference type `b`?
553     ///
554     /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
555     /// are not exactly the same reference type.
556     ///
557     /// # Panics
558     ///
559     /// Panics if either type is associated with a different engine.
eq(a: &RefType, b: &RefType) -> bool560     pub fn eq(a: &RefType, b: &RefType) -> bool {
561         a.matches(b) && b.matches(a)
562     }
563 
ensure_matches(&self, engine: &Engine, other: &RefType) -> Result<()>564     pub(crate) fn ensure_matches(&self, engine: &Engine, other: &RefType) -> Result<()> {
565         if !self.comes_from_same_engine(engine) || !other.comes_from_same_engine(engine) {
566             bail!("type used with wrong engine");
567         }
568         if self.matches(other) {
569             Ok(())
570         } else {
571             bail!("type mismatch: expected {other}, found {self}")
572         }
573     }
574 
comes_from_same_engine(&self, engine: &Engine) -> bool575     pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
576         self.heap_type().comes_from_same_engine(engine)
577     }
578 
to_wasm_type(&self) -> WasmRefType579     pub(crate) fn to_wasm_type(&self) -> WasmRefType {
580         WasmRefType {
581             nullable: self.is_nullable(),
582             heap_type: self.heap_type().to_wasm_type(),
583         }
584     }
585 
from_wasm_type(engine: &Engine, ty: &WasmRefType) -> RefType586     pub(crate) fn from_wasm_type(engine: &Engine, ty: &WasmRefType) -> RefType {
587         RefType {
588             is_nullable: ty.nullable,
589             heap_type: HeapType::from_wasm_type(engine, &ty.heap_type),
590         }
591     }
592 
is_vmgcref_type_and_points_to_object(&self) -> bool593     pub(crate) fn is_vmgcref_type_and_points_to_object(&self) -> bool {
594         self.heap_type().is_vmgcref_type_and_points_to_object()
595     }
596 
into_registered_type(self) -> Option<RegisteredType>597     pub(crate) fn into_registered_type(self) -> Option<RegisteredType> {
598         self.heap_type.into_registered_type()
599     }
600 }
601 
602 /// The heap types that can Wasm can have references to.
603 ///
604 /// # Subtyping Hierarchy
605 ///
606 /// Wasm has three different heap type hierarchies:
607 ///
608 /// 1. Function types
609 /// 2. External types
610 /// 3. Internal (struct and array) types
611 /// 4. Exception types
612 ///
613 /// Each hierarchy has a top type (the common supertype of which everything else
614 /// in its hierarchy is a subtype of) and a bottom type (the common subtype of
615 /// which everything else in its hierarchy is supertype of).
616 ///
617 /// ## Function Types Hierarchy
618 ///
619 /// The top of the function types hierarchy is `func`; the bottom is
620 /// `nofunc`. In between are all the concrete function types.
621 ///
622 /// ```text
623 ///                          func
624 ///                       /  /  \  \
625 ///      ,----------------  /    \  -------------------------.
626 ///     /                  /      \                           \
627 ///    |              ,----        -----------.                |
628 ///    |              |                       |                |
629 ///    |              |                       |                |
630 /// (func)    (func (param i32))    (func (param i32 i32))    ...
631 ///    |              |                       |                |
632 ///    |              |                       |                |
633 ///    |              `---.        ,----------'                |
634 ///     \                  \      /                           /
635 ///      `---------------.  \    /  ,------------------------'
636 ///                       \  \  /  /
637 ///                         nofunc
638 /// ```
639 ///
640 /// Additionally, some concrete function types are sub- or supertypes of other
641 /// concrete function types, if that was declared in their definition. For
642 /// simplicity, this isn't depicted in the diagram above.
643 ///
644 /// ## External
645 ///
646 /// The top of the external types hierarchy is `extern`; the bottom is
647 /// `noextern`. There are no concrete types in this hierarchy.
648 ///
649 /// ```text
650 ///  extern
651 ///    |
652 /// noextern
653 /// ```
654 ///
655 /// ## Internal
656 ///
657 /// The top of the internal types hierarchy is `any`; the bottom is `none`. The
658 /// `eq` type is the common supertype of all types that can be compared for
659 /// equality. The `struct` and `array` types are the common supertypes of all
660 /// concrete struct and array types respectively. The `i31` type represents
661 /// unboxed 31-bit integers.
662 ///
663 /// ```text
664 ///                                   any
665 ///                                  / | \
666 ///    ,----------------------------'  |  `--------------------------.
667 ///   /                                |                              \
668 ///  |                        .--------'                               |
669 ///  |                        |                                        |
670 ///  |                      struct                                   array
671 ///  |                     /  |   \                                 /  |   \
672 /// i31             ,-----'   |    '-----.                   ,-----'   |    `-----.
673 ///  |             /          |           \                 /          |           \
674 ///  |            |           |            |               |           |            |
675 ///  |        (struct)    (struct i32)    ...        (array i32)    (array i64)    ...
676 ///  |            |           |            |               |           |            |
677 ///  |             \          |           /                 \          |           /
678 ///   \             `-----.   |    ,-----'                   `-----.   |    ,-----'
679 ///    \                   \  |   /                                 \  |   /
680 ///     \                   \ |  /                                   \ |  /
681 ///      \                   \| /                                     \| /
682 ///       \                   |/                                       |/
683 ///        \                  |                                        |
684 ///         \                 |                                       /
685 ///          \                '--------.                             /
686 ///           \                        |                            /
687 ///            `--------------------.  |   ,-----------------------'
688 ///                                  \ |  /
689 ///                                   none
690 /// ```
691 ///
692 /// Additionally, concrete struct and array types can be subtypes of other
693 /// concrete struct and array types respectively, if that was declared in their
694 /// definitions. Once again, this is omitted from the above diagram for
695 /// simplicity.
696 ///
697 /// ## Exceptions
698 ///
699 /// The top of the exception types hierarchy is `exn`; the bottom is
700 /// `noexn`. At the WebAssembly level, there are no concrete types in
701 /// this hierarchy. However, internally we do reify a heap type for
702 /// each tag, similar to how continuation objects work.
703 ///
704 /// ```text
705 ///   exn
706 ///  / | \
707 /// (exn $t) ...
708 ///  \ | /
709 /// noexn
710 /// ```
711 ///
712 /// # Subtyping and Equality
713 ///
714 /// `HeapType` does not implement `Eq`, because heap types have a subtyping
715 /// relationship, and so 99.99% of the time you actually want to check whether
716 /// one type matches (i.e. is a subtype of) another type. You can use the
717 /// [`HeapType::matches`] method to perform these types of checks. If, however,
718 /// you are in that 0.01% scenario where you need to check precise equality
719 /// between types, you can use the [`HeapType::eq`] method.
720 #[derive(Debug, Clone, Hash)]
721 pub enum HeapType {
722     /// The abstract `extern` heap type represents external host data.
723     ///
724     /// This is the top type for the external type hierarchy, and therefore is
725     /// the common supertype of all external reference types.
726     Extern,
727 
728     /// The abstract `noextern` heap type represents the null external
729     /// reference.
730     ///
731     /// This is the bottom type for the external type hierarchy, and therefore
732     /// is the common subtype of all external reference types.
733     NoExtern,
734 
735     /// The abstract `func` heap type represents a reference to any kind of
736     /// function.
737     ///
738     /// This is the top type for the function references type hierarchy, and is
739     /// therefore a supertype of every function reference.
740     Func,
741 
742     /// A reference to a function of a specific, concrete type.
743     ///
744     /// These are subtypes of `func` and supertypes of `nofunc`.
745     ConcreteFunc(FuncType),
746 
747     /// The abstract `nofunc` heap type represents the null function reference.
748     ///
749     /// This is the bottom type for the function references type hierarchy, and
750     /// therefore `nofunc` is a subtype of all function reference types.
751     NoFunc,
752 
753     /// The abstract `any` heap type represents all internal Wasm data.
754     ///
755     /// This is the top type of the internal type hierarchy, and is therefore a
756     /// supertype of all internal types (such as `eq`, `i31`, `struct`s, and
757     /// `array`s).
758     Any,
759 
760     /// The abstract `eq` heap type represenets all internal Wasm references
761     /// that can be compared for equality.
762     ///
763     /// This is a subtype of `any` and a supertype of `i31`, `array`, `struct`,
764     /// and `none` heap types.
765     Eq,
766 
767     /// The `i31` heap type represents unboxed 31-bit integers.
768     ///
769     /// This is a subtype of `any` and `eq`, and a supertype of `none`.
770     I31,
771 
772     /// The abstract `array` heap type represents a reference to any kind of
773     /// array.
774     ///
775     /// This is a subtype of `any` and `eq`, and a supertype of all concrete
776     /// array types, as well as a supertype of the abstract `none` heap type.
777     Array,
778 
779     /// A reference to an array of a specific, concrete type.
780     ///
781     /// These are subtypes of the `array` heap type (therefore also a subtype of
782     /// `any` and `eq`) and supertypes of the `none` heap type.
783     ConcreteArray(ArrayType),
784 
785     /// The abstract `struct` heap type represents a reference to any kind of
786     /// struct.
787     ///
788     /// This is a subtype of `any` and `eq`, and a supertype of all concrete
789     /// struct types, as well as a supertype of the abstract `none` heap type.
790     Struct,
791 
792     /// A reference to an struct of a specific, concrete type.
793     ///
794     /// These are subtypes of the `struct` heap type (therefore also a subtype
795     /// of `any` and `eq`) and supertypes of the `none` heap type.
796     ConcreteStruct(StructType),
797 
798     /// The abstract `exn` heap type represents a reference to any
799     /// kind of exception.
800     ///
801     /// This is a supertype of the internal concrete exception heap
802     /// types and the `noexn` heap type.
803     Exn,
804 
805     /// A concrete exception object with a specific tag.
806     ///
807     /// These are internal, not exposed at the Wasm level, but useful
808     /// in our implementation and host API. These are subtypes of
809     /// `exn` and supertypes of `noexn`.
810     ConcreteExn(ExnType),
811 
812     /// A reference to a continuation of a specific, concrete type.
813     ///
814     /// These are subtypes of `cont` and supertypes of `nocont`.
815     ConcreteCont(ContType),
816 
817     /// The `cont` heap type represents a reference to any kind of continuation.
818     ///
819     /// This is the top type for the continuation objects type hierarchy, and is
820     /// therefore a supertype of every continuation object.
821     Cont,
822 
823     /// The `nocont` heap type represents the null continuation object.
824     ///
825     /// This is the bottom type for the continuation objects type hierarchy, and
826     /// therefore `nocont` is a subtype of all continuation object types.
827     NoCont,
828 
829     /// The abstract `none` heap type represents the null internal reference.
830     ///
831     /// This is the bottom type for the internal type hierarchy, and therefore
832     /// `none` is a subtype of internal types.
833     None,
834 
835     /// The `noexn` heap type represents the null exception object.
836     ///
837     /// This is the bottom type for the exception objects type hierarchy.
838     NoExn,
839 }
840 
841 impl Display for HeapType {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result842     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
843         match self {
844             HeapType::Extern => write!(f, "extern"),
845             HeapType::NoExtern => write!(f, "noextern"),
846             HeapType::Func => write!(f, "func"),
847             HeapType::NoFunc => write!(f, "nofunc"),
848             HeapType::Any => write!(f, "any"),
849             HeapType::Eq => write!(f, "eq"),
850             HeapType::I31 => write!(f, "i31"),
851             HeapType::Array => write!(f, "array"),
852             HeapType::Struct => write!(f, "struct"),
853             HeapType::None => write!(f, "none"),
854             HeapType::ConcreteFunc(ty) => write!(f, "(concrete func {:?})", ty.type_index()),
855             HeapType::ConcreteArray(ty) => write!(f, "(concrete array {:?})", ty.type_index()),
856             HeapType::ConcreteStruct(ty) => write!(f, "(concrete struct {:?})", ty.type_index()),
857             HeapType::ConcreteCont(ty) => write!(f, "(concrete cont {:?})", ty.type_index()),
858             HeapType::ConcreteExn(ty) => write!(f, "(concrete exn {:?})", ty.type_index()),
859             HeapType::Cont => write!(f, "cont"),
860             HeapType::NoCont => write!(f, "nocont"),
861             HeapType::Exn => write!(f, "exn"),
862             HeapType::NoExn => write!(f, "noexn"),
863         }
864     }
865 }
866 
867 impl From<FuncType> for HeapType {
868     #[inline]
from(f: FuncType) -> Self869     fn from(f: FuncType) -> Self {
870         HeapType::ConcreteFunc(f)
871     }
872 }
873 
874 impl From<ArrayType> for HeapType {
875     #[inline]
from(a: ArrayType) -> Self876     fn from(a: ArrayType) -> Self {
877         HeapType::ConcreteArray(a)
878     }
879 }
880 
881 impl From<StructType> for HeapType {
882     #[inline]
from(s: StructType) -> Self883     fn from(s: StructType) -> Self {
884         HeapType::ConcreteStruct(s)
885     }
886 }
887 
888 impl From<ContType> for HeapType {
889     #[inline]
from(f: ContType) -> Self890     fn from(f: ContType) -> Self {
891         HeapType::ConcreteCont(f)
892     }
893 }
894 
895 impl From<ExnType> for HeapType {
896     #[inline]
from(e: ExnType) -> Self897     fn from(e: ExnType) -> Self {
898         HeapType::ConcreteExn(e)
899     }
900 }
901 
902 impl HeapType {
903     /// Is this the abstract `extern` heap type?
is_extern(&self) -> bool904     pub fn is_extern(&self) -> bool {
905         matches!(self, HeapType::Extern)
906     }
907 
908     /// Is this the abstract `func` heap type?
is_func(&self) -> bool909     pub fn is_func(&self) -> bool {
910         matches!(self, HeapType::Func)
911     }
912 
913     /// Is this the abstract `nofunc` heap type?
is_no_func(&self) -> bool914     pub fn is_no_func(&self) -> bool {
915         matches!(self, HeapType::NoFunc)
916     }
917 
918     /// Is this the abstract `any` heap type?
is_any(&self) -> bool919     pub fn is_any(&self) -> bool {
920         matches!(self, HeapType::Any)
921     }
922 
923     /// Is this the abstract `i31` heap type?
is_i31(&self) -> bool924     pub fn is_i31(&self) -> bool {
925         matches!(self, HeapType::I31)
926     }
927 
928     /// Is this the abstract `none` heap type?
is_none(&self) -> bool929     pub fn is_none(&self) -> bool {
930         matches!(self, HeapType::None)
931     }
932 
933     /// Is this the abstract `cont` heap type?
is_cont(&self) -> bool934     pub fn is_cont(&self) -> bool {
935         matches!(self, HeapType::Cont)
936     }
937 
938     /// Is this the abstract `exn` heap type?
is_exn(&self) -> bool939     pub fn is_exn(&self) -> bool {
940         matches!(self, HeapType::Exn)
941     }
942 
943     /// Is this the abstract `noexn` heap type?
is_no_exn(&self) -> bool944     pub fn is_no_exn(&self) -> bool {
945         matches!(self, HeapType::NoExn)
946     }
947 
948     /// Is this an abstract type?
949     ///
950     /// Types that are not abstract are concrete, user-defined types.
is_abstract(&self) -> bool951     pub fn is_abstract(&self) -> bool {
952         !self.is_concrete()
953     }
954 
955     /// Is this a concrete, user-defined heap type?
956     ///
957     /// Types that are not concrete, user-defined types are abstract types.
958     #[inline]
is_concrete(&self) -> bool959     pub fn is_concrete(&self) -> bool {
960         matches!(
961             self,
962             HeapType::ConcreteFunc(_)
963                 | HeapType::ConcreteArray(_)
964                 | HeapType::ConcreteStruct(_)
965                 | HeapType::ConcreteCont(_)
966                 | HeapType::ConcreteExn(_)
967         )
968     }
969 
970     /// Is this a concrete, user-defined function type?
is_concrete_func(&self) -> bool971     pub fn is_concrete_func(&self) -> bool {
972         matches!(self, HeapType::ConcreteFunc(_))
973     }
974 
975     /// Get the underlying concrete, user-defined function type, if any.
976     ///
977     /// Returns `None` if this is not a concrete function type.
as_concrete_func(&self) -> Option<&FuncType>978     pub fn as_concrete_func(&self) -> Option<&FuncType> {
979         match self {
980             HeapType::ConcreteFunc(f) => Some(f),
981             _ => None,
982         }
983     }
984 
985     /// Get the underlying concrete, user-defined type, panicking if this is not
986     /// a concrete function type.
unwrap_concrete_func(&self) -> &FuncType987     pub fn unwrap_concrete_func(&self) -> &FuncType {
988         self.as_concrete_func().unwrap()
989     }
990 
991     /// Is this a concrete, user-defined array type?
is_concrete_array(&self) -> bool992     pub fn is_concrete_array(&self) -> bool {
993         matches!(self, HeapType::ConcreteArray(_))
994     }
995 
996     /// Get the underlying concrete, user-defined array type, if any.
997     ///
998     /// Returns `None` for if this is not a concrete array type.
as_concrete_array(&self) -> Option<&ArrayType>999     pub fn as_concrete_array(&self) -> Option<&ArrayType> {
1000         match self {
1001             HeapType::ConcreteArray(f) => Some(f),
1002             _ => None,
1003         }
1004     }
1005 
1006     /// Get the underlying concrete, user-defined type, panicking if this is not
1007     /// a concrete array type.
unwrap_concrete_array(&self) -> &ArrayType1008     pub fn unwrap_concrete_array(&self) -> &ArrayType {
1009         self.as_concrete_array().unwrap()
1010     }
1011 
1012     /// Is this a concrete, user-defined continuation type?
is_concrete_cont(&self) -> bool1013     pub fn is_concrete_cont(&self) -> bool {
1014         matches!(self, HeapType::ConcreteCont(_))
1015     }
1016 
1017     /// Get the underlying concrete, user-defined continuation type, if any.
1018     ///
1019     /// Returns `None` if this is not a concrete continuation type.
as_concrete_cont(&self) -> Option<&ContType>1020     pub fn as_concrete_cont(&self) -> Option<&ContType> {
1021         match self {
1022             HeapType::ConcreteCont(f) => Some(f),
1023             _ => None,
1024         }
1025     }
1026 
1027     /// Is this a concrete, user-defined struct type?
is_concrete_struct(&self) -> bool1028     pub fn is_concrete_struct(&self) -> bool {
1029         matches!(self, HeapType::ConcreteStruct(_))
1030     }
1031 
1032     /// Get the underlying concrete, user-defined struct type, if any.
1033     ///
1034     /// Returns `None` for if this is not a concrete struct type.
as_concrete_struct(&self) -> Option<&StructType>1035     pub fn as_concrete_struct(&self) -> Option<&StructType> {
1036         match self {
1037             HeapType::ConcreteStruct(f) => Some(f),
1038             _ => None,
1039         }
1040     }
1041 
1042     /// Get the underlying concrete, user-defined type, panicking if this is not
1043     /// a concrete continuation type.
unwrap_concrete_cont(&self) -> &ContType1044     pub fn unwrap_concrete_cont(&self) -> &ContType {
1045         self.as_concrete_cont().unwrap()
1046     }
1047 
1048     /// Get the underlying concrete, user-defined type, panicking if this is not
1049     /// a concrete struct type.
unwrap_concrete_struct(&self) -> &StructType1050     pub fn unwrap_concrete_struct(&self) -> &StructType {
1051         self.as_concrete_struct().unwrap()
1052     }
1053 
1054     /// Is this a concrete, user-defined exception type?
is_concrete_exn(&self) -> bool1055     pub fn is_concrete_exn(&self) -> bool {
1056         matches!(self, HeapType::ConcreteExn(_))
1057     }
1058 
1059     /// Get the underlying concrete, user-defined exception type, if any.
1060     ///
1061     /// Returns `None` if this is not a concrete exception type.
as_concrete_exn(&self) -> Option<&ExnType>1062     pub fn as_concrete_exn(&self) -> Option<&ExnType> {
1063         match self {
1064             HeapType::ConcreteExn(e) => Some(e),
1065             _ => None,
1066         }
1067     }
1068 
1069     /// Get the top type of this heap type's type hierarchy.
1070     ///
1071     /// The returned heap type is a supertype of all types in this heap type's
1072     /// type hierarchy.
1073     #[inline]
top(&self) -> HeapType1074     pub fn top(&self) -> HeapType {
1075         match self {
1076             HeapType::Func | HeapType::ConcreteFunc(_) | HeapType::NoFunc => HeapType::Func,
1077 
1078             HeapType::Extern | HeapType::NoExtern => HeapType::Extern,
1079 
1080             HeapType::Any
1081             | HeapType::Eq
1082             | HeapType::I31
1083             | HeapType::Array
1084             | HeapType::ConcreteArray(_)
1085             | HeapType::Struct
1086             | HeapType::ConcreteStruct(_)
1087             | HeapType::None => HeapType::Any,
1088 
1089             HeapType::Cont | HeapType::ConcreteCont(_) | HeapType::NoCont => HeapType::Cont,
1090 
1091             HeapType::Exn | HeapType::ConcreteExn(_) | HeapType::NoExn => HeapType::Exn,
1092         }
1093     }
1094 
1095     /// Is this the top type within its type hierarchy?
1096     #[inline]
is_top(&self) -> bool1097     pub fn is_top(&self) -> bool {
1098         match self {
1099             HeapType::Any | HeapType::Extern | HeapType::Func | HeapType::Cont | HeapType::Exn => {
1100                 true
1101             }
1102             _ => false,
1103         }
1104     }
1105 
1106     /// Get the bottom type of this heap type's type hierarchy.
1107     ///
1108     /// The returned heap type is a subtype of all types in this heap type's
1109     /// type hierarchy.
1110     #[inline]
bottom(&self) -> HeapType1111     pub fn bottom(&self) -> HeapType {
1112         match self {
1113             HeapType::Extern | HeapType::NoExtern => HeapType::NoExtern,
1114 
1115             HeapType::Func | HeapType::ConcreteFunc(_) | HeapType::NoFunc => HeapType::NoFunc,
1116 
1117             HeapType::Any
1118             | HeapType::Eq
1119             | HeapType::I31
1120             | HeapType::Array
1121             | HeapType::ConcreteArray(_)
1122             | HeapType::Struct
1123             | HeapType::ConcreteStruct(_)
1124             | HeapType::None => HeapType::None,
1125 
1126             HeapType::Cont | HeapType::ConcreteCont(_) | HeapType::NoCont => HeapType::NoCont,
1127 
1128             HeapType::Exn | HeapType::ConcreteExn(_) | HeapType::NoExn => HeapType::NoExn,
1129         }
1130     }
1131 
1132     /// Is this the bottom type within its type hierarchy?
1133     #[inline]
is_bottom(&self) -> bool1134     pub fn is_bottom(&self) -> bool {
1135         match self {
1136             HeapType::None
1137             | HeapType::NoExtern
1138             | HeapType::NoFunc
1139             | HeapType::NoCont
1140             | HeapType::NoExn => true,
1141             _ => false,
1142         }
1143     }
1144 
1145     /// Does this heap type match the other heap type?
1146     ///
1147     /// That is, is this heap type a subtype of the other?
1148     ///
1149     /// # Panics
1150     ///
1151     /// Panics if either type is associated with a different engine from the
1152     /// other.
matches(&self, other: &HeapType) -> bool1153     pub fn matches(&self, other: &HeapType) -> bool {
1154         match (self, other) {
1155             (HeapType::Extern, HeapType::Extern) => true,
1156             (HeapType::Extern, _) => false,
1157 
1158             (HeapType::NoExtern, HeapType::NoExtern | HeapType::Extern) => true,
1159             (HeapType::NoExtern, _) => false,
1160 
1161             (HeapType::NoFunc, HeapType::NoFunc | HeapType::ConcreteFunc(_) | HeapType::Func) => {
1162                 true
1163             }
1164             (HeapType::NoFunc, _) => false,
1165 
1166             (HeapType::ConcreteFunc(_), HeapType::Func) => true,
1167             (HeapType::ConcreteFunc(a), HeapType::ConcreteFunc(b)) => {
1168                 assert!(a.comes_from_same_engine(b.engine()));
1169                 a.engine()
1170                     .signatures()
1171                     .is_subtype(a.type_index(), b.type_index())
1172             }
1173             (HeapType::ConcreteFunc(_), _) => false,
1174 
1175             (HeapType::Func, HeapType::Func) => true,
1176             (HeapType::Func, _) => false,
1177 
1178             (HeapType::Cont, HeapType::Cont) => true,
1179             (HeapType::Cont, _) => false,
1180 
1181             (HeapType::NoCont, HeapType::NoCont | HeapType::ConcreteCont(_) | HeapType::Cont) => {
1182                 true
1183             }
1184             (HeapType::NoCont, _) => false,
1185 
1186             (HeapType::ConcreteCont(_), HeapType::Cont) => true,
1187             (HeapType::ConcreteCont(a), HeapType::ConcreteCont(b)) => a.matches(b),
1188             (HeapType::ConcreteCont(_), _) => false,
1189 
1190             (
1191                 HeapType::None,
1192                 HeapType::None
1193                 | HeapType::ConcreteArray(_)
1194                 | HeapType::Array
1195                 | HeapType::ConcreteStruct(_)
1196                 | HeapType::Struct
1197                 | HeapType::I31
1198                 | HeapType::Eq
1199                 | HeapType::Any,
1200             ) => true,
1201             (HeapType::None, _) => false,
1202 
1203             (HeapType::ConcreteArray(_), HeapType::Array | HeapType::Eq | HeapType::Any) => true,
1204             (HeapType::ConcreteArray(a), HeapType::ConcreteArray(b)) => {
1205                 assert!(a.comes_from_same_engine(b.engine()));
1206                 a.engine()
1207                     .signatures()
1208                     .is_subtype(a.type_index(), b.type_index())
1209             }
1210             (HeapType::ConcreteArray(_), _) => false,
1211 
1212             (HeapType::Array, HeapType::Array | HeapType::Eq | HeapType::Any) => true,
1213             (HeapType::Array, _) => false,
1214 
1215             (HeapType::ConcreteStruct(_), HeapType::Struct | HeapType::Eq | HeapType::Any) => true,
1216             (HeapType::ConcreteStruct(a), HeapType::ConcreteStruct(b)) => {
1217                 assert!(a.comes_from_same_engine(b.engine()));
1218                 a.engine()
1219                     .signatures()
1220                     .is_subtype(a.type_index(), b.type_index())
1221             }
1222             (HeapType::ConcreteStruct(_), _) => false,
1223 
1224             (HeapType::Struct, HeapType::Struct | HeapType::Eq | HeapType::Any) => true,
1225             (HeapType::Struct, _) => false,
1226 
1227             (HeapType::I31, HeapType::I31 | HeapType::Eq | HeapType::Any) => true,
1228             (HeapType::I31, _) => false,
1229 
1230             (HeapType::Eq, HeapType::Eq | HeapType::Any) => true,
1231             (HeapType::Eq, _) => false,
1232 
1233             (HeapType::Any, HeapType::Any) => true,
1234             (HeapType::Any, _) => false,
1235 
1236             (HeapType::NoExn, HeapType::Exn | HeapType::ConcreteExn(_) | HeapType::NoExn) => true,
1237             (HeapType::NoExn, _) => false,
1238 
1239             (HeapType::ConcreteExn(_), HeapType::Exn) => true,
1240             (HeapType::ConcreteExn(a), HeapType::ConcreteExn(b)) => a.matches(b),
1241             (HeapType::ConcreteExn(_), _) => false,
1242 
1243             (HeapType::Exn, HeapType::Exn) => true,
1244             (HeapType::Exn, _) => false,
1245         }
1246     }
1247 
1248     /// Is heap type `a` precisely equal to heap type `b`?
1249     ///
1250     /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
1251     /// are not exactly the same heap type.
1252     ///
1253     /// # Panics
1254     ///
1255     /// Panics if either type is associated with a different engine from the
1256     /// other.
eq(a: &HeapType, b: &HeapType) -> bool1257     pub fn eq(a: &HeapType, b: &HeapType) -> bool {
1258         a.matches(b) && b.matches(a)
1259     }
1260 
ensure_matches(&self, engine: &Engine, other: &HeapType) -> Result<()>1261     pub(crate) fn ensure_matches(&self, engine: &Engine, other: &HeapType) -> Result<()> {
1262         if !self.comes_from_same_engine(engine) || !other.comes_from_same_engine(engine) {
1263             bail!("type used with wrong engine");
1264         }
1265         if self.matches(other) {
1266             Ok(())
1267         } else {
1268             bail!("type mismatch: expected {other}, found {self}");
1269         }
1270     }
1271 
comes_from_same_engine(&self, engine: &Engine) -> bool1272     pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
1273         match self {
1274             HeapType::Extern
1275             | HeapType::NoExtern
1276             | HeapType::Func
1277             | HeapType::NoFunc
1278             | HeapType::Any
1279             | HeapType::Eq
1280             | HeapType::I31
1281             | HeapType::Array
1282             | HeapType::Struct
1283             | HeapType::Cont
1284             | HeapType::NoCont
1285             | HeapType::Exn
1286             | HeapType::NoExn
1287             | HeapType::None => true,
1288             HeapType::ConcreteFunc(ty) => ty.comes_from_same_engine(engine),
1289             HeapType::ConcreteArray(ty) => ty.comes_from_same_engine(engine),
1290             HeapType::ConcreteStruct(ty) => ty.comes_from_same_engine(engine),
1291             HeapType::ConcreteCont(ty) => ty.comes_from_same_engine(engine),
1292             HeapType::ConcreteExn(ty) => ty.comes_from_same_engine(engine),
1293         }
1294     }
1295 
to_wasm_type(&self) -> WasmHeapType1296     pub(crate) fn to_wasm_type(&self) -> WasmHeapType {
1297         match self {
1298             HeapType::Extern => WasmHeapType::Extern,
1299             HeapType::NoExtern => WasmHeapType::NoExtern,
1300             HeapType::Func => WasmHeapType::Func,
1301             HeapType::NoFunc => WasmHeapType::NoFunc,
1302             HeapType::Any => WasmHeapType::Any,
1303             HeapType::Eq => WasmHeapType::Eq,
1304             HeapType::I31 => WasmHeapType::I31,
1305             HeapType::Array => WasmHeapType::Array,
1306             HeapType::Struct => WasmHeapType::Struct,
1307             HeapType::None => WasmHeapType::None,
1308             HeapType::ConcreteFunc(f) => {
1309                 WasmHeapType::ConcreteFunc(EngineOrModuleTypeIndex::Engine(f.type_index()))
1310             }
1311             HeapType::ConcreteArray(a) => {
1312                 WasmHeapType::ConcreteArray(EngineOrModuleTypeIndex::Engine(a.type_index()))
1313             }
1314             HeapType::ConcreteStruct(a) => {
1315                 WasmHeapType::ConcreteStruct(EngineOrModuleTypeIndex::Engine(a.type_index()))
1316             }
1317             HeapType::Cont => WasmHeapType::Cont,
1318             HeapType::NoCont => WasmHeapType::NoCont,
1319             HeapType::ConcreteCont(c) => {
1320                 WasmHeapType::ConcreteCont(EngineOrModuleTypeIndex::Engine(c.type_index()))
1321             }
1322             HeapType::Exn => WasmHeapType::Exn,
1323             HeapType::NoExn => WasmHeapType::NoExn,
1324             HeapType::ConcreteExn(e) => {
1325                 WasmHeapType::ConcreteExn(EngineOrModuleTypeIndex::Engine(e.type_index()))
1326             }
1327         }
1328     }
1329 
from_wasm_type(engine: &Engine, ty: &WasmHeapType) -> HeapType1330     pub(crate) fn from_wasm_type(engine: &Engine, ty: &WasmHeapType) -> HeapType {
1331         match ty {
1332             WasmHeapType::Extern => HeapType::Extern,
1333             WasmHeapType::NoExtern => HeapType::NoExtern,
1334             WasmHeapType::Func => HeapType::Func,
1335             WasmHeapType::NoFunc => HeapType::NoFunc,
1336             WasmHeapType::Any => HeapType::Any,
1337             WasmHeapType::Eq => HeapType::Eq,
1338             WasmHeapType::I31 => HeapType::I31,
1339             WasmHeapType::Array => HeapType::Array,
1340             WasmHeapType::Struct => HeapType::Struct,
1341             WasmHeapType::None => HeapType::None,
1342             WasmHeapType::ConcreteFunc(EngineOrModuleTypeIndex::Engine(idx)) => {
1343                 HeapType::ConcreteFunc(FuncType::from_shared_type_index(engine, *idx))
1344             }
1345             WasmHeapType::ConcreteArray(EngineOrModuleTypeIndex::Engine(idx)) => {
1346                 HeapType::ConcreteArray(ArrayType::from_shared_type_index(engine, *idx))
1347             }
1348             WasmHeapType::ConcreteStruct(EngineOrModuleTypeIndex::Engine(idx)) => {
1349                 HeapType::ConcreteStruct(StructType::from_shared_type_index(engine, *idx))
1350             }
1351 
1352             WasmHeapType::ConcreteFunc(EngineOrModuleTypeIndex::Module(_))
1353             | WasmHeapType::ConcreteFunc(EngineOrModuleTypeIndex::RecGroup(_))
1354             | WasmHeapType::ConcreteArray(EngineOrModuleTypeIndex::Module(_))
1355             | WasmHeapType::ConcreteArray(EngineOrModuleTypeIndex::RecGroup(_))
1356             | WasmHeapType::ConcreteStruct(EngineOrModuleTypeIndex::Module(_))
1357             | WasmHeapType::ConcreteStruct(EngineOrModuleTypeIndex::RecGroup(_))
1358             | WasmHeapType::ConcreteCont(EngineOrModuleTypeIndex::Module(_))
1359             | WasmHeapType::ConcreteCont(EngineOrModuleTypeIndex::RecGroup(_))
1360             | WasmHeapType::ConcreteExn(EngineOrModuleTypeIndex::Module(_))
1361             | WasmHeapType::ConcreteExn(EngineOrModuleTypeIndex::RecGroup(_)) => {
1362                 panic!("HeapType::from_wasm_type on non-canonicalized-for-runtime-usage heap type")
1363             }
1364             WasmHeapType::Cont => HeapType::Cont,
1365             WasmHeapType::NoCont => HeapType::NoCont,
1366             WasmHeapType::ConcreteCont(EngineOrModuleTypeIndex::Engine(idx)) => {
1367                 HeapType::ConcreteCont(ContType::from_shared_type_index(engine, *idx))
1368             }
1369             WasmHeapType::Exn => HeapType::Exn,
1370             WasmHeapType::NoExn => HeapType::NoExn,
1371             WasmHeapType::ConcreteExn(EngineOrModuleTypeIndex::Engine(idx)) => {
1372                 HeapType::ConcreteExn(ExnType::from_shared_type_index(engine, *idx))
1373             }
1374         }
1375     }
1376 
as_registered_type(&self) -> Option<&RegisteredType>1377     pub(crate) fn as_registered_type(&self) -> Option<&RegisteredType> {
1378         match self {
1379             HeapType::ConcreteCont(c) => Some(&c.registered_type),
1380             HeapType::ConcreteFunc(f) => Some(&f.registered_type),
1381             HeapType::ConcreteArray(a) => Some(&a.registered_type),
1382             HeapType::ConcreteStruct(a) => Some(&a.registered_type),
1383             HeapType::ConcreteExn(e) => Some(&e.registered_type),
1384 
1385             HeapType::Extern
1386             | HeapType::NoExtern
1387             | HeapType::Func
1388             | HeapType::NoFunc
1389             | HeapType::Any
1390             | HeapType::Eq
1391             | HeapType::I31
1392             | HeapType::Array
1393             | HeapType::Struct
1394             | HeapType::Cont
1395             | HeapType::NoCont
1396             | HeapType::Exn
1397             | HeapType::NoExn
1398             | HeapType::None => None,
1399         }
1400     }
1401 
1402     #[inline]
is_vmgcref_type(&self) -> bool1403     pub(crate) fn is_vmgcref_type(&self) -> bool {
1404         match self.top() {
1405             Self::Any | Self::Extern | Self::Exn => true,
1406             Self::Func => false,
1407             Self::Cont => false,
1408             ty => unreachable!("not a top type: {ty:?}"),
1409         }
1410     }
1411 
1412     /// Is this a `VMGcRef` type that is not i31 and is not an uninhabited
1413     /// bottom type?
1414     #[inline]
is_vmgcref_type_and_points_to_object(&self) -> bool1415     pub(crate) fn is_vmgcref_type_and_points_to_object(&self) -> bool {
1416         self.is_vmgcref_type()
1417             && !matches!(
1418                 self,
1419                 HeapType::I31 | HeapType::NoExtern | HeapType::NoFunc | HeapType::None
1420             )
1421     }
1422 
into_registered_type(self) -> Option<RegisteredType>1423     pub(crate) fn into_registered_type(self) -> Option<RegisteredType> {
1424         use HeapType::*;
1425         match self {
1426             ConcreteFunc(ty) => Some(ty.registered_type),
1427             ConcreteArray(ty) => Some(ty.registered_type),
1428             ConcreteStruct(ty) => Some(ty.registered_type),
1429             ConcreteCont(ty) => Some(ty.registered_type),
1430             ConcreteExn(ty) => Some(ty.registered_type),
1431             Extern | NoExtern | Func | NoFunc | Any | Eq | I31 | Array | Struct | Cont | NoCont
1432             | Exn | NoExn | None => Option::None,
1433         }
1434     }
1435 }
1436 
1437 // External Types
1438 
1439 /// A list of all possible types which can be externally referenced from a
1440 /// WebAssembly module.
1441 ///
1442 /// This list can be found in [`ImportType`] or [`ExportType`], so these types
1443 /// can either be imported or exported.
1444 #[derive(Debug, Clone)]
1445 pub enum ExternType {
1446     /// This external type is the type of a WebAssembly function.
1447     Func(FuncType),
1448     /// This external type is the type of a WebAssembly global.
1449     Global(GlobalType),
1450     /// This external type is the type of a WebAssembly table.
1451     Table(TableType),
1452     /// This external type is the type of a WebAssembly memory.
1453     Memory(MemoryType),
1454     /// This external type is the type of a WebAssembly tag.
1455     Tag(TagType),
1456 }
1457 
1458 macro_rules! extern_type_accessors {
1459     ($(($variant:ident($ty:ty) $get:ident $unwrap:ident))*) => ($(
1460         /// Attempt to return the underlying type of this external type,
1461         /// returning `None` if it is a different type.
1462         pub fn $get(&self) -> Option<&$ty> {
1463             if let ExternType::$variant(e) = self {
1464                 Some(e)
1465             } else {
1466                 None
1467             }
1468         }
1469 
1470         /// Returns the underlying descriptor of this [`ExternType`], panicking
1471         /// if it is a different type.
1472         ///
1473         /// # Panics
1474         ///
1475         /// Panics if `self` is not of the right type.
1476         pub fn $unwrap(&self) -> &$ty {
1477             self.$get().expect(concat!("expected ", stringify!($ty)))
1478         }
1479     )*)
1480 }
1481 
1482 impl ExternType {
1483     extern_type_accessors! {
1484         (Func(FuncType) func unwrap_func)
1485         (Global(GlobalType) global unwrap_global)
1486         (Table(TableType) table unwrap_table)
1487         (Memory(MemoryType) memory unwrap_memory)
1488         (Tag(TagType) tag unwrap_tag)
1489     }
1490 
from_wasmtime( engine: &Engine, types: &ModuleTypes, ty: &EntityType, ) -> ExternType1491     pub(crate) fn from_wasmtime(
1492         engine: &Engine,
1493         types: &ModuleTypes,
1494         ty: &EntityType,
1495     ) -> ExternType {
1496         match ty {
1497             EntityType::Function(idx) => match idx {
1498                 EngineOrModuleTypeIndex::Engine(e) => {
1499                     FuncType::from_shared_type_index(engine, *e).into()
1500                 }
1501                 EngineOrModuleTypeIndex::Module(m) => {
1502                     let subty = &types[*m];
1503                     debug_assert!(subty.is_canonicalized_for_runtime_usage());
1504                     // subty.canonicalize_for_runtime_usage(&mut |idx| {
1505                     //     signatures.shared_type(idx).unwrap()
1506                     // });
1507                     FuncType::from_wasm_func_type(
1508                         engine,
1509                         subty.is_final,
1510                         subty.supertype,
1511                         subty.unwrap_func().clone_panic_on_oom(),
1512                     )
1513                     .panic_on_oom()
1514                     .into()
1515                 }
1516                 EngineOrModuleTypeIndex::RecGroup(_) => unreachable!(),
1517             },
1518             EntityType::Global(ty) => GlobalType::from_wasmtime_global(engine, ty).into(),
1519             EntityType::Memory(ty) => MemoryType::from_wasmtime_memory(ty).into(),
1520             EntityType::Table(ty) => TableType::from_wasmtime_table(engine, ty).into(),
1521             EntityType::Tag(ty) => TagType::from_wasmtime_tag(engine, ty).into(),
1522         }
1523     }
1524     /// Construct a default value, if possible, for the underlying type.
default_value(&self, store: impl AsContextMut) -> Result<Extern>1525     pub fn default_value(&self, store: impl AsContextMut) -> Result<Extern> {
1526         match self {
1527             ExternType::Func(func_ty) => func_ty.default_value(store).map(Extern::Func),
1528             ExternType::Global(global_ty) => global_ty.default_value(store).map(Extern::Global),
1529             ExternType::Table(table_ty) => table_ty.default_value(store).map(Extern::Table),
1530             ExternType::Memory(mem_ty) => mem_ty.default_value(store),
1531             ExternType::Tag(tag_ty) => tag_ty.default_value(store).map(Extern::Tag),
1532         }
1533     }
1534 }
1535 
1536 impl From<FuncType> for ExternType {
from(ty: FuncType) -> ExternType1537     fn from(ty: FuncType) -> ExternType {
1538         ExternType::Func(ty)
1539     }
1540 }
1541 
1542 impl From<GlobalType> for ExternType {
from(ty: GlobalType) -> ExternType1543     fn from(ty: GlobalType) -> ExternType {
1544         ExternType::Global(ty)
1545     }
1546 }
1547 
1548 impl From<MemoryType> for ExternType {
from(ty: MemoryType) -> ExternType1549     fn from(ty: MemoryType) -> ExternType {
1550         ExternType::Memory(ty)
1551     }
1552 }
1553 
1554 impl From<TableType> for ExternType {
from(ty: TableType) -> ExternType1555     fn from(ty: TableType) -> ExternType {
1556         ExternType::Table(ty)
1557     }
1558 }
1559 
1560 impl From<TagType> for ExternType {
from(ty: TagType) -> ExternType1561     fn from(ty: TagType) -> ExternType {
1562         ExternType::Tag(ty)
1563     }
1564 }
1565 
1566 /// The storage type of a `struct` field or `array` element.
1567 ///
1568 /// This is either a packed 8- or -16 bit integer, or else it is some unpacked
1569 /// Wasm value type.
1570 #[derive(Clone, Hash)]
1571 pub enum StorageType {
1572     /// `i8`, an 8-bit integer.
1573     I8,
1574     /// `i16`, a 16-bit integer.
1575     I16,
1576     /// A value type.
1577     ValType(ValType),
1578 }
1579 
1580 impl fmt::Display for StorageType {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1581     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1582         match self {
1583             StorageType::I8 => write!(f, "i8"),
1584             StorageType::I16 => write!(f, "i16"),
1585             StorageType::ValType(ty) => fmt::Display::fmt(ty, f),
1586         }
1587     }
1588 }
1589 
1590 impl From<ValType> for StorageType {
1591     #[inline]
from(v: ValType) -> Self1592     fn from(v: ValType) -> Self {
1593         StorageType::ValType(v)
1594     }
1595 }
1596 
1597 impl From<RefType> for StorageType {
1598     #[inline]
from(r: RefType) -> Self1599     fn from(r: RefType) -> Self {
1600         StorageType::ValType(r.into())
1601     }
1602 }
1603 
1604 impl StorageType {
1605     /// Is this an `i8`?
1606     #[inline]
is_i8(&self) -> bool1607     pub fn is_i8(&self) -> bool {
1608         matches!(self, Self::I8)
1609     }
1610 
1611     /// Is this an `i16`?
1612     #[inline]
is_i16(&self) -> bool1613     pub fn is_i16(&self) -> bool {
1614         matches!(self, Self::I16)
1615     }
1616 
1617     /// Is this a Wasm value type?
1618     #[inline]
is_val_type(&self) -> bool1619     pub fn is_val_type(&self) -> bool {
1620         matches!(self, Self::I16)
1621     }
1622 
1623     /// Get this storage type's underlying value type, if any.
1624     ///
1625     /// Returns `None` if this storage type is not a value type.
1626     #[inline]
as_val_type(&self) -> Option<&ValType>1627     pub fn as_val_type(&self) -> Option<&ValType> {
1628         match self {
1629             Self::ValType(v) => Some(v),
1630             _ => None,
1631         }
1632     }
1633 
1634     /// Get this storage type's underlying value type, panicking if it is not a
1635     /// value type.
unwrap_val_type(&self) -> &ValType1636     pub fn unwrap_val_type(&self) -> &ValType {
1637         self.as_val_type().unwrap()
1638     }
1639 
1640     /// Unpack this (possibly packed) storage type into a full `ValType`.
1641     ///
1642     /// If this is a `StorageType::ValType`, then the inner `ValType` is
1643     /// returned as-is.
1644     ///
1645     /// If this is a packed `StorageType::I8` or `StorageType::I16, then a
1646     /// `ValType::I32` is returned.
unpack(&self) -> &ValType1647     pub fn unpack(&self) -> &ValType {
1648         match self {
1649             StorageType::I8 | StorageType::I16 => &ValType::I32,
1650             StorageType::ValType(ty) => ty,
1651         }
1652     }
1653 
1654     /// Does this field type match the other field type?
1655     ///
1656     /// That is, is this field type a subtype of the other field type?
1657     ///
1658     /// # Panics
1659     ///
1660     /// Panics if either type is associated with a different engine from the
1661     /// other.
matches(&self, other: &Self) -> bool1662     pub fn matches(&self, other: &Self) -> bool {
1663         match (self, other) {
1664             (StorageType::I8, StorageType::I8) => true,
1665             (StorageType::I8, _) => false,
1666             (StorageType::I16, StorageType::I16) => true,
1667             (StorageType::I16, _) => false,
1668             (StorageType::ValType(a), StorageType::ValType(b)) => a.matches(b),
1669             (StorageType::ValType(_), _) => false,
1670         }
1671     }
1672 
1673     /// Is field type `a` precisely equal to field type `b`?
1674     ///
1675     /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
1676     /// are not exactly the same field type.
1677     ///
1678     /// # Panics
1679     ///
1680     /// Panics if either type is associated with a different engine from the
1681     /// other.
eq(a: &Self, b: &Self) -> bool1682     pub fn eq(a: &Self, b: &Self) -> bool {
1683         match (a, b) {
1684             (StorageType::I8, StorageType::I8) => true,
1685             (StorageType::I8, _) => false,
1686             (StorageType::I16, StorageType::I16) => true,
1687             (StorageType::I16, _) => false,
1688             (StorageType::ValType(a), StorageType::ValType(b)) => ValType::eq(a, b),
1689             (StorageType::ValType(_), _) => false,
1690         }
1691     }
1692 
comes_from_same_engine(&self, engine: &Engine) -> bool1693     pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
1694         match self {
1695             StorageType::I8 | StorageType::I16 => true,
1696             StorageType::ValType(v) => v.comes_from_same_engine(engine),
1697         }
1698     }
1699 
from_wasm_storage_type(engine: &Engine, ty: &WasmStorageType) -> Self1700     pub(crate) fn from_wasm_storage_type(engine: &Engine, ty: &WasmStorageType) -> Self {
1701         match ty {
1702             WasmStorageType::I8 => Self::I8,
1703             WasmStorageType::I16 => Self::I16,
1704             WasmStorageType::Val(v) => ValType::from_wasm_type(engine, &v).into(),
1705         }
1706     }
1707 
to_wasm_storage_type(&self) -> WasmStorageType1708     pub(crate) fn to_wasm_storage_type(&self) -> WasmStorageType {
1709         match self {
1710             Self::I8 => WasmStorageType::I8,
1711             Self::I16 => WasmStorageType::I16,
1712             Self::ValType(v) => WasmStorageType::Val(v.to_wasm_type()),
1713         }
1714     }
1715 
1716     /// The byte size of this type, if it has a defined size in the spec.
1717     ///
1718     /// See
1719     /// https://webassembly.github.io/gc/core/syntax/types.html#bitwidth-fieldtype
1720     /// and
1721     /// https://webassembly.github.io/gc/core/syntax/types.html#bitwidth-valtype
1722     #[cfg(feature = "gc")]
data_byte_size(&self) -> Option<u32>1723     pub(crate) fn data_byte_size(&self) -> Option<u32> {
1724         match self {
1725             StorageType::I8 => Some(1),
1726             StorageType::I16 => Some(2),
1727             StorageType::ValType(ValType::I32 | ValType::F32) => Some(4),
1728             StorageType::ValType(ValType::I64 | ValType::F64) => Some(8),
1729             StorageType::ValType(ValType::V128) => Some(16),
1730             StorageType::ValType(ValType::Ref(_)) => None,
1731         }
1732     }
1733 }
1734 
1735 /// The type of a `struct` field or an `array`'s elements.
1736 ///
1737 /// This is a pair of both the field's storage type and its mutability
1738 /// (i.e. whether the field can be updated or not).
1739 #[derive(Clone, Hash)]
1740 pub struct FieldType {
1741     mutability: Mutability,
1742     element_type: StorageType,
1743 }
1744 
1745 impl fmt::Display for FieldType {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1746     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1747         if self.mutability.is_var() {
1748             write!(f, "(mut {})", self.element_type)
1749         } else {
1750             fmt::Display::fmt(&self.element_type, f)
1751         }
1752     }
1753 }
1754 
1755 impl FieldType {
1756     /// Construct a new field type from the given parts.
1757     #[inline]
new(mutability: Mutability, element_type: StorageType) -> Self1758     pub fn new(mutability: Mutability, element_type: StorageType) -> Self {
1759         Self {
1760             mutability,
1761             element_type,
1762         }
1763     }
1764 
1765     /// Get whether or not this field type is mutable.
1766     #[inline]
mutability(&self) -> Mutability1767     pub fn mutability(&self) -> Mutability {
1768         self.mutability
1769     }
1770 
1771     /// Get this field type's storage type.
1772     #[inline]
element_type(&self) -> &StorageType1773     pub fn element_type(&self) -> &StorageType {
1774         &self.element_type
1775     }
1776 
1777     /// Does this field type match the other field type?
1778     ///
1779     /// That is, is this field type a subtype of the other field type?
1780     ///
1781     /// # Panics
1782     ///
1783     /// Panics if either type is associated with a different engine from the
1784     /// other.
matches(&self, other: &Self) -> bool1785     pub fn matches(&self, other: &Self) -> bool {
1786         // Our storage type must match `other`'s storage type and either
1787         //
1788         // 1. Both field types are immutable, or
1789         //
1790         // 2. Both field types are mutable and `other`'s storage type must match
1791         //    ours, i.e. the storage types are exactly the same.
1792         use Mutability as M;
1793         match (self.mutability, other.mutability) {
1794             // Case 1
1795             (M::Const, M::Const) => self.element_type.matches(&other.element_type),
1796             // Case 2
1797             (M::Var, M::Var) => StorageType::eq(&self.element_type, &other.element_type),
1798             // Does not match.
1799             _ => false,
1800         }
1801     }
1802 
1803     /// Is field type `a` precisely equal to field type `b`?
1804     ///
1805     /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
1806     /// are not exactly the same field type.
1807     ///
1808     /// # Panics
1809     ///
1810     /// Panics if either type is associated with a different engine from the
1811     /// other.
eq(a: &Self, b: &Self) -> bool1812     pub fn eq(a: &Self, b: &Self) -> bool {
1813         a.matches(b) && b.matches(a)
1814     }
1815 
comes_from_same_engine(&self, engine: &Engine) -> bool1816     pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
1817         self.element_type.comes_from_same_engine(engine)
1818     }
1819 
from_wasm_field_type(engine: &Engine, ty: &WasmFieldType) -> Self1820     pub(crate) fn from_wasm_field_type(engine: &Engine, ty: &WasmFieldType) -> Self {
1821         Self {
1822             mutability: if ty.mutable {
1823                 Mutability::Var
1824             } else {
1825                 Mutability::Const
1826             },
1827             element_type: StorageType::from_wasm_storage_type(engine, &ty.element_type),
1828         }
1829     }
1830 
to_wasm_field_type(&self) -> WasmFieldType1831     pub(crate) fn to_wasm_field_type(&self) -> WasmFieldType {
1832         WasmFieldType {
1833             element_type: self.element_type.to_wasm_storage_type(),
1834             mutable: matches!(self.mutability, Mutability::Var),
1835         }
1836     }
1837 }
1838 
1839 /// The type of a WebAssembly struct.
1840 ///
1841 /// WebAssembly structs are a static, fixed-length, ordered sequence of
1842 /// fields. Fields are named by index, not an identifier. Each field is mutable
1843 /// or constant and stores unpacked [`Val`][crate::Val]s or packed 8-/16-bit
1844 /// integers.
1845 ///
1846 /// # Subtyping and Equality
1847 ///
1848 /// `StructType` does not implement `Eq`, because reference types have a
1849 /// subtyping relationship, and so 99.99% of the time you actually want to check
1850 /// whether one type matches (i.e. is a subtype of) another type. You can use
1851 /// the [`StructType::matches`] method to perform these types of checks. If,
1852 /// however, you are in that 0.01% scenario where you need to check precise
1853 /// equality between types, you can use the [`StructType::eq`] method.
1854 //
1855 // TODO: Once we have struct values, update above docs with a reference to the
1856 // future `Struct::matches_ty` method
1857 #[derive(Debug, Clone, Hash)]
1858 pub struct StructType {
1859     registered_type: RegisteredType,
1860 }
1861 
1862 impl fmt::Display for StructType {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1863     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1864         write!(f, "(struct")?;
1865         for field in self.fields() {
1866             write!(f, " (field {field})")?;
1867         }
1868         write!(f, ")")?;
1869         Ok(())
1870     }
1871 }
1872 
1873 impl StructType {
1874     /// Construct a new `StructType` with the given field types.
1875     ///
1876     /// This `StructType` will be final and without a supertype.
1877     ///
1878     /// The result will be associated with the given engine, and attempts to use
1879     /// it with other engines will panic (for example, checking whether it is a
1880     /// subtype of another struct type that is associated with a different
1881     /// engine).
1882     ///
1883     /// Returns an error if the number of fields exceeds the implementation
1884     /// limit.
1885     ///
1886     /// # Panics
1887     ///
1888     /// Panics if any given field type is not associated with the given engine.
new(engine: &Engine, fields: impl IntoIterator<Item = FieldType>) -> Result<Self>1889     pub fn new(engine: &Engine, fields: impl IntoIterator<Item = FieldType>) -> Result<Self> {
1890         Self::with_finality_and_supertype(engine, Finality::Final, None, fields)
1891     }
1892 
1893     /// Construct a new `StructType` with the given finality, supertype, and
1894     /// fields.
1895     ///
1896     /// The result will be associated with the given engine, and attempts to use
1897     /// it with other engines will panic (for example, checking whether it is a
1898     /// subtype of another struct type that is associated with a different
1899     /// engine).
1900     ///
1901     /// Returns an error if the number of fields exceeds the implementation
1902     /// limit, if the supertype is final, or if this type does not match the
1903     /// supertype.
1904     ///
1905     /// # Panics
1906     ///
1907     /// Panics if any given field type is not associated with the given engine.
with_finality_and_supertype( engine: &Engine, finality: Finality, supertype: Option<&Self>, fields: impl IntoIterator<Item = FieldType>, ) -> Result<Self>1908     pub fn with_finality_and_supertype(
1909         engine: &Engine,
1910         finality: Finality,
1911         supertype: Option<&Self>,
1912         fields: impl IntoIterator<Item = FieldType>,
1913     ) -> Result<Self> {
1914         let fields = fields.into_iter();
1915 
1916         let mut wasmtime_fields = Vec::with_capacity({
1917             let size_hint = fields.size_hint();
1918             let cap = size_hint.1.unwrap_or(size_hint.0);
1919             // Only reserve space if we have a supertype, as that is the only time
1920             // that this vec is used.
1921             supertype.is_some() as usize * cap
1922         });
1923 
1924         // Same as in `FuncType::new`: we must prevent any `RegisteredType`s
1925         // from being reclaimed while constructing this struct type.
1926         let mut registrations = smallvec::SmallVec::<[_; 4]>::new();
1927 
1928         let fields: Box<[WasmFieldType]> = fields
1929             .map(|ty: FieldType| -> Result<_, Error> {
1930                 assert!(ty.comes_from_same_engine(engine));
1931 
1932                 if supertype.is_some() {
1933                     wasmtime_fields.push(ty.clone());
1934                 }
1935 
1936                 if let Some(r) = ty.element_type.as_val_type().and_then(|v| v.as_ref()) {
1937                     if let Some(r) = r.heap_type().as_registered_type() {
1938                         registrations.push(r.clone());
1939                     }
1940                 }
1941 
1942                 Ok(ty.to_wasm_field_type())
1943             })
1944             .try_collect()?;
1945 
1946         if let Some(supertype) = supertype {
1947             ensure!(
1948                 supertype.finality().is_non_final(),
1949                 "cannot create a subtype of a final supertype"
1950             );
1951             ensure!(
1952                 Self::fields_match(wasmtime_fields.into_iter(), supertype.fields()),
1953                 "struct fields must match their supertype's fields"
1954             );
1955         }
1956 
1957         Self::from_wasm_struct_type(
1958             engine,
1959             finality.is_final(),
1960             false,
1961             supertype.map(|ty| ty.type_index().into()),
1962             WasmStructType { fields },
1963         )
1964     }
1965 
1966     /// Get the engine that this struct type is associated with.
engine(&self) -> &Engine1967     pub fn engine(&self) -> &Engine {
1968         self.registered_type.engine()
1969     }
1970 
1971     /// Get the finality of this struct type.
finality(&self) -> Finality1972     pub fn finality(&self) -> Finality {
1973         match self.registered_type.is_final {
1974             true => Finality::Final,
1975             false => Finality::NonFinal,
1976         }
1977     }
1978 
1979     /// Get the supertype of this struct type, if any.
supertype(&self) -> Option<Self>1980     pub fn supertype(&self) -> Option<Self> {
1981         self.registered_type
1982             .supertype
1983             .map(|ty| Self::from_shared_type_index(self.engine(), ty.unwrap_engine_type_index()))
1984     }
1985 
1986     /// Get the `i`th field type.
1987     ///
1988     /// Returns `None` if `i` is out of bounds.
field(&self, i: usize) -> Option<FieldType>1989     pub fn field(&self, i: usize) -> Option<FieldType> {
1990         let engine = self.engine();
1991         self.as_wasm_struct_type()
1992             .fields
1993             .get(i)
1994             .map(|ty| FieldType::from_wasm_field_type(engine, ty))
1995     }
1996 
1997     /// Returns the list of field types for this function.
1998     #[inline]
fields(&self) -> impl ExactSizeIterator<Item = FieldType> + '_1999     pub fn fields(&self) -> impl ExactSizeIterator<Item = FieldType> + '_ {
2000         let engine = self.engine();
2001         self.as_wasm_struct_type()
2002             .fields
2003             .iter()
2004             .map(|ty| FieldType::from_wasm_field_type(engine, ty))
2005     }
2006 
2007     /// Does this struct type match the other struct type?
2008     ///
2009     /// That is, is this function type a subtype of the other struct type?
2010     ///
2011     /// # Panics
2012     ///
2013     /// Panics if either type is associated with a different engine from the
2014     /// other.
matches(&self, other: &StructType) -> bool2015     pub fn matches(&self, other: &StructType) -> bool {
2016         assert!(self.comes_from_same_engine(other.engine()));
2017 
2018         self.engine()
2019             .signatures()
2020             .is_subtype(self.type_index(), other.type_index())
2021     }
2022 
fields_match( a: impl ExactSizeIterator<Item = FieldType>, b: impl ExactSizeIterator<Item = FieldType>, ) -> bool2023     fn fields_match(
2024         a: impl ExactSizeIterator<Item = FieldType>,
2025         b: impl ExactSizeIterator<Item = FieldType>,
2026     ) -> bool {
2027         a.len() >= b.len() && a.zip(b).all(|(a, b)| a.matches(&b))
2028     }
2029 
2030     /// Is struct type `a` precisely equal to struct type `b`?
2031     ///
2032     /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
2033     /// are not exactly the same struct type.
2034     ///
2035     /// # Panics
2036     ///
2037     /// Panics if either type is associated with a different engine from the
2038     /// other.
eq(a: &StructType, b: &StructType) -> bool2039     pub fn eq(a: &StructType, b: &StructType) -> bool {
2040         assert!(a.comes_from_same_engine(b.engine()));
2041         a.type_index() == b.type_index()
2042     }
2043 
comes_from_same_engine(&self, engine: &Engine) -> bool2044     pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
2045         Engine::same(self.registered_type().engine(), engine)
2046     }
2047 
type_index(&self) -> VMSharedTypeIndex2048     pub(crate) fn type_index(&self) -> VMSharedTypeIndex {
2049         self.registered_type().index()
2050     }
2051 
as_wasm_struct_type(&self) -> &WasmStructType2052     pub(crate) fn as_wasm_struct_type(&self) -> &WasmStructType {
2053         self.registered_type().unwrap_struct()
2054     }
2055 
registered_type(&self) -> &RegisteredType2056     pub(crate) fn registered_type(&self) -> &RegisteredType {
2057         &self.registered_type
2058     }
2059 
2060     /// Construct a `StructType` from a `WasmStructType`.
2061     ///
2062     /// This method should only be used when something has already registered --
2063     /// and is *keeping registered* -- any other concrete Wasm types referenced
2064     /// by the given `WasmStructType`.
2065     ///
2066     /// For example, this method may be called to convert an struct type from
2067     /// within a Wasm module's `ModuleTypes` since the Wasm module itself is
2068     /// holding a strong reference to all of its types, including any `(ref null
2069     /// <index>)` types used as the element type for this struct type.
from_wasm_struct_type( engine: &Engine, is_final: bool, is_shared: bool, supertype: Option<EngineOrModuleTypeIndex>, ty: WasmStructType, ) -> Result<StructType>2070     pub(crate) fn from_wasm_struct_type(
2071         engine: &Engine,
2072         is_final: bool,
2073         is_shared: bool,
2074         supertype: Option<EngineOrModuleTypeIndex>,
2075         ty: WasmStructType,
2076     ) -> Result<StructType> {
2077         const MAX_FIELDS: usize = 10_000;
2078         let fields_len = ty.fields.len();
2079         ensure!(
2080             fields_len <= MAX_FIELDS,
2081             "attempted to define a struct type with {fields_len} fields, but \
2082              that is more than the maximum supported number of fields \
2083              ({MAX_FIELDS})",
2084         );
2085 
2086         let ty = RegisteredType::new(
2087             engine,
2088             WasmSubType {
2089                 is_final,
2090                 supertype,
2091                 composite_type: WasmCompositeType {
2092                     shared: is_shared,
2093                     inner: WasmCompositeInnerType::Struct(ty),
2094                 },
2095             },
2096         )?;
2097         Ok(Self {
2098             registered_type: ty,
2099         })
2100     }
2101 
from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> StructType2102     pub(crate) fn from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> StructType {
2103         let ty = RegisteredType::root(engine, index);
2104         Self::from_registered_type(ty)
2105     }
2106 
from_registered_type(registered_type: RegisteredType) -> Self2107     pub(crate) fn from_registered_type(registered_type: RegisteredType) -> Self {
2108         debug_assert!(registered_type.is_struct());
2109         Self { registered_type }
2110     }
2111 }
2112 
2113 /// The type of a WebAssembly array.
2114 ///
2115 /// WebAssembly arrays are dynamically-sized, but not resizable. They contain
2116 /// either unpacked [`Val`][crate::Val]s or packed 8-/16-bit integers.
2117 ///
2118 /// # Subtyping and Equality
2119 ///
2120 /// `ArrayType` does not implement `Eq`, because reference types have a
2121 /// subtyping relationship, and so 99.99% of the time you actually want to check
2122 /// whether one type matches (i.e. is a subtype of) another type. You can use
2123 /// the [`ArrayType::matches`] method to perform these types of checks. If,
2124 /// however, you are in that 0.01% scenario where you need to check precise
2125 /// equality between types, you can use the [`ArrayType::eq`] method.
2126 //
2127 // TODO: Once we have array values, update above docs with a reference to the
2128 // future `Array::matches_ty` method
2129 #[derive(Debug, Clone, Hash)]
2130 pub struct ArrayType {
2131     registered_type: RegisteredType,
2132 }
2133 
2134 impl fmt::Display for ArrayType {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result2135     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2136         let field_ty = self.field_type();
2137         write!(f, "(array (field {field_ty}))")?;
2138         Ok(())
2139     }
2140 }
2141 
2142 impl ArrayType {
2143     /// Construct a new `ArrayType` with the given field type's mutability and
2144     /// storage type.
2145     ///
2146     /// The new `ArrayType` will be final and without a supertype.
2147     ///
2148     /// The result will be associated with the given engine, and attempts to use
2149     /// it with other engines will panic (for example, checking whether it is a
2150     /// subtype of another array type that is associated with a different
2151     /// engine).
2152     ///
2153     /// # Panics
2154     ///
2155     /// Panics if the given field type is not associated with the given engine.
new(engine: &Engine, field_type: FieldType) -> Self2156     pub fn new(engine: &Engine, field_type: FieldType) -> Self {
2157         Self::with_finality_and_supertype(engine, Finality::Final, None, field_type)
2158             .expect("cannot fail without a supertype")
2159     }
2160 
2161     /// Construct a new `StructType` with the given finality, supertype, and
2162     /// fields.
2163     ///
2164     /// The result will be associated with the given engine, and attempts to use
2165     /// it with other engines will panic (for example, checking whether it is a
2166     /// subtype of another struct type that is associated with a different
2167     /// engine).
2168     ///
2169     /// Returns an error if the supertype is final, or if this type does not
2170     /// match the supertype.
2171     ///
2172     /// # Panics
2173     ///
2174     /// Panics if the given field type is not associated with the given engine.
with_finality_and_supertype( engine: &Engine, finality: Finality, supertype: Option<&Self>, field_type: FieldType, ) -> Result<Self>2175     pub fn with_finality_and_supertype(
2176         engine: &Engine,
2177         finality: Finality,
2178         supertype: Option<&Self>,
2179         field_type: FieldType,
2180     ) -> Result<Self> {
2181         if let Some(supertype) = supertype {
2182             assert!(supertype.comes_from_same_engine(engine));
2183             ensure!(
2184                 supertype.finality().is_non_final(),
2185                 "cannot create a subtype of a final supertype"
2186             );
2187             ensure!(
2188                 field_type.matches(&supertype.field_type()),
2189                 "array field type must match its supertype's field type"
2190             );
2191         }
2192 
2193         // Same as in `FuncType::new`: we must prevent any `RegisteredType` in
2194         // `field_type` from being reclaimed while constructing this array type.
2195         let _registration = field_type
2196             .element_type
2197             .as_val_type()
2198             .and_then(|v| v.as_ref())
2199             .and_then(|r| r.heap_type().as_registered_type());
2200 
2201         assert!(field_type.comes_from_same_engine(engine));
2202         let wasm_ty = WasmArrayType(field_type.to_wasm_field_type());
2203 
2204         Ok(Self::from_wasm_array_type(
2205             engine,
2206             finality.is_final(),
2207             supertype.map(|ty| ty.type_index().into()),
2208             wasm_ty,
2209         )?)
2210     }
2211 
2212     /// Get the engine that this array type is associated with.
engine(&self) -> &Engine2213     pub fn engine(&self) -> &Engine {
2214         self.registered_type.engine()
2215     }
2216 
2217     /// Get the finality of this array type.
finality(&self) -> Finality2218     pub fn finality(&self) -> Finality {
2219         match self.registered_type.is_final {
2220             true => Finality::Final,
2221             false => Finality::NonFinal,
2222         }
2223     }
2224 
2225     /// Get the supertype of this array type, if any.
supertype(&self) -> Option<Self>2226     pub fn supertype(&self) -> Option<Self> {
2227         self.registered_type
2228             .supertype
2229             .map(|ty| Self::from_shared_type_index(self.engine(), ty.unwrap_engine_type_index()))
2230     }
2231 
2232     /// Get this array's underlying field type.
2233     ///
2234     /// The field type contains information about both this array type's
2235     /// mutability and the storage type used for its elements.
field_type(&self) -> FieldType2236     pub fn field_type(&self) -> FieldType {
2237         FieldType::from_wasm_field_type(self.engine(), &self.as_wasm_array_type().0)
2238     }
2239 
2240     /// Get this array type's mutability and whether its instances' elements can
2241     /// be updated or not.
2242     ///
2243     /// This is a convenience method providing a short-hand for
2244     /// `my_array_type.field_type().mutability()`.
mutability(&self) -> Mutability2245     pub fn mutability(&self) -> Mutability {
2246         if self.as_wasm_array_type().0.mutable {
2247             Mutability::Var
2248         } else {
2249             Mutability::Const
2250         }
2251     }
2252 
2253     /// Get the storage type used for this array type's elements.
2254     ///
2255     /// This is a convenience method providing a short-hand for
2256     /// `my_array_type.field_type().element_type()`.
element_type(&self) -> StorageType2257     pub fn element_type(&self) -> StorageType {
2258         StorageType::from_wasm_storage_type(
2259             self.engine(),
2260             &self.registered_type.unwrap_array().0.element_type,
2261         )
2262     }
2263 
2264     /// Does this array type match the other array type?
2265     ///
2266     /// That is, is this function type a subtype of the other array type?
2267     ///
2268     /// # Panics
2269     ///
2270     /// Panics if either type is associated with a different engine from the
2271     /// other.
matches(&self, other: &ArrayType) -> bool2272     pub fn matches(&self, other: &ArrayType) -> bool {
2273         assert!(self.comes_from_same_engine(other.engine()));
2274 
2275         self.engine()
2276             .signatures()
2277             .is_subtype(self.type_index(), other.type_index())
2278     }
2279 
2280     /// Is array type `a` precisely equal to array type `b`?
2281     ///
2282     /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
2283     /// are not exactly the same array type.
2284     ///
2285     /// # Panics
2286     ///
2287     /// Panics if either type is associated with a different engine from the
2288     /// other.
eq(a: &ArrayType, b: &ArrayType) -> bool2289     pub fn eq(a: &ArrayType, b: &ArrayType) -> bool {
2290         assert!(a.comes_from_same_engine(b.engine()));
2291         a.type_index() == b.type_index()
2292     }
2293 
comes_from_same_engine(&self, engine: &Engine) -> bool2294     pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
2295         Engine::same(self.registered_type.engine(), engine)
2296     }
2297 
2298     #[cfg(feature = "gc")]
registered_type(&self) -> &RegisteredType2299     pub(crate) fn registered_type(&self) -> &RegisteredType {
2300         &self.registered_type
2301     }
2302 
type_index(&self) -> VMSharedTypeIndex2303     pub(crate) fn type_index(&self) -> VMSharedTypeIndex {
2304         self.registered_type.index()
2305     }
2306 
as_wasm_array_type(&self) -> &WasmArrayType2307     pub(crate) fn as_wasm_array_type(&self) -> &WasmArrayType {
2308         self.registered_type.unwrap_array()
2309     }
2310 
2311     /// Construct a `ArrayType` from a `WasmArrayType`.
2312     ///
2313     /// This method should only be used when something has already registered --
2314     /// and is *keeping registered* -- any other concrete Wasm types referenced
2315     /// by the given `WasmArrayType`.
2316     ///
2317     /// For example, this method may be called to convert an array type from
2318     /// within a Wasm module's `ModuleTypes` since the Wasm module itself is
2319     /// holding a strong reference to all of its types, including any `(ref null
2320     /// <index>)` types used as the element type for this array type.
from_wasm_array_type( engine: &Engine, is_final: bool, supertype: Option<EngineOrModuleTypeIndex>, ty: WasmArrayType, ) -> Result<ArrayType>2321     pub(crate) fn from_wasm_array_type(
2322         engine: &Engine,
2323         is_final: bool,
2324         supertype: Option<EngineOrModuleTypeIndex>,
2325         ty: WasmArrayType,
2326     ) -> Result<ArrayType> {
2327         let ty = RegisteredType::new(
2328             engine,
2329             WasmSubType {
2330                 is_final,
2331                 supertype,
2332                 composite_type: WasmCompositeType {
2333                     shared: false,
2334                     inner: WasmCompositeInnerType::Array(ty),
2335                 },
2336             },
2337         )?;
2338         Ok(Self {
2339             registered_type: ty,
2340         })
2341     }
2342 
from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> ArrayType2343     pub(crate) fn from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> ArrayType {
2344         let ty = RegisteredType::root(engine, index);
2345         Self::from_registered_type(ty)
2346     }
2347 
from_registered_type(registered_type: RegisteredType) -> Self2348     pub(crate) fn from_registered_type(registered_type: RegisteredType) -> Self {
2349         debug_assert!(registered_type.is_array());
2350         Self { registered_type }
2351     }
2352 }
2353 
2354 /// The type of a WebAssembly function.
2355 ///
2356 /// WebAssembly functions can have 0 or more parameters and results.
2357 ///
2358 /// # Subtyping and Equality
2359 ///
2360 /// `FuncType` does not implement `Eq`, because reference types have a subtyping
2361 /// relationship, and so 99.99% of the time you actually want to check whether
2362 /// one type matches (i.e. is a subtype of) another type. You can use the
2363 /// [`FuncType::matches`] and [`Func::matches_ty`][crate::Func::matches_ty]
2364 /// methods to perform these types of checks. If, however, you are in that 0.01%
2365 /// scenario where you need to check precise equality between types, you can use
2366 /// the [`FuncType::eq`] method.
2367 #[derive(Debug, Clone, Hash)]
2368 pub struct FuncType {
2369     registered_type: RegisteredType,
2370 }
2371 
2372 impl Display for FuncType {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result2373     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2374         write!(f, "(type (func")?;
2375         if self.params().len() > 0 {
2376             write!(f, " (param")?;
2377             for p in self.params() {
2378                 write!(f, " {p}")?;
2379             }
2380             write!(f, ")")?;
2381         }
2382         if self.results().len() > 0 {
2383             write!(f, " (result")?;
2384             for r in self.results() {
2385                 write!(f, " {r}")?;
2386             }
2387             write!(f, ")")?;
2388         }
2389         write!(f, "))")
2390     }
2391 }
2392 
2393 impl FuncType {
2394     /// Creates a new function type from the given parameters and results.
2395     ///
2396     /// The function type returned will represent a function which takes
2397     /// `params` as arguments and returns `results` when it is finished.
2398     ///
2399     /// The resulting function type will be final and without a supertype.
2400     ///
2401     /// # Panics
2402     ///
2403     /// Panics if any parameter or value type is not associated with the given
2404     /// engine.
new( engine: &Engine, params: impl IntoIterator<Item = ValType>, results: impl IntoIterator<Item = ValType>, ) -> FuncType2405     pub fn new(
2406         engine: &Engine,
2407         params: impl IntoIterator<Item = ValType>,
2408         results: impl IntoIterator<Item = ValType>,
2409     ) -> FuncType {
2410         Self::with_finality_and_supertype(engine, Finality::Final, None, params, results)
2411             .expect("cannot fail without a supertype")
2412     }
2413 
2414     /// Like [`FuncType::new`] but returns an
2415     /// [`OutOfMemory`][crate::error::OutOfMemory] error on allocation failure.
try_new( engine: &Engine, params: impl IntoIterator<Item = ValType>, results: impl IntoIterator<Item = ValType>, ) -> Result<FuncType, OutOfMemory>2416     pub fn try_new(
2417         engine: &Engine,
2418         params: impl IntoIterator<Item = ValType>,
2419         results: impl IntoIterator<Item = ValType>,
2420     ) -> Result<FuncType, OutOfMemory> {
2421         Self::with_finality_and_supertype(engine, Finality::Final, None, params, results).map_err(
2422             |e| {
2423                 e.downcast::<OutOfMemory>()
2424                     .expect("cannot fail without a supertype, other than OOM")
2425             },
2426         )
2427     }
2428 
2429     /// Create a new function type with the given finality, supertype, parameter
2430     /// types, and result types.
2431     ///
2432     /// Returns an error if the supertype is final, or if this function type
2433     /// does not match the supertype.
2434     ///
2435     /// # Panics
2436     ///
2437     /// Panics if any parameter or value type is not associated with the given
2438     /// engine.
with_finality_and_supertype( engine: &Engine, finality: Finality, supertype: Option<&Self>, params: impl IntoIterator<Item = ValType>, results: impl IntoIterator<Item = ValType>, ) -> Result<Self>2439     pub fn with_finality_and_supertype(
2440         engine: &Engine,
2441         finality: Finality,
2442         supertype: Option<&Self>,
2443         params: impl IntoIterator<Item = ValType>,
2444         results: impl IntoIterator<Item = ValType>,
2445     ) -> Result<Self> {
2446         let params = params.into_iter();
2447         let results = results.into_iter();
2448 
2449         let mut wasmtime_params = TryVec::with_capacity({
2450             let size_hint = params.size_hint();
2451             let cap = size_hint.1.unwrap_or(size_hint.0);
2452             // Only reserve space if we have a supertype, as that is the only time
2453             // that this vec is used.
2454             supertype.is_some() as usize * cap
2455         })?;
2456 
2457         let mut wasmtime_results = TryVec::with_capacity({
2458             let size_hint = results.size_hint();
2459             let cap = size_hint.1.unwrap_or(size_hint.0);
2460             // Same as above.
2461             supertype.is_some() as usize * cap
2462         })?;
2463 
2464         // Keep any of our parameters' and results' `RegisteredType`s alive
2465         // across `Self::from_wasm_func_type`. If one of our given `ValType`s is
2466         // the only thing keeping a type in the registry, we don't want to
2467         // unregister it when we convert the `ValType` into a `WasmValType` just
2468         // before we register our new `WasmFuncType` that will reference it.
2469         let mut registrations = TryVec::new();
2470 
2471         let mut to_wasm_type =
2472             |ty: ValType, vec: &mut TryVec<_>| -> Result<WasmValType, OutOfMemory> {
2473                 assert!(ty.comes_from_same_engine(engine));
2474 
2475                 if supertype.is_some() {
2476                     vec.push(ty.clone())?;
2477                 }
2478 
2479                 if let Some(r) = ty.as_ref() {
2480                     if let Some(r) = r.heap_type().as_registered_type() {
2481                         registrations.push(r.clone())?;
2482                     }
2483                 }
2484 
2485                 Ok(ty.to_wasm_type())
2486             };
2487 
2488         let params: Box<[_]> = params
2489             .map(|p| to_wasm_type(p, &mut wasmtime_params))
2490             .try_collect()?;
2491         let results: Box<[_]> = results
2492             .map(|p| to_wasm_type(p, &mut wasmtime_results))
2493             .try_collect()?;
2494         let wasm_func_ty = WasmFuncType::new(params, results)?;
2495 
2496         if let Some(supertype) = supertype {
2497             assert!(supertype.comes_from_same_engine(engine));
2498             ensure!(
2499                 supertype.finality().is_non_final(),
2500                 "cannot create a subtype of a final supertype"
2501             );
2502             ensure!(
2503                 Self::matches_impl(
2504                     wasmtime_params.iter().cloned(),
2505                     supertype.params(),
2506                     wasmtime_results.iter().cloned(),
2507                     supertype.results()
2508                 ),
2509                 "function type must match its supertype: found (func{params}{results}), expected \
2510                  {supertype}",
2511                 params = if wasmtime_params.is_empty() {
2512                     String::new()
2513                 } else {
2514                     let mut s = format!(" (params");
2515                     for p in &wasmtime_params {
2516                         write!(&mut s, " {p}").unwrap();
2517                     }
2518                     s.push(')');
2519                     s
2520                 },
2521                 results = if wasmtime_results.is_empty() {
2522                     String::new()
2523                 } else {
2524                     let mut s = format!(" (results");
2525                     for r in &wasmtime_results {
2526                         write!(&mut s, " {r}").unwrap();
2527                     }
2528                     s.push(')');
2529                     s
2530                 },
2531             );
2532         }
2533 
2534         Ok(Self::from_wasm_func_type(
2535             engine,
2536             finality.is_final(),
2537             supertype.map(|ty| ty.type_index().into()),
2538             wasm_func_ty,
2539         )?)
2540     }
2541 
2542     /// Get the engine that this function type is associated with.
engine(&self) -> &Engine2543     pub fn engine(&self) -> &Engine {
2544         self.registered_type.engine()
2545     }
2546 
2547     /// Get the finality of this function type.
finality(&self) -> Finality2548     pub fn finality(&self) -> Finality {
2549         match self.registered_type.is_final {
2550             true => Finality::Final,
2551             false => Finality::NonFinal,
2552         }
2553     }
2554 
2555     /// Get the supertype of this function type, if any.
supertype(&self) -> Option<Self>2556     pub fn supertype(&self) -> Option<Self> {
2557         self.registered_type
2558             .supertype
2559             .map(|ty| Self::from_shared_type_index(self.engine(), ty.unwrap_engine_type_index()))
2560     }
2561 
2562     /// Get the `i`th parameter type.
2563     ///
2564     /// Returns `None` if `i` is out of bounds.
param(&self, i: usize) -> Option<ValType>2565     pub fn param(&self, i: usize) -> Option<ValType> {
2566         let engine = self.engine();
2567         self.registered_type
2568             .unwrap_func()
2569             .params()
2570             .get(i)
2571             .map(|ty| ValType::from_wasm_type(engine, ty))
2572     }
2573 
2574     /// Returns the list of parameter types for this function.
2575     #[inline]
params(&self) -> impl ExactSizeIterator<Item = ValType> + '_2576     pub fn params(&self) -> impl ExactSizeIterator<Item = ValType> + '_ {
2577         let engine = self.engine();
2578         self.registered_type
2579             .unwrap_func()
2580             .params()
2581             .iter()
2582             .map(|ty| ValType::from_wasm_type(engine, ty))
2583     }
2584 
2585     /// Get the `i`th result type.
2586     ///
2587     /// Returns `None` if `i` is out of bounds.
result(&self, i: usize) -> Option<ValType>2588     pub fn result(&self, i: usize) -> Option<ValType> {
2589         let engine = self.engine();
2590         self.registered_type
2591             .unwrap_func()
2592             .results()
2593             .get(i)
2594             .map(|ty| ValType::from_wasm_type(engine, ty))
2595     }
2596 
2597     /// Returns the list of result types for this function.
2598     #[inline]
results(&self) -> impl ExactSizeIterator<Item = ValType> + '_2599     pub fn results(&self) -> impl ExactSizeIterator<Item = ValType> + '_ {
2600         let engine = self.engine();
2601         self.registered_type
2602             .unwrap_func()
2603             .results()
2604             .iter()
2605             .map(|ty| ValType::from_wasm_type(engine, ty))
2606     }
2607 
2608     /// Does this function type match the other function type?
2609     ///
2610     /// That is, is this function type a subtype of the other function type?
2611     ///
2612     /// # Panics
2613     ///
2614     /// Panics if either type is associated with a different engine from the
2615     /// other.
matches(&self, other: &FuncType) -> bool2616     pub fn matches(&self, other: &FuncType) -> bool {
2617         assert!(self.comes_from_same_engine(other.engine()));
2618 
2619         // Avoid matching on structure for subtyping checks when we have
2620         // precisely the same type.
2621         if self.type_index() == other.type_index() {
2622             return true;
2623         }
2624 
2625         Self::matches_impl(
2626             self.params(),
2627             other.params(),
2628             self.results(),
2629             other.results(),
2630         )
2631     }
2632 
matches_impl( a_params: impl ExactSizeIterator<Item = ValType>, b_params: impl ExactSizeIterator<Item = ValType>, a_results: impl ExactSizeIterator<Item = ValType>, b_results: impl ExactSizeIterator<Item = ValType>, ) -> bool2633     fn matches_impl(
2634         a_params: impl ExactSizeIterator<Item = ValType>,
2635         b_params: impl ExactSizeIterator<Item = ValType>,
2636         a_results: impl ExactSizeIterator<Item = ValType>,
2637         b_results: impl ExactSizeIterator<Item = ValType>,
2638     ) -> bool {
2639         a_params.len() == b_params.len()
2640             && a_results.len() == b_results.len()
2641             // Params are contravariant and results are covariant. For more
2642             // details and a refresher on variance, read
2643             // https://github.com/bytecodealliance/wasm-tools/blob/f1d89a4/crates/wasmparser/src/readers/core/types/matches.rs#L137-L174
2644             && a_params
2645                 .zip(b_params)
2646                 .all(|(a, b)| b.matches(&a))
2647             && a_results
2648                 .zip(b_results)
2649                 .all(|(a, b)| a.matches(&b))
2650     }
2651 
2652     /// Is function type `a` precisely equal to function type `b`?
2653     ///
2654     /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
2655     /// are not exactly the same function type.
2656     ///
2657     /// # Panics
2658     ///
2659     /// Panics if either type is associated with a different engine from the
2660     /// other.
eq(a: &FuncType, b: &FuncType) -> bool2661     pub fn eq(a: &FuncType, b: &FuncType) -> bool {
2662         assert!(a.comes_from_same_engine(b.engine()));
2663         a.type_index() == b.type_index()
2664     }
2665 
comes_from_same_engine(&self, engine: &Engine) -> bool2666     pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
2667         Engine::same(self.registered_type.engine(), engine)
2668     }
2669 
type_index(&self) -> VMSharedTypeIndex2670     pub(crate) fn type_index(&self) -> VMSharedTypeIndex {
2671         self.registered_type.index()
2672     }
2673 
into_registered_type(self) -> RegisteredType2674     pub(crate) fn into_registered_type(self) -> RegisteredType {
2675         self.registered_type
2676     }
2677 
2678     /// Construct a `FuncType` from a `WasmFuncType`.
2679     ///
2680     /// This method should only be used when something has already registered --
2681     /// and is *keeping registered* -- any other concrete Wasm types referenced
2682     /// by the given `WasmFuncType`.
2683     ///
2684     /// For example, this method may be called to convert a function type from
2685     /// within a Wasm module's `ModuleTypes` since the Wasm module itself is
2686     /// holding a strong reference to all of its types, including any `(ref null
2687     /// <index>)` types used in the function's parameters and results.
from_wasm_func_type( engine: &Engine, is_final: bool, supertype: Option<EngineOrModuleTypeIndex>, ty: WasmFuncType, ) -> Result<FuncType, OutOfMemory>2688     pub(crate) fn from_wasm_func_type(
2689         engine: &Engine,
2690         is_final: bool,
2691         supertype: Option<EngineOrModuleTypeIndex>,
2692         ty: WasmFuncType,
2693     ) -> Result<FuncType, OutOfMemory> {
2694         let ty = RegisteredType::new(
2695             engine,
2696             WasmSubType {
2697                 is_final,
2698                 supertype,
2699                 composite_type: WasmCompositeType {
2700                     shared: false,
2701                     inner: WasmCompositeInnerType::Func(ty),
2702                 },
2703             },
2704         )?;
2705         Ok(Self {
2706             registered_type: ty,
2707         })
2708     }
2709 
from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> FuncType2710     pub(crate) fn from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> FuncType {
2711         let ty = RegisteredType::root(engine, index);
2712         Self::from_registered_type(ty)
2713     }
2714 
from_registered_type(registered_type: RegisteredType) -> Self2715     pub(crate) fn from_registered_type(registered_type: RegisteredType) -> Self {
2716         debug_assert!(registered_type.is_func());
2717         Self { registered_type }
2718     }
2719     /// Construct a func which returns results of default value, if each result type has a default value.
default_value(&self, mut store: impl AsContextMut) -> Result<Func>2720     pub fn default_value(&self, mut store: impl AsContextMut) -> Result<Func> {
2721         let dummy_results = self
2722             .results()
2723             .map(|ty| ty.default_value())
2724             .collect::<Option<Vec<_>>>()
2725             .ok_or_else(|| format_err!("function results do not have a default value"))?;
2726         Ok(Func::new(&mut store, self.clone(), move |_, _, results| {
2727             for (slot, dummy) in results.iter_mut().zip(dummy_results.iter()) {
2728                 *slot = *dummy;
2729             }
2730             Ok(())
2731         }))
2732     }
2733 }
2734 
2735 // Continuation types
2736 /// A WebAssembly continuation descriptor.
2737 #[derive(Debug, Clone, Hash)]
2738 pub struct ContType {
2739     registered_type: RegisteredType,
2740 }
2741 
2742 impl ContType {
2743     /// Get the engine that this function type is associated with.
engine(&self) -> &Engine2744     pub fn engine(&self) -> &Engine {
2745         self.registered_type.engine()
2746     }
2747 
comes_from_same_engine(&self, engine: &Engine) -> bool2748     pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
2749         Engine::same(self.registered_type.engine(), engine)
2750     }
2751 
type_index(&self) -> VMSharedTypeIndex2752     pub(crate) fn type_index(&self) -> VMSharedTypeIndex {
2753         self.registered_type.index()
2754     }
2755 
2756     /// Does this continuation type match the other continuation type?
2757     ///
2758     /// That is, is this continuation type a subtype of the other continuation type?
2759     ///
2760     /// # Panics
2761     ///
2762     /// Panics if either type is associated with a different engine from the
2763     /// other.
matches(&self, other: &ContType) -> bool2764     pub fn matches(&self, other: &ContType) -> bool {
2765         assert!(self.comes_from_same_engine(other.engine()));
2766 
2767         // Avoid matching on structure for subtyping checks when we have
2768         // precisely the same type.
2769         // TODO(dhil): Implement subtype check later.
2770         self.type_index() == other.type_index()
2771     }
2772 
from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> ContType2773     pub(crate) fn from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> ContType {
2774         let ty = RegisteredType::root(engine, index);
2775         assert!(ty.is_cont());
2776         Self {
2777             registered_type: ty,
2778         }
2779     }
2780 }
2781 
2782 // Exception types
2783 
2784 /// A WebAssembly exception-object signature type.
2785 ///
2786 /// This type captures the *signature* of an exception object. Note
2787 /// that the WebAssembly standard does not define concrete types in
2788 /// the heap-type lattice between `exn` (any exception object -- the
2789 /// top type) and `noexn` (the uninhabited bottom type). Wasmtime
2790 /// defines concrete types based on the *signature* -- that is, the
2791 /// function type that describes the signature of the exception
2792 /// payload values -- rather than the tag. The tag is a per-instance
2793 /// nominal entity (similar to a memory or a table) and is associated
2794 /// only with particular exception *objects*.
2795 #[derive(Debug, Clone, Hash)]
2796 pub struct ExnType {
2797     func_ty: FuncType,
2798     registered_type: RegisteredType,
2799 }
2800 
2801 impl fmt::Display for ExnType {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result2802     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2803         write!(f, "(exn {}", self.func_ty)?;
2804         for field in self.fields() {
2805             write!(f, " (field {field})")?;
2806         }
2807         write!(f, ")")?;
2808         Ok(())
2809     }
2810 }
2811 
2812 impl ExnType {
2813     /// Create a new `ExnType`.
2814     ///
2815     /// This function creates a new exception object type with the
2816     /// given signature, i.e., list of payload value types. This
2817     /// signature implies a tag type, and when instantiated at
2818     /// runtime, it must be associated with a tag of that type.
new(engine: &Engine, fields: impl IntoIterator<Item = ValType>) -> Result<ExnType>2819     pub fn new(engine: &Engine, fields: impl IntoIterator<Item = ValType>) -> Result<ExnType> {
2820         let fields: TryVec<_> = fields.into_iter().try_collect()?;
2821 
2822         // First, construct/intern a FuncType: we need this to exist
2823         // so we can hand out a TagType, and it also roots any nested registrations.
2824         let func_ty = FuncType::try_new(engine, fields.iter().cloned(), [])?;
2825 
2826         Self::_new(engine, fields, func_ty)
2827     }
2828 
2829     /// Create a new `ExnType` from an existing `TagType`.
2830     ///
2831     /// This function creates a new exception object type with the
2832     /// signature represented by the tag. The signature must have no
2833     /// result values, i.e., must be of the form `(T1, T2, ...) ->
2834     /// ()`.
from_tag_type(tag: &TagType) -> Result<ExnType>2835     pub fn from_tag_type(tag: &TagType) -> Result<ExnType> {
2836         let func_ty = tag.ty();
2837 
2838         // Check that the tag's signature type has no results.
2839         ensure!(
2840             func_ty.results().len() == 0,
2841             "Cannot create an exception type from a tag type with results in the signature"
2842         );
2843 
2844         Self::_new(tag.ty.engine(), func_ty.params(), func_ty.clone())
2845     }
2846 
_new( engine: &Engine, fields: impl IntoIterator<Item = ValType>, func_ty: FuncType, ) -> Result<ExnType>2847     fn _new(
2848         engine: &Engine,
2849         fields: impl IntoIterator<Item = ValType>,
2850         func_ty: FuncType,
2851     ) -> Result<ExnType> {
2852         let mut wasm_fields = TryVec::new();
2853         for ty in fields.into_iter() {
2854             assert!(ty.comes_from_same_engine(engine));
2855             wasm_fields.push(WasmFieldType {
2856                 element_type: WasmStorageType::Val(ty.to_wasm_type()),
2857                 mutable: false,
2858             })?;
2859         }
2860 
2861         let ty = RegisteredType::new(
2862             engine,
2863             WasmSubType {
2864                 is_final: true,
2865                 supertype: None,
2866                 composite_type: WasmCompositeType {
2867                     shared: false,
2868                     inner: WasmCompositeInnerType::Exn(WasmExnType {
2869                         func_ty: EngineOrModuleTypeIndex::Engine(func_ty.type_index()),
2870                         fields: wasm_fields.into_boxed_slice()?,
2871                     }),
2872                 },
2873             },
2874         )?;
2875 
2876         Ok(ExnType {
2877             func_ty,
2878             registered_type: ty,
2879         })
2880     }
2881 
2882     /// Get the tag type that this exception type is associated with.
tag_type(&self) -> TagType2883     pub fn tag_type(&self) -> TagType {
2884         TagType {
2885             ty: self.func_ty.clone(),
2886         }
2887     }
2888 
2889     /// Get the `i`th field type.
2890     ///
2891     /// Returns `None` if `i` is out of bounds.
field(&self, i: usize) -> Option<FieldType>2892     pub fn field(&self, i: usize) -> Option<FieldType> {
2893         let engine = self.engine();
2894         self.as_wasm_exn_type()
2895             .fields
2896             .get(i)
2897             .map(|ty| FieldType::from_wasm_field_type(engine, ty))
2898     }
2899 
2900     /// Returns the list of field types for this function.
2901     #[inline]
fields(&self) -> impl ExactSizeIterator<Item = FieldType> + '_2902     pub fn fields(&self) -> impl ExactSizeIterator<Item = FieldType> + '_ {
2903         let engine = self.engine();
2904         self.as_wasm_exn_type()
2905             .fields
2906             .iter()
2907             .map(|ty| FieldType::from_wasm_field_type(engine, ty))
2908     }
2909 
2910     /// Get the engine that this exception type is associated with.
engine(&self) -> &Engine2911     pub fn engine(&self) -> &Engine {
2912         self.registered_type.engine()
2913     }
2914 
comes_from_same_engine(&self, engine: &Engine) -> bool2915     pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
2916         Engine::same(self.registered_type.engine(), engine)
2917     }
2918 
as_wasm_exn_type(&self) -> &WasmExnType2919     pub(crate) fn as_wasm_exn_type(&self) -> &WasmExnType {
2920         self.registered_type().unwrap_exn()
2921     }
2922 
type_index(&self) -> VMSharedTypeIndex2923     pub(crate) fn type_index(&self) -> VMSharedTypeIndex {
2924         self.registered_type.index()
2925     }
2926 
2927     /// Does this exception type match the other exception type?
2928     ///
2929     /// That is, is this exception type a subtype of the other exception type?
2930     ///
2931     /// # Panics
2932     ///
2933     /// Panics if either type is associated with a different engine from the
2934     /// other.
matches(&self, other: &ExnType) -> bool2935     pub fn matches(&self, other: &ExnType) -> bool {
2936         assert!(self.comes_from_same_engine(other.engine()));
2937 
2938         // We have no concrete-exception-type subtyping; concrete
2939         // exception types are only (mutually, trivially) subtypes if
2940         // they are exactly equal.
2941         self.type_index() == other.type_index()
2942     }
2943 
registered_type(&self) -> &RegisteredType2944     pub(crate) fn registered_type(&self) -> &RegisteredType {
2945         &self.registered_type
2946     }
2947 
from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> ExnType2948     pub(crate) fn from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> ExnType {
2949         let ty = RegisteredType::root(engine, index);
2950         assert!(ty.is_exn());
2951         let func_ty = FuncType::from_shared_type_index(
2952             engine,
2953             ty.unwrap_exn().func_ty.unwrap_engine_type_index(),
2954         );
2955         Self {
2956             func_ty,
2957             registered_type: ty,
2958         }
2959     }
2960 }
2961 
2962 // Global Types
2963 
2964 /// A WebAssembly global descriptor.
2965 ///
2966 /// This type describes an instance of a global in a WebAssembly module. Globals
2967 /// are local to an [`Instance`](crate::Instance) and are either immutable or
2968 /// mutable.
2969 #[derive(Debug, Clone, Hash)]
2970 pub struct GlobalType {
2971     content: ValType,
2972     mutability: Mutability,
2973 }
2974 
2975 impl GlobalType {
2976     /// Creates a new global descriptor of the specified `content` type and
2977     /// whether or not it's mutable.
new(content: ValType, mutability: Mutability) -> GlobalType2978     pub fn new(content: ValType, mutability: Mutability) -> GlobalType {
2979         GlobalType {
2980             content,
2981             mutability,
2982         }
2983     }
2984 
2985     /// Returns the value type of this global descriptor.
content(&self) -> &ValType2986     pub fn content(&self) -> &ValType {
2987         &self.content
2988     }
2989 
2990     /// Returns whether or not this global is mutable.
mutability(&self) -> Mutability2991     pub fn mutability(&self) -> Mutability {
2992         self.mutability
2993     }
2994 
2995     /// Returns `None` if the wasmtime global has a type that we can't
2996     /// represent, but that should only very rarely happen and indicate a bug.
from_wasmtime_global(engine: &Engine, global: &Global) -> GlobalType2997     pub(crate) fn from_wasmtime_global(engine: &Engine, global: &Global) -> GlobalType {
2998         let ty = ValType::from_wasm_type(engine, &global.wasm_ty);
2999         let mutability = if global.mutability {
3000             Mutability::Var
3001         } else {
3002             Mutability::Const
3003         };
3004         GlobalType::new(ty, mutability)
3005     }
3006     /// Construct a new global import with this type’s default value.
3007     ///
3008     /// This creates a host `Global` in the given store initialized to the
3009     /// type’s zero/null default (e.g. `0` for numeric globals, `null_ref` for refs).
default_value(&self, store: impl AsContextMut) -> Result<RuntimeGlobal>3010     pub fn default_value(&self, store: impl AsContextMut) -> Result<RuntimeGlobal> {
3011         let val = self
3012             .content()
3013             .default_value()
3014             .ok_or_else(|| format_err!("global type has no default value"))?;
3015         RuntimeGlobal::new(store, self.clone(), val)
3016     }
3017 
into_registered_type(self) -> Option<RegisteredType>3018     pub(crate) fn into_registered_type(self) -> Option<RegisteredType> {
3019         self.content.into_registered_type()
3020     }
3021 }
3022 
3023 // Tag Types
3024 
3025 /// A descriptor for a tag in a WebAssembly module.
3026 ///
3027 /// Note that tags are local to an [`Instance`](crate::Instance),
3028 /// i.e., are a runtime entity. However, a tag is associated with a
3029 /// function type, and so has a kind of static type. This descriptor
3030 /// is a thin wrapper around a `FuncType` representing the function
3031 /// type of a tag.
3032 #[derive(Debug, Clone, Hash)]
3033 pub struct TagType {
3034     ty: FuncType,
3035 }
3036 
3037 impl TagType {
3038     /// Creates a new global descriptor of the specified type.
new(ty: FuncType) -> TagType3039     pub fn new(ty: FuncType) -> TagType {
3040         TagType { ty }
3041     }
3042 
3043     /// Returns the underlying function type of this tag descriptor.
ty(&self) -> &FuncType3044     pub fn ty(&self) -> &FuncType {
3045         &self.ty
3046     }
3047 
from_wasmtime_tag(engine: &Engine, tag: &Tag) -> TagType3048     pub(crate) fn from_wasmtime_tag(engine: &Engine, tag: &Tag) -> TagType {
3049         let ty = FuncType::from_shared_type_index(engine, tag.signature.unwrap_engine_type_index());
3050         TagType { ty }
3051     }
3052 
3053     /// Construct a new default tag with this type.
3054     ///
3055     /// This creates a host `Tag` in the given store. Tag instances
3056     /// have no content other than their type, so this "default" value
3057     /// is identical to ordinary host tag allocation.
default_value(&self, store: impl AsContextMut) -> Result<RuntimeTag>3058     pub fn default_value(&self, store: impl AsContextMut) -> Result<RuntimeTag> {
3059         RuntimeTag::new(store, self)
3060     }
3061 }
3062 
3063 // Table Types
3064 
3065 /// A descriptor for a table in a WebAssembly module.
3066 ///
3067 /// Tables are contiguous chunks of a specific element, typically a `funcref` or
3068 /// an `externref`. The most common use for tables is a function table through
3069 /// which `call_indirect` can invoke other functions.
3070 #[derive(Debug, Clone, Hash)]
3071 pub struct TableType {
3072     // Keep a `wasmtime::RefType` so that `TableType::element` doesn't need to
3073     // take an `&Engine`.
3074     element: RefType,
3075     ty: Table,
3076 }
3077 
3078 impl TableType {
3079     /// Creates a new table descriptor which will contain the specified
3080     /// `element` and have the `limits` applied to its length.
new(element: RefType, min: u32, max: Option<u32>) -> TableType3081     pub fn new(element: RefType, min: u32, max: Option<u32>) -> TableType {
3082         let ref_type = element.to_wasm_type();
3083 
3084         debug_assert!(
3085             ref_type.is_canonicalized_for_runtime_usage(),
3086             "should be canonicalized for runtime usage: {ref_type:?}"
3087         );
3088 
3089         let limits = Limits {
3090             min: u64::from(min),
3091             max: max.map(|x| u64::from(x)),
3092         };
3093 
3094         TableType {
3095             element,
3096             ty: Table {
3097                 idx_type: IndexType::I32,
3098                 limits,
3099                 ref_type,
3100             },
3101         }
3102     }
3103 
3104     /// Crates a new descriptor for a 64-bit table.
3105     ///
3106     /// Note that 64-bit tables are part of the memory64 proposal for
3107     /// WebAssembly which is not standardized yet.
new64(element: RefType, min: u64, max: Option<u64>) -> TableType3108     pub fn new64(element: RefType, min: u64, max: Option<u64>) -> TableType {
3109         let ref_type = element.to_wasm_type();
3110 
3111         debug_assert!(
3112             ref_type.is_canonicalized_for_runtime_usage(),
3113             "should be canonicalized for runtime usage: {ref_type:?}"
3114         );
3115 
3116         TableType {
3117             element,
3118             ty: Table {
3119                 ref_type,
3120                 idx_type: IndexType::I64,
3121                 limits: Limits { min, max },
3122             },
3123         }
3124     }
3125 
3126     /// Returns whether or not this table is a 64-bit table.
3127     ///
3128     /// Note that 64-bit tables are part of the memory64 proposal for
3129     /// WebAssembly which is not standardized yet.
is_64(&self) -> bool3130     pub fn is_64(&self) -> bool {
3131         matches!(self.ty.idx_type, IndexType::I64)
3132     }
3133 
3134     /// Returns the element value type of this table.
element(&self) -> &RefType3135     pub fn element(&self) -> &RefType {
3136         &self.element
3137     }
3138 
3139     /// Returns minimum number of elements this table must have
minimum(&self) -> u643140     pub fn minimum(&self) -> u64 {
3141         self.ty.limits.min
3142     }
3143 
3144     /// Returns the optionally-specified maximum number of elements this table
3145     /// can have.
3146     ///
3147     /// If this returns `None` then the table is not limited in size.
maximum(&self) -> Option<u64>3148     pub fn maximum(&self) -> Option<u64> {
3149         self.ty.limits.max
3150     }
3151 
from_wasmtime_table(engine: &Engine, table: &Table) -> TableType3152     pub(crate) fn from_wasmtime_table(engine: &Engine, table: &Table) -> TableType {
3153         let element = RefType::from_wasm_type(engine, &table.ref_type);
3154         TableType {
3155             element,
3156             ty: *table,
3157         }
3158     }
3159 
wasmtime_table(&self) -> &Table3160     pub(crate) fn wasmtime_table(&self) -> &Table {
3161         &self.ty
3162     }
3163     /// Construct a new table import whose entries are filled with this type’s default.
3164     ///
3165     /// Creates a host `Table` in the store with its initial size and element
3166     /// type’s default (e.g. `null_ref` for nullable refs).
default_value(&self, store: impl AsContextMut) -> Result<RuntimeTable>3167     pub fn default_value(&self, store: impl AsContextMut) -> Result<RuntimeTable> {
3168         let val: ValType = self.element().clone().into();
3169         let init_val = val
3170             .default_value()
3171             .context("table element type does not have a default value")?
3172             .ref_()
3173             .unwrap();
3174         RuntimeTable::new(store, self.clone(), init_val)
3175     }
3176 }
3177 
3178 // Memory Types
3179 
3180 /// A builder for [`MemoryType`][crate::MemoryType]s.
3181 ///
3182 /// A new builder can be constructed via its `Default` implementation.
3183 ///
3184 /// When you're done configuring, get the underlying
3185 /// [`MemoryType`][crate::MemoryType] by calling the
3186 /// [`build`][crate::MemoryTypeBuilder::build] method.
3187 ///
3188 /// # Example
3189 ///
3190 /// ```
3191 /// # fn foo() -> wasmtime::Result<()> {
3192 /// use wasmtime::MemoryTypeBuilder;
3193 ///
3194 /// let memory_type = MemoryTypeBuilder::new()
3195 ///     // Set the minimum size, in pages.
3196 ///     .min(4096)
3197 ///     // Set the maximum size, in pages.
3198 ///     .max(Some(4096))
3199 ///     // Set the page size to 1 byte (aka 2**0).
3200 ///     .page_size_log2(0)
3201 ///     // Get the underlying memory type.
3202 ///     .build()?;
3203 /// #   Ok(())
3204 /// # }
3205 /// ```
3206 pub struct MemoryTypeBuilder {
3207     ty: Memory,
3208 }
3209 
3210 impl Default for MemoryTypeBuilder {
default() -> Self3211     fn default() -> Self {
3212         MemoryTypeBuilder {
3213             ty: Memory {
3214                 idx_type: IndexType::I32,
3215                 limits: Limits { min: 0, max: None },
3216                 shared: false,
3217                 page_size_log2: Memory::DEFAULT_PAGE_SIZE_LOG2,
3218             },
3219         }
3220     }
3221 }
3222 
3223 impl MemoryTypeBuilder {
3224     /// Create a new builder for a [`MemoryType`] with the default settings.
3225     ///
3226     /// By default memory types have the following properties:
3227     ///
3228     /// * The minimum memory size is 0 pages.
3229     /// * The maximum memory size is unspecified.
3230     /// * Memories use 32-bit indexes.
3231     /// * The page size is 64KiB.
3232     ///
3233     /// Each option can be configured through the methods on the returned
3234     /// builder.
new() -> MemoryTypeBuilder3235     pub fn new() -> MemoryTypeBuilder {
3236         MemoryTypeBuilder::default()
3237     }
3238 
validate(&self) -> Result<()>3239     fn validate(&self) -> Result<()> {
3240         if self
3241             .ty
3242             .limits
3243             .max
3244             .map_or(false, |max| max < self.ty.limits.min)
3245         {
3246             bail!("maximum page size cannot be smaller than the minimum page size");
3247         }
3248 
3249         match self.ty.page_size_log2 {
3250             0 | Memory::DEFAULT_PAGE_SIZE_LOG2 => {}
3251             x => bail!(
3252                 "page size must be 2**16 or 2**0, but was given 2**{x}; note \
3253                  that future Wasm extensions might allow any power of two page \
3254                  size, but only 2**16 and 2**0 are currently valid",
3255             ),
3256         }
3257 
3258         if self.ty.shared && self.ty.limits.max.is_none() {
3259             bail!("shared memories must have a maximum size");
3260         }
3261 
3262         let absolute_max = self.ty.max_size_based_on_index_type();
3263         let min = self
3264             .ty
3265             .minimum_byte_size()
3266             .context("memory's minimum byte size must fit in a u64")?;
3267         if min > absolute_max {
3268             bail!("minimum size is too large for this memory type's index type");
3269         }
3270         if self
3271             .ty
3272             .maximum_byte_size()
3273             .map_or(false, |max| max > absolute_max)
3274         {
3275             bail!("maximum size is too large for this memory type's index type");
3276         }
3277 
3278         Ok(())
3279     }
3280 
3281     /// Set the minimum size, in units of pages, for the memory type being
3282     /// built.
3283     ///
3284     /// The default minimum is `0`.
min(&mut self, minimum: u64) -> &mut Self3285     pub fn min(&mut self, minimum: u64) -> &mut Self {
3286         self.ty.limits.min = minimum;
3287         self
3288     }
3289 
3290     /// Set the maximum size, in units of pages, for the memory type being
3291     /// built.
3292     ///
3293     /// The default maximum is `None`.
max(&mut self, maximum: Option<u64>) -> &mut Self3294     pub fn max(&mut self, maximum: Option<u64>) -> &mut Self {
3295         self.ty.limits.max = maximum;
3296         self
3297     }
3298 
3299     /// Set whether this is a 64-bit memory or not.
3300     ///
3301     /// If a memory is not a 64-bit memory, then it is a 32-bit memory.
3302     ///
3303     /// The default is `false`, aka 32-bit memories.
3304     ///
3305     /// Note that 64-bit memories are part of [the memory64
3306     /// proposal](https://github.com/WebAssembly/memory64) for WebAssembly which
3307     /// is not fully standardized yet.
memory64(&mut self, memory64: bool) -> &mut Self3308     pub fn memory64(&mut self, memory64: bool) -> &mut Self {
3309         self.ty.idx_type = match memory64 {
3310             true => IndexType::I64,
3311             false => IndexType::I32,
3312         };
3313         self
3314     }
3315 
3316     /// Set the sharedness for the memory type being built.
3317     ///
3318     /// The default is `false`, aka unshared.
3319     ///
3320     /// Note that shared memories are part of [the threads
3321     /// proposal](https://github.com/WebAssembly/threads) for WebAssembly which
3322     /// is not fully standardized yet.
shared(&mut self, shared: bool) -> &mut Self3323     pub fn shared(&mut self, shared: bool) -> &mut Self {
3324         self.ty.shared = shared;
3325         self
3326     }
3327 
3328     /// Set the log base 2 of the page size, in bytes, for the memory type being
3329     /// built.
3330     ///
3331     /// The default value is `16`, which results in the default Wasm page size
3332     /// of 64KiB (aka 2<sup>16</sup> or 65536).
3333     ///
3334     /// Other than `16`, the only valid value is `0`, which results in a page
3335     /// size of one byte (aka 2<sup>0</sup>). Single-byte page sizes can be used
3336     /// to get fine-grained control over a Wasm memory's resource consumption
3337     /// and run Wasm in embedded environments with less than 64KiB of RAM, for
3338     /// example.
3339     ///
3340     /// Future extensions to the core WebAssembly language might relax these
3341     /// constraints and introduce more valid page sizes, such as any power of
3342     /// two between 1 and 65536 inclusive.
3343     ///
3344     /// Note that non-default page sizes are part of [the custom-page-sizes
3345     /// proposal](https://github.com/WebAssembly/custom-page-sizes) for
3346     /// WebAssembly which is not fully standardized yet.
page_size_log2(&mut self, page_size_log2: u8) -> &mut Self3347     pub fn page_size_log2(&mut self, page_size_log2: u8) -> &mut Self {
3348         self.ty.page_size_log2 = page_size_log2;
3349         self
3350     }
3351 
3352     /// Get the underlying memory type that this builder has been building.
3353     ///
3354     /// # Errors
3355     ///
3356     /// Returns an error if the configured memory type is invalid, for example
3357     /// if the maximum size is smaller than the minimum size.
build(&self) -> Result<MemoryType>3358     pub fn build(&self) -> Result<MemoryType> {
3359         self.validate()?;
3360         Ok(MemoryType { ty: self.ty })
3361     }
3362 }
3363 
3364 /// A descriptor for a WebAssembly memory type.
3365 ///
3366 /// Memories are described in units of pages (64KB) and represent contiguous
3367 /// chunks of addressable memory.
3368 #[derive(Debug, Clone, Hash, Eq, PartialEq)]
3369 pub struct MemoryType {
3370     ty: Memory,
3371 }
3372 
3373 impl MemoryType {
3374     /// Creates a new descriptor for a 32-bit WebAssembly memory given the
3375     /// specified limits of the memory.
3376     ///
3377     /// The `minimum` and `maximum` values here are specified in units of
3378     /// WebAssembly pages, which are 64KiB by default. Use
3379     /// [`MemoryTypeBuilder`][crate::MemoryTypeBuilder] if you want a
3380     /// non-default page size.
3381     ///
3382     /// # Panics
3383     ///
3384     /// Panics if the minimum is greater than the maximum or if the minimum or
3385     /// maximum number of pages can result in a byte size that is not
3386     /// addressable with a 32-bit integer.
new(minimum: u32, maximum: Option<u32>) -> MemoryType3387     pub fn new(minimum: u32, maximum: Option<u32>) -> MemoryType {
3388         MemoryTypeBuilder::default()
3389             .min(minimum.into())
3390             .max(maximum.map(Into::into))
3391             .build()
3392             .unwrap()
3393     }
3394 
3395     /// Creates a new descriptor for a 64-bit WebAssembly memory given the
3396     /// specified limits of the memory.
3397     ///
3398     /// The `minimum` and `maximum` values here are specified in units of
3399     /// WebAssembly pages, which are 64KiB by default. Use
3400     /// [`MemoryTypeBuilder`][crate::MemoryTypeBuilder] if you want a
3401     /// non-default page size.
3402     ///
3403     /// Note that 64-bit memories are part of [the memory64
3404     /// proposal](https://github.com/WebAssembly/memory64) for WebAssembly which
3405     /// is not fully standardized yet.
3406     ///
3407     /// # Panics
3408     ///
3409     /// Panics if the minimum is greater than the maximum or if the minimum or
3410     /// maximum number of pages can result in a byte size that is not
3411     /// addressable with a 64-bit integer.
new64(minimum: u64, maximum: Option<u64>) -> MemoryType3412     pub fn new64(minimum: u64, maximum: Option<u64>) -> MemoryType {
3413         MemoryTypeBuilder::default()
3414             .memory64(true)
3415             .min(minimum)
3416             .max(maximum)
3417             .build()
3418             .unwrap()
3419     }
3420 
3421     /// Creates a new descriptor for shared WebAssembly memory given the
3422     /// specified limits of the memory.
3423     ///
3424     /// The `minimum` and `maximum` values here are specified in units of
3425     /// WebAssembly pages, which are 64KiB by default. Use
3426     /// [`MemoryTypeBuilder`][crate::MemoryTypeBuilder] if you want a
3427     /// non-default page size.
3428     ///
3429     /// Note that shared memories are part of [the threads
3430     /// proposal](https://github.com/WebAssembly/threads) for WebAssembly which
3431     /// is not fully standardized yet.
3432     ///
3433     /// # Panics
3434     ///
3435     /// Panics if the minimum is greater than the maximum or if the minimum or
3436     /// maximum number of pages can result in a byte size that is not
3437     /// addressable with a 32-bit integer.
shared(minimum: u32, maximum: u32) -> MemoryType3438     pub fn shared(minimum: u32, maximum: u32) -> MemoryType {
3439         MemoryTypeBuilder::default()
3440             .shared(true)
3441             .min(minimum.into())
3442             .max(Some(maximum.into()))
3443             .build()
3444             .unwrap()
3445     }
3446 
3447     /// Creates a new [`MemoryTypeBuilder`] to configure all the various knobs
3448     /// of the final memory type being created.
3449     ///
3450     /// This is a convenience function for [`MemoryTypeBuilder::new`].
builder() -> MemoryTypeBuilder3451     pub fn builder() -> MemoryTypeBuilder {
3452         MemoryTypeBuilder::new()
3453     }
3454 
3455     /// Returns whether this is a 64-bit memory or not.
3456     ///
3457     /// Note that 64-bit memories are part of the memory64 proposal for
3458     /// WebAssembly which is not standardized yet.
is_64(&self) -> bool3459     pub fn is_64(&self) -> bool {
3460         matches!(self.ty.idx_type, IndexType::I64)
3461     }
3462 
3463     /// Returns whether this is a shared memory or not.
3464     ///
3465     /// Note that shared memories are part of the threads proposal for
3466     /// WebAssembly which is not standardized yet.
is_shared(&self) -> bool3467     pub fn is_shared(&self) -> bool {
3468         self.ty.shared
3469     }
3470 
3471     /// Returns minimum number of WebAssembly pages this memory must have.
3472     ///
3473     /// Note that the return value, while a `u64`, will always fit into a `u32`
3474     /// for 32-bit memories.
minimum(&self) -> u643475     pub fn minimum(&self) -> u64 {
3476         self.ty.limits.min
3477     }
3478 
3479     /// Returns the optionally-specified maximum number of pages this memory
3480     /// can have.
3481     ///
3482     /// If this returns `None` then the memory is not limited in size.
3483     ///
3484     /// Note that the return value, while a `u64`, will always fit into a `u32`
3485     /// for 32-bit memories.
maximum(&self) -> Option<u64>3486     pub fn maximum(&self) -> Option<u64> {
3487         self.ty.limits.max
3488     }
3489 
3490     /// This memory's page size, in bytes.
page_size(&self) -> u643491     pub fn page_size(&self) -> u64 {
3492         self.ty.page_size()
3493     }
3494 
3495     /// The log2 of this memory's page size, in bytes.
page_size_log2(&self) -> u83496     pub fn page_size_log2(&self) -> u8 {
3497         self.ty.page_size_log2
3498     }
3499 
from_wasmtime_memory(memory: &Memory) -> MemoryType3500     pub(crate) fn from_wasmtime_memory(memory: &Memory) -> MemoryType {
3501         MemoryType { ty: *memory }
3502     }
3503 
wasmtime_memory(&self) -> &Memory3504     pub(crate) fn wasmtime_memory(&self) -> &Memory {
3505         &self.ty
3506     }
3507     /// Construct a new memory import initialized to this memory type’s default
3508     /// state.
3509     ///
3510     /// Returns a host `Memory` or `SharedMemory` depending on if this is a
3511     /// shared memory type or not. The memory's type will have the same type as
3512     /// `self` and the initial contents of the memory, if any, will be all zero.
default_value(&self, store: impl AsContextMut) -> Result<Extern>3513     pub fn default_value(&self, store: impl AsContextMut) -> Result<Extern> {
3514         Ok(if self.is_shared() {
3515             #[cfg(feature = "threads")]
3516             {
3517                 let store = store.as_context();
3518                 Extern::SharedMemory(crate::SharedMemory::new(store.engine(), self.clone())?)
3519             }
3520             #[cfg(not(feature = "threads"))]
3521             {
3522                 bail!("creation of shared memories disabled at compile time")
3523             }
3524         } else {
3525             Extern::Memory(crate::Memory::new(store, self.clone())?)
3526         })
3527     }
3528 }
3529 
3530 // Import Types
3531 
3532 /// A descriptor for an imported value into a wasm module.
3533 ///
3534 /// This type is primarily accessed from the
3535 /// [`Module::imports`](crate::Module::imports) API. Each [`ImportType`]
3536 /// describes an import into the wasm module with the module/name that it's
3537 /// imported from as well as the type of item that's being imported.
3538 #[derive(Clone)]
3539 pub struct ImportType<'module> {
3540     /// The module of the import.
3541     module: &'module str,
3542 
3543     /// The field of the import.
3544     name: &'module str,
3545 
3546     /// The type of the import.
3547     ty: EntityType,
3548     types: &'module ModuleTypes,
3549     engine: &'module Engine,
3550 }
3551 
3552 impl<'module> ImportType<'module> {
3553     /// Creates a new import descriptor which comes from `module` and `name` and
3554     /// is of type `ty`.
new( module: &'module str, name: &'module str, ty: EntityType, types: &'module ModuleTypes, engine: &'module Engine, ) -> ImportType<'module>3555     pub(crate) fn new(
3556         module: &'module str,
3557         name: &'module str,
3558         ty: EntityType,
3559         types: &'module ModuleTypes,
3560         engine: &'module Engine,
3561     ) -> ImportType<'module> {
3562         assert!(ty.is_canonicalized_for_runtime_usage());
3563         ImportType {
3564             module,
3565             name,
3566             ty,
3567             types,
3568             engine,
3569         }
3570     }
3571 
3572     /// Returns the module name that this import is expected to come from.
module(&self) -> &'module str3573     pub fn module(&self) -> &'module str {
3574         self.module
3575     }
3576 
3577     /// Returns the field name of the module that this import is expected to
3578     /// come from.
name(&self) -> &'module str3579     pub fn name(&self) -> &'module str {
3580         self.name
3581     }
3582 
3583     /// Returns the expected type of this import.
ty(&self) -> ExternType3584     pub fn ty(&self) -> ExternType {
3585         ExternType::from_wasmtime(self.engine, self.types, &self.ty)
3586     }
3587 }
3588 
3589 impl<'module> fmt::Debug for ImportType<'module> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result3590     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3591         f.debug_struct("ImportType")
3592             .field("module", &self.module())
3593             .field("name", &self.name())
3594             .field("ty", &self.ty())
3595             .finish()
3596     }
3597 }
3598 
3599 // Export Types
3600 
3601 /// A descriptor for an exported WebAssembly value.
3602 ///
3603 /// This type is primarily accessed from the
3604 /// [`Module::exports`](crate::Module::exports) accessor and describes what
3605 /// names are exported from a wasm module and the type of the item that is
3606 /// exported.
3607 #[derive(Clone)]
3608 pub struct ExportType<'module> {
3609     /// The name of the export.
3610     name: &'module str,
3611 
3612     /// The type of the export.
3613     ty: EntityType,
3614     types: &'module ModuleTypes,
3615     engine: &'module Engine,
3616 }
3617 
3618 impl<'module> ExportType<'module> {
3619     /// Creates a new export which is exported with the given `name` and has the
3620     /// given `ty`.
new( name: &'module str, ty: EntityType, types: &'module ModuleTypes, engine: &'module Engine, ) -> ExportType<'module>3621     pub(crate) fn new(
3622         name: &'module str,
3623         ty: EntityType,
3624         types: &'module ModuleTypes,
3625         engine: &'module Engine,
3626     ) -> ExportType<'module> {
3627         ExportType {
3628             name,
3629             ty,
3630             types,
3631             engine,
3632         }
3633     }
3634 
3635     /// Returns the name by which this export is known.
name(&self) -> &'module str3636     pub fn name(&self) -> &'module str {
3637         self.name
3638     }
3639 
3640     /// Returns the type of this export.
ty(&self) -> ExternType3641     pub fn ty(&self) -> ExternType {
3642         ExternType::from_wasmtime(self.engine, self.types, &self.ty)
3643     }
3644 }
3645 
3646 impl<'module> fmt::Debug for ExportType<'module> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result3647     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3648         f.debug_struct("ExportType")
3649             .field("name", &self.name().to_owned())
3650             .field("ty", &self.ty())
3651             .finish()
3652     }
3653 }
3654