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