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