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