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