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