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