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);
1800 Self::from_registered_type(ty)
1801 }
1802
1803 pub(crate) fn from_registered_type(registered_type: RegisteredType) -> Self {
1804 debug_assert!(registered_type.is_struct());
1805 Self { registered_type }
1806 }
1807}
1808
1809/// The type of a WebAssembly array.
1810///
1811/// WebAssembly arrays are dynamically-sized, but not resizable. They contain
1812/// either unpacked [`Val`][crate::Val]s or packed 8-/16-bit integers.
1813///
1814/// # Subtyping and Equality
1815///
1816/// `ArrayType` does not implement `Eq`, because reference types have a
1817/// subtyping relationship, and so 99.99% of the time you actually want to check
1818/// whether one type matches (i.e. is a subtype of) another type. You can use
1819/// the [`ArrayType::matches`] method to perform these types of checks. If,
1820/// however, you are in that 0.01% scenario where you need to check precise
1821/// equality between types, you can use the [`ArrayType::eq`] method.
1822//
1823// TODO: Once we have array values, update above docs with a reference to the
1824// future `Array::matches_ty` method
1825#[derive(Debug, Clone, Hash)]
1826pub struct ArrayType {
1827 registered_type: RegisteredType,
1828}
1829
1830impl fmt::Display for ArrayType {
1831 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1832 let field_ty = self.field_type();
1833 write!(f, "(array (field {field_ty}))")?;
1834 Ok(())
1835 }
1836}
1837
1838impl ArrayType {
1839 /// Construct a new `ArrayType` with the given field type's mutability and
1840 /// storage type.
1841 ///
1842 /// The new `ArrayType` will be final and without a supertype.
1843 ///
1844 /// The result will be associated with the given engine, and attempts to use
1845 /// it with other engines will panic (for example, checking whether it is a
1846 /// subtype of another array type that is associated with a different
1847 /// engine).
1848 ///
1849 /// # Panics
1850 ///
1851 /// Panics if the given field type is not associated with the given engine.
1852 pub fn new(engine: &Engine, field_type: FieldType) -> Self {
1853 Self::with_finality_and_supertype(engine, Finality::Final, None, field_type)
1854 .expect("cannot fail without a supertype")
1855 }
1856
1857 /// Construct a new `StructType` with the given finality, supertype, and
1858 /// fields.
1859 ///
1860 /// The result will be associated with the given engine, and attempts to use
1861 /// it with other engines will panic (for example, checking whether it is a
1862 /// subtype of another struct type that is associated with a different
1863 /// engine).
1864 ///
1865 /// Returns an error if the supertype is final, or if this type does not
1866 /// match the supertype.
1867 ///
1868 /// # Panics
1869 ///
1870 /// Panics if the given field type is not associated with the given engine.
1871 pub fn with_finality_and_supertype(
1872 engine: &Engine,
1873 finality: Finality,
1874 supertype: Option<&Self>,
1875 field_type: FieldType,
1876 ) -> Result<Self> {
1877 if let Some(supertype) = supertype {
1878 assert!(supertype.comes_from_same_engine(engine));
1879 ensure!(
1880 supertype.finality().is_non_final(),
1881 "cannot create a subtype of a final supertype"
1882 );
1883 ensure!(
1884 field_type.matches(&supertype.field_type()),
1885 "array field type must match its supertype's field type"
1886 );
1887 }
1888
1889 // Same as in `FuncType::new`: we must prevent any `RegisteredType` in
1890 // `field_type` from being reclaimed while constructing this array type.
1891 let _registration = field_type
1892 .element_type
1893 .as_val_type()
1894 .and_then(|v| v.as_ref())
1895 .and_then(|r| r.heap_type().as_registered_type());
1896
1897 assert!(field_type.comes_from_same_engine(engine));
1898 let wasm_ty = WasmArrayType(field_type.to_wasm_field_type());
1899
1900 Ok(Self::from_wasm_array_type(
1901 engine,
1902 finality.is_final(),
1903 supertype.map(|ty| ty.type_index().into()),
1904 wasm_ty,
1905 ))
1906 }
1907
1908 /// Get the engine that this array type is associated with.
1909 pub fn engine(&self) -> &Engine {
1910 self.registered_type.engine()
1911 }
1912
1913 /// Get the finality of this array type.
1914 pub fn finality(&self) -> Finality {
1915 match self.registered_type.is_final {
1916 true => Finality::Final,
1917 false => Finality::NonFinal,
1918 }
1919 }
1920
1921 /// Get the supertype of this array type, if any.
1922 pub fn supertype(&self) -> Option<Self> {
1923 self.registered_type
1924 .supertype
1925 .map(|ty| Self::from_shared_type_index(self.engine(), ty.unwrap_engine_type_index()))
1926 }
1927
1928 /// Get this array's underlying field type.
1929 ///
1930 /// The field type contains information about both this array type's
1931 /// mutability and the storage type used for its elements.
1932 pub fn field_type(&self) -> FieldType {
1933 FieldType::from_wasm_field_type(self.engine(), &self.as_wasm_array_type().0)
1934 }
1935
1936 /// Get this array type's mutability and whether its instances' elements can
1937 /// be updated or not.
1938 ///
1939 /// This is a convenience method providing a short-hand for
1940 /// `my_array_type.field_type().mutability()`.
1941 pub fn mutability(&self) -> Mutability {
1942 if self.as_wasm_array_type().0.mutable {
1943 Mutability::Var
1944 } else {
1945 Mutability::Const
1946 }
1947 }
1948
1949 /// Get the storage type used for this array type's elements.
1950 ///
1951 /// This is a convenience method providing a short-hand for
1952 /// `my_array_type.field_type().element_type()`.
1953 pub fn element_type(&self) -> StorageType {
1954 StorageType::from_wasm_storage_type(
1955 self.engine(),
1956 &self.registered_type.unwrap_array().0.element_type,
1957 )
1958 }
1959
1960 /// Does this array type match the other array type?
1961 ///
1962 /// That is, is this function type a subtype of the other array type?
1963 ///
1964 /// # Panics
1965 ///
1966 /// Panics if either type is associated with a different engine from the
1967 /// other.
1968 pub fn matches(&self, other: &ArrayType) -> bool {
1969 assert!(self.comes_from_same_engine(other.engine()));
1970
1971 self.engine()
1972 .signatures()
1973 .is_subtype(self.type_index(), other.type_index())
1974 }
1975
1976 /// Is array type `a` precisely equal to array type `b`?
1977 ///
1978 /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
1979 /// are not exactly the same array type.
1980 ///
1981 /// # Panics
1982 ///
1983 /// Panics if either type is associated with a different engine from the
1984 /// other.
1985 pub fn eq(a: &ArrayType, b: &ArrayType) -> bool {
1986 assert!(a.comes_from_same_engine(b.engine()));
1987 a.type_index() == b.type_index()
1988 }
1989
1990 pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
1991 Engine::same(self.registered_type.engine(), engine)
1992 }
1993
1994 #[cfg(feature = "gc")]
1995 pub(crate) fn registered_type(&self) -> &RegisteredType {
1996 &self.registered_type
1997 }
1998
1999 pub(crate) fn type_index(&self) -> VMSharedTypeIndex {
2000 self.registered_type.index()
2001 }
2002
2003 pub(crate) fn as_wasm_array_type(&self) -> &WasmArrayType {
2004 self.registered_type.unwrap_array()
2005 }
2006
2007 /// Construct a `ArrayType` from a `WasmArrayType`.
2008 ///
2009 /// This method should only be used when something has already registered --
2010 /// and is *keeping registered* -- any other concrete Wasm types referenced
2011 /// by the given `WasmArrayType`.
2012 ///
2013 /// For example, this method may be called to convert an array type from
2014 /// within a Wasm module's `ModuleTypes` since the Wasm module itself is
2015 /// holding a strong reference to all of its types, including any `(ref null
2016 /// <index>)` types used as the element type for this array type.
2017 pub(crate) fn from_wasm_array_type(
2018 engine: &Engine,
2019 is_final: bool,
2020 supertype: Option<EngineOrModuleTypeIndex>,
2021 ty: WasmArrayType,
2022 ) -> ArrayType {
2023 let ty = RegisteredType::new(
2024 engine,
2025 WasmSubType {
2026 is_final,
2027 supertype,
2028 composite_type: WasmCompositeType {
2029 shared: false,
2030 inner: WasmCompositeInnerType::Array(ty),
2031 },
2032 },
2033 );
2034 Self {
2035 registered_type: ty,
2036 }
2037 }
2038
2039 pub(crate) fn from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> ArrayType {
2040 let ty = RegisteredType::root(engine, index);
2041 Self::from_registered_type(ty)
2042 }
2043
2044 pub(crate) fn from_registered_type(registered_type: RegisteredType) -> Self {
2045 debug_assert!(registered_type.is_array());
2046 Self { registered_type }
2047 }
2048}
2049
2050/// The type of a WebAssembly function.
2051///
2052/// WebAssembly functions can have 0 or more parameters and results.
2053///
2054/// # Subtyping and Equality
2055///
2056/// `FuncType` does not implement `Eq`, because reference types have a subtyping
2057/// relationship, and so 99.99% of the time you actually want to check whether
2058/// one type matches (i.e. is a subtype of) another type. You can use the
2059/// [`FuncType::matches`] and [`Func::matches_ty`][crate::Func::matches_ty]
2060/// methods to perform these types of checks. If, however, you are in that 0.01%
2061/// scenario where you need to check precise equality between types, you can use
2062/// the [`FuncType::eq`] method.
2063#[derive(Debug, Clone, Hash)]
2064pub struct FuncType {
2065 registered_type: RegisteredType,
2066}
2067
2068impl Display for FuncType {
2069 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2070 write!(f, "(type (func")?;
2071 if self.params().len() > 0 {
2072 write!(f, " (param")?;
2073 for p in self.params() {
2074 write!(f, " {p}")?;
2075 }
2076 write!(f, ")")?;
2077 }
2078 if self.results().len() > 0 {
2079 write!(f, " (result")?;
2080 for r in self.results() {
2081 write!(f, " {r}")?;
2082 }
2083 write!(f, ")")?;
2084 }
2085 write!(f, "))")
2086 }
2087}
2088
2089impl FuncType {
2090 /// Creates a new function type from the given parameters and results.
2091 ///
2092 /// The function type returned will represent a function which takes
2093 /// `params` as arguments and returns `results` when it is finished.
2094 ///
2095 /// The resulting function type will be final and without a supertype.
2096 ///
2097 /// # Panics
2098 ///
2099 /// Panics if any parameter or value type is not associated with the given
2100 /// engine.
2101 pub fn new(
2102 engine: &Engine,
2103 params: impl IntoIterator<Item = ValType>,
2104 results: impl IntoIterator<Item = ValType>,
2105 ) -> FuncType {
2106 Self::with_finality_and_supertype(engine, Finality::Final, None, params, results)
2107 .expect("cannot fail without a supertype")
2108 }
2109
2110 /// Create a new function type with the given finality, supertype, parameter
2111 /// types, and result types.
2112 ///
2113 /// Returns an error if the supertype is final, or if this function type
2114 /// does not match the supertype.
2115 ///
2116 /// # Panics
2117 ///
2118 /// Panics if any parameter or value type is not associated with the given
2119 /// engine.
2120 pub fn with_finality_and_supertype(
2121 engine: &Engine,
2122 finality: Finality,
2123 supertype: Option<&Self>,
2124 params: impl IntoIterator<Item = ValType>,
2125 results: impl IntoIterator<Item = ValType>,
2126 ) -> Result<Self> {
2127 let params = params.into_iter();
2128 let results = results.into_iter();
2129
2130 let mut wasmtime_params = Vec::with_capacity({
2131 let size_hint = params.size_hint();
2132 let cap = size_hint.1.unwrap_or(size_hint.0);
2133 // Only reserve space if we have a supertype, as that is the only time
2134 // that this vec is used.
2135 supertype.is_some() as usize * cap
2136 });
2137
2138 let mut wasmtime_results = Vec::with_capacity({
2139 let size_hint = results.size_hint();
2140 let cap = size_hint.1.unwrap_or(size_hint.0);
2141 // Same as above.
2142 supertype.is_some() as usize * cap
2143 });
2144
2145 // Keep any of our parameters' and results' `RegisteredType`s alive
2146 // across `Self::from_wasm_func_type`. If one of our given `ValType`s is
2147 // the only thing keeping a type in the registry, we don't want to
2148 // unregister it when we convert the `ValType` into a `WasmValType` just
2149 // before we register our new `WasmFuncType` that will reference it.
2150 let mut registrations = smallvec::SmallVec::<[_; 4]>::new();
2151
2152 let mut to_wasm_type = |ty: ValType, vec: &mut Vec<_>| {
2153 assert!(ty.comes_from_same_engine(engine));
2154
2155 if supertype.is_some() {
2156 vec.push(ty.clone());
2157 }
2158
2159 if let Some(r) = ty.as_ref() {
2160 if let Some(r) = r.heap_type().as_registered_type() {
2161 registrations.push(r.clone());
2162 }
2163 }
2164
2165 ty.to_wasm_type()
2166 };
2167
2168 let wasm_func_ty = WasmFuncType::new(
2169 params
2170 .map(|p| to_wasm_type(p, &mut wasmtime_params))
2171 .collect(),
2172 results
2173 .map(|r| to_wasm_type(r, &mut wasmtime_results))
2174 .collect(),
2175 );
2176
2177 if let Some(supertype) = supertype {
2178 assert!(supertype.comes_from_same_engine(engine));
2179 ensure!(
2180 supertype.finality().is_non_final(),
2181 "cannot create a subtype of a final supertype"
2182 );
2183 ensure!(
2184 Self::matches_impl(
2185 wasmtime_params.iter().cloned(),
2186 supertype.params(),
2187 wasmtime_results.iter().cloned(),
2188 supertype.results()
2189 ),
2190 "function type must match its supertype: found (func{params}{results}), expected \
2191 {supertype}",
2192 params = if wasmtime_params.is_empty() {
2193 String::new()
2194 } else {
2195 let mut s = format!(" (params");
2196 for p in &wasmtime_params {
2197 write!(&mut s, " {p}").unwrap();
2198 }
2199 s.push(')');
2200 s
2201 },
2202 results = if wasmtime_results.is_empty() {
2203 String::new()
2204 } else {
2205 let mut s = format!(" (results");
2206 for r in &wasmtime_results {
2207 write!(&mut s, " {r}").unwrap();
2208 }
2209 s.push(')');
2210 s
2211 },
2212 );
2213 }
2214
2215 Ok(Self::from_wasm_func_type(
2216 engine,
2217 finality.is_final(),
2218 supertype.map(|ty| ty.type_index().into()),
2219 wasm_func_ty,
2220 ))
2221 }
2222
2223 /// Get the engine that this function type is associated with.
2224 pub fn engine(&self) -> &Engine {
2225 self.registered_type.engine()
2226 }
2227
2228 /// Get the finality of this function type.
2229 pub fn finality(&self) -> Finality {
2230 match self.registered_type.is_final {
2231 true => Finality::Final,
2232 false => Finality::NonFinal,
2233 }
2234 }
2235
2236 /// Get the supertype of this function type, if any.
2237 pub fn supertype(&self) -> Option<Self> {
2238 self.registered_type
2239 .supertype
2240 .map(|ty| Self::from_shared_type_index(self.engine(), ty.unwrap_engine_type_index()))
2241 }
2242
2243 /// Get the `i`th parameter type.
2244 ///
2245 /// Returns `None` if `i` is out of bounds.
2246 pub fn param(&self, i: usize) -> Option<ValType> {
2247 let engine = self.engine();
2248 self.registered_type
2249 .unwrap_func()
2250 .params()
2251 .get(i)
2252 .map(|ty| ValType::from_wasm_type(engine, ty))
2253 }
2254
2255 /// Returns the list of parameter types for this function.
2256 #[inline]
2257 pub fn params(&self) -> impl ExactSizeIterator<Item = ValType> + '_ {
2258 let engine = self.engine();
2259 self.registered_type
2260 .unwrap_func()
2261 .params()
2262 .iter()
2263 .map(|ty| ValType::from_wasm_type(engine, ty))
2264 }
2265
2266 /// Get the `i`th result type.
2267 ///
2268 /// Returns `None` if `i` is out of bounds.
2269 pub fn result(&self, i: usize) -> Option<ValType> {
2270 let engine = self.engine();
2271 self.registered_type
2272 .unwrap_func()
2273 .returns()
2274 .get(i)
2275 .map(|ty| ValType::from_wasm_type(engine, ty))
2276 }
2277
2278 /// Returns the list of result types for this function.
2279 #[inline]
2280 pub fn results(&self) -> impl ExactSizeIterator<Item = ValType> + '_ {
2281 let engine = self.engine();
2282 self.registered_type
2283 .unwrap_func()
2284 .returns()
2285 .iter()
2286 .map(|ty| ValType::from_wasm_type(engine, ty))
2287 }
2288
2289 /// Does this function type match the other function type?
2290 ///
2291 /// That is, is this function type a subtype of the other function type?
2292 ///
2293 /// # Panics
2294 ///
2295 /// Panics if either type is associated with a different engine from the
2296 /// other.
2297 pub fn matches(&self, other: &FuncType) -> bool {
2298 assert!(self.comes_from_same_engine(other.engine()));
2299
2300 // Avoid matching on structure for subtyping checks when we have
2301 // precisely the same type.
2302 if self.type_index() == other.type_index() {
2303 return true;
2304 }
2305
2306 Self::matches_impl(
2307 self.params(),
2308 other.params(),
2309 self.results(),
2310 other.results(),
2311 )
2312 }
2313
2314 fn matches_impl(
2315 a_params: impl ExactSizeIterator<Item = ValType>,
2316 b_params: impl ExactSizeIterator<Item = ValType>,
2317 a_results: impl ExactSizeIterator<Item = ValType>,
2318 b_results: impl ExactSizeIterator<Item = ValType>,
2319 ) -> bool {
2320 a_params.len() == b_params.len()
2321 && a_results.len() == b_results.len()
2322 // Params are contravariant and results are covariant. For more
2323 // details and a refresher on variance, read
2324 // https://github.com/bytecodealliance/wasm-tools/blob/f1d89a4/crates/wasmparser/src/readers/core/types/matches.rs#L137-L174
2325 && a_params
2326 .zip(b_params)
2327 .all(|(a, b)| b.matches(&a))
2328 && a_results
2329 .zip(b_results)
2330 .all(|(a, b)| a.matches(&b))
2331 }
2332
2333 /// Is function type `a` precisely equal to function type `b`?
2334 ///
2335 /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
2336 /// are not exactly the same function type.
2337 ///
2338 /// # Panics
2339 ///
2340 /// Panics if either type is associated with a different engine from the
2341 /// other.
2342 pub fn eq(a: &FuncType, b: &FuncType) -> bool {
2343 assert!(a.comes_from_same_engine(b.engine()));
2344 a.type_index() == b.type_index()
2345 }
2346
2347 pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
2348 Engine::same(self.registered_type.engine(), engine)
2349 }
2350
2351 pub(crate) fn type_index(&self) -> VMSharedTypeIndex {
2352 self.registered_type.index()
2353 }
2354
2355 #[cfg(feature = "gc")]
2356 pub(crate) fn as_wasm_func_type(&self) -> &WasmFuncType {
2357 self.registered_type.unwrap_func()
2358 }
2359
2360 pub(crate) fn into_registered_type(self) -> RegisteredType {
2361 self.registered_type
2362 }
2363
2364 /// Construct a `FuncType` from a `WasmFuncType`.
2365 ///
2366 /// This method should only be used when something has already registered --
2367 /// and is *keeping registered* -- any other concrete Wasm types referenced
2368 /// by the given `WasmFuncType`.
2369 ///
2370 /// For example, this method may be called to convert a function type from
2371 /// within a Wasm module's `ModuleTypes` since the Wasm module itself is
2372 /// holding a strong reference to all of its types, including any `(ref null
2373 /// <index>)` types used in the function's parameters and results.
2374 pub(crate) fn from_wasm_func_type(
2375 engine: &Engine,
2376 is_final: bool,
2377 supertype: Option<EngineOrModuleTypeIndex>,
2378 ty: WasmFuncType,
2379 ) -> FuncType {
2380 let ty = RegisteredType::new(
2381 engine,
2382 WasmSubType {
2383 is_final,
2384 supertype,
2385 composite_type: WasmCompositeType {
2386 shared: false,
2387 inner: WasmCompositeInnerType::Func(ty),
2388 },
2389 },
2390 );
2391 Self {
2392 registered_type: ty,
2393 }
2394 }
2395
2396 pub(crate) fn from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> FuncType {
2397 let ty = RegisteredType::root(engine, index);
2398 Self::from_registered_type(ty)
2399 }
2400
2401 pub(crate) fn from_registered_type(registered_type: RegisteredType) -> Self {
2402 debug_assert!(registered_type.is_func());
2403 Self { registered_type }
2404 }
2405}
2406
2407// Global Types
2408
2409/// A WebAssembly global descriptor.
2410///
2411/// This type describes an instance of a global in a WebAssembly module. Globals
2412/// are local to an [`Instance`](crate::Instance) and are either immutable or
2413/// mutable.
2414#[derive(Debug, Clone, Hash)]
2415pub struct GlobalType {
2416 content: ValType,
2417 mutability: Mutability,
2418}
2419
2420impl GlobalType {
2421 /// Creates a new global descriptor of the specified `content` type and
2422 /// whether or not it's mutable.
2423 pub fn new(content: ValType, mutability: Mutability) -> GlobalType {
2424 GlobalType {
2425 content,
2426 mutability,
2427 }
2428 }
2429
2430 /// Returns the value type of this global descriptor.
2431 pub fn content(&self) -> &ValType {
2432 &self.content
2433 }
2434
2435 /// Returns whether or not this global is mutable.
2436 pub fn mutability(&self) -> Mutability {
2437 self.mutability
2438 }
2439
2440 pub(crate) fn to_wasm_type(&self) -> Global {
2441 let wasm_ty = self.content().to_wasm_type();
2442 let mutability = matches!(self.mutability(), Mutability::Var);
2443 Global {
2444 wasm_ty,
2445 mutability,
2446 }
2447 }
2448
2449 /// Returns `None` if the wasmtime global has a type that we can't
2450 /// represent, but that should only very rarely happen and indicate a bug.
2451 pub(crate) fn from_wasmtime_global(engine: &Engine, global: &Global) -> GlobalType {
2452 let ty = ValType::from_wasm_type(engine, &global.wasm_ty);
2453 let mutability = if global.mutability {
2454 Mutability::Var
2455 } else {
2456 Mutability::Const
2457 };
2458 GlobalType::new(ty, mutability)
2459 }
2460}
2461
2462// Tag Types
2463
2464/// A descriptor for a tag in a WebAssembly module.
2465///
2466/// This type describes an instance of a tag in a WebAssembly
2467/// module. Tags are local to an [`Instance`](crate::Instance).
2468#[derive(Debug, Clone, Hash)]
2469pub struct TagType {
2470 ty: FuncType,
2471}
2472
2473impl TagType {
2474 /// Creates a new global descriptor of the specified type.
2475 pub fn new(ty: FuncType) -> TagType {
2476 TagType { ty }
2477 }
2478
2479 /// Returns the underlying function type of this tag descriptor.
2480 pub fn ty(&self) -> &FuncType {
2481 &self.ty
2482 }
2483
2484 pub(crate) fn from_wasmtime_tag(engine: &Engine, tag: &Tag) -> TagType {
2485 let ty = FuncType::from_shared_type_index(engine, tag.signature.unwrap_engine_type_index());
2486 TagType { ty }
2487 }
2488}
2489
2490// Table Types
2491
2492/// A descriptor for a table in a WebAssembly module.
2493///
2494/// Tables are contiguous chunks of a specific element, typically a `funcref` or
2495/// an `externref`. The most common use for tables is a function table through
2496/// which `call_indirect` can invoke other functions.
2497#[derive(Debug, Clone, Hash)]
2498pub struct TableType {
2499 // Keep a `wasmtime::RefType` so that `TableType::element` doesn't need to
2500 // take an `&Engine`.
2501 element: RefType,
2502 ty: Table,
2503}
2504
2505impl TableType {
2506 /// Creates a new table descriptor which will contain the specified
2507 /// `element` and have the `limits` applied to its length.
2508 pub fn new(element: RefType, min: u32, max: Option<u32>) -> TableType {
2509 let ref_type = element.to_wasm_type();
2510
2511 debug_assert!(
2512 ref_type.is_canonicalized_for_runtime_usage(),
2513 "should be canonicalized for runtime usage: {ref_type:?}"
2514 );
2515
2516 let limits = Limits {
2517 min: u64::from(min),
2518 max: max.map(|x| u64::from(x)),
2519 };
2520
2521 TableType {
2522 element,
2523 ty: Table {
2524 idx_type: IndexType::I32,
2525 limits,
2526 ref_type,
2527 },
2528 }
2529 }
2530
2531 /// Crates a new descriptor for a 64-bit table.
2532 ///
2533 /// Note that 64-bit tables are part of the memory64 proposal for
2534 /// WebAssembly which is not standardized yet.
2535 pub fn new64(element: RefType, min: u64, max: Option<u64>) -> TableType {
2536 let ref_type = element.to_wasm_type();
2537
2538 debug_assert!(
2539 ref_type.is_canonicalized_for_runtime_usage(),
2540 "should be canonicalized for runtime usage: {ref_type:?}"
2541 );
2542
2543 TableType {
2544 element,
2545 ty: Table {
2546 ref_type,
2547 idx_type: IndexType::I64,
2548 limits: Limits { min, max },
2549 },
2550 }
2551 }
2552
2553 /// Returns whether or not this table is a 64-bit table.
2554 ///
2555 /// Note that 64-bit tables are part of the memory64 proposal for
2556 /// WebAssembly which is not standardized yet.
2557 pub fn is_64(&self) -> bool {
2558 matches!(self.ty.idx_type, IndexType::I64)
2559 }
2560
2561 /// Returns the element value type of this table.
2562 pub fn element(&self) -> &RefType {
2563 &self.element
2564 }
2565
2566 /// Returns minimum number of elements this table must have
2567 pub fn minimum(&self) -> u64 {
2568 self.ty.limits.min
2569 }
2570
2571 /// Returns the optionally-specified maximum number of elements this table
2572 /// can have.
2573 ///
2574 /// If this returns `None` then the table is not limited in size.
2575 pub fn maximum(&self) -> Option<u64> {
2576 self.ty.limits.max
2577 }
2578
2579 pub(crate) fn from_wasmtime_table(engine: &Engine, table: &Table) -> TableType {
2580 let element = RefType::from_wasm_type(engine, &table.ref_type);
2581 TableType {
2582 element,
2583 ty: *table,
2584 }
2585 }
2586
2587 pub(crate) fn wasmtime_table(&self) -> &Table {
2588 &self.ty
2589 }
2590}
2591
2592// Memory Types
2593
2594/// A builder for [`MemoryType`][crate::MemoryType]s.
2595///
2596/// A new builder can be constructed via its `Default` implementation.
2597///
2598/// When you're done configuring, get the underlying
2599/// [`MemoryType`][crate::MemoryType] by calling the
2600/// [`build`][crate::MemoryTypeBuilder::build] method.
2601///
2602/// # Example
2603///
2604/// ```
2605/// # fn foo() -> wasmtime::Result<()> {
2606/// use wasmtime::MemoryTypeBuilder;
2607///
2608/// let memory_type = MemoryTypeBuilder::new()
2609/// // Set the minimum size, in pages.
2610/// .min(4096)
2611/// // Set the maximum size, in pages.
2612/// .max(Some(4096))
2613/// // Set the page size to 1 byte (aka 2**0).
2614/// .page_size_log2(0)
2615/// // Get the underlying memory type.
2616/// .build()?;
2617/// # Ok(())
2618/// # }
2619/// ```
2620pub struct MemoryTypeBuilder {
2621 ty: Memory,
2622}
2623
2624impl Default for MemoryTypeBuilder {
2625 fn default() -> Self {
2626 MemoryTypeBuilder {
2627 ty: Memory {
2628 idx_type: IndexType::I32,
2629 limits: Limits { min: 0, max: None },
2630 shared: false,
2631 page_size_log2: Memory::DEFAULT_PAGE_SIZE_LOG2,
2632 },
2633 }
2634 }
2635}
2636
2637impl MemoryTypeBuilder {
2638 /// Create a new builder for a [`MemoryType`] with the default settings.
2639 ///
2640 /// By default memory types have the following properties:
2641 ///
2642 /// * The minimum memory size is 0 pages.
2643 /// * The maximum memory size is unspecified.
2644 /// * Memories use 32-bit indexes.
2645 /// * The page size is 64KiB.
2646 ///
2647 /// Each option can be configured through the methods on the returned
2648 /// builder.
2649 pub fn new() -> MemoryTypeBuilder {
2650 MemoryTypeBuilder::default()
2651 }
2652
2653 fn validate(&self) -> Result<()> {
2654 if self
2655 .ty
2656 .limits
2657 .max
2658 .map_or(false, |max| max < self.ty.limits.min)
2659 {
2660 bail!("maximum page size cannot be smaller than the minimum page size");
2661 }
2662
2663 match self.ty.page_size_log2 {
2664 0 | Memory::DEFAULT_PAGE_SIZE_LOG2 => {}
2665 x => bail!(
2666 "page size must be 2**16 or 2**0, but was given 2**{x}; note \
2667 that future Wasm extensions might allow any power of two page \
2668 size, but only 2**16 and 2**0 are currently valid",
2669 ),
2670 }
2671
2672 if self.ty.shared && self.ty.limits.max.is_none() {
2673 bail!("shared memories must have a maximum size");
2674 }
2675
2676 let absolute_max = self.ty.max_size_based_on_index_type();
2677 let min = self
2678 .ty
2679 .minimum_byte_size()
2680 .context("memory's minimum byte size must fit in a u64")?;
2681 if min > absolute_max {
2682 bail!("minimum size is too large for this memory type's index type");
2683 }
2684 if self
2685 .ty
2686 .maximum_byte_size()
2687 .map_or(false, |max| max > absolute_max)
2688 {
2689 bail!("maximum size is too large for this memory type's index type");
2690 }
2691
2692 Ok(())
2693 }
2694
2695 /// Set the minimum size, in units of pages, for the memory type being
2696 /// built.
2697 ///
2698 /// The default minimum is `0`.
2699 pub fn min(&mut self, minimum: u64) -> &mut Self {
2700 self.ty.limits.min = minimum;
2701 self
2702 }
2703
2704 /// Set the maximum size, in units of pages, for the memory type being
2705 /// built.
2706 ///
2707 /// The default maximum is `None`.
2708 pub fn max(&mut self, maximum: Option<u64>) -> &mut Self {
2709 self.ty.limits.max = maximum;
2710 self
2711 }
2712
2713 /// Set whether this is a 64-bit memory or not.
2714 ///
2715 /// If a memory is not a 64-bit memory, then it is a 32-bit memory.
2716 ///
2717 /// The default is `false`, aka 32-bit memories.
2718 ///
2719 /// Note that 64-bit memories are part of [the memory64
2720 /// proposal](https://github.com/WebAssembly/memory64) for WebAssembly which
2721 /// is not fully standardized yet.
2722 pub fn memory64(&mut self, memory64: bool) -> &mut Self {
2723 self.ty.idx_type = match memory64 {
2724 true => IndexType::I64,
2725 false => IndexType::I32,
2726 };
2727 self
2728 }
2729
2730 /// Set the sharedness for the memory type being built.
2731 ///
2732 /// The default is `false`, aka unshared.
2733 ///
2734 /// Note that shared memories are part of [the threads
2735 /// proposal](https://github.com/WebAssembly/threads) for WebAssembly which
2736 /// is not fully standardized yet.
2737 pub fn shared(&mut self, shared: bool) -> &mut Self {
2738 self.ty.shared = shared;
2739 self
2740 }
2741
2742 /// Set the log base 2 of the page size, in bytes, for the memory type being
2743 /// built.
2744 ///
2745 /// The default value is `16`, which results in the default Wasm page size
2746 /// of 64KiB (aka 2<sup>16</sup> or 65536).
2747 ///
2748 /// Other than `16`, the only valid value is `0`, which results in a page
2749 /// size of one byte (aka 2<sup>0</sup>). Single-byte page sizes can be used
2750 /// to get fine-grained control over a Wasm memory's resource consumption
2751 /// and run Wasm in embedded environments with less than 64KiB of RAM, for
2752 /// example.
2753 ///
2754 /// Future extensions to the core WebAssembly language might relax these
2755 /// constraints and introduce more valid page sizes, such as any power of
2756 /// two between 1 and 65536 inclusive.
2757 ///
2758 /// Note that non-default page sizes are part of [the custom-page-sizes
2759 /// proposal](https://github.com/WebAssembly/custom-page-sizes) for
2760 /// WebAssembly which is not fully standardized yet.
2761 pub fn page_size_log2(&mut self, page_size_log2: u8) -> &mut Self {
2762 self.ty.page_size_log2 = page_size_log2;
2763 self
2764 }
2765
2766 /// Get the underlying memory type that this builder has been building.
2767 ///
2768 /// # Errors
2769 ///
2770 /// Returns an error if the configured memory type is invalid, for example
2771 /// if the maximum size is smaller than the minimum size.
2772 pub fn build(&self) -> Result<MemoryType> {
2773 self.validate()?;
2774 Ok(MemoryType { ty: self.ty })
2775 }
2776}
2777
2778/// A descriptor for a WebAssembly memory type.
2779///
2780/// Memories are described in units of pages (64KB) and represent contiguous
2781/// chunks of addressable memory.
2782#[derive(Debug, Clone, Hash, Eq, PartialEq)]
2783pub struct MemoryType {
2784 ty: Memory,
2785}
2786
2787impl MemoryType {
2788 /// Creates a new descriptor for a 32-bit WebAssembly memory given the
2789 /// specified limits of the memory.
2790 ///
2791 /// The `minimum` and `maximum` values here are specified in units of
2792 /// WebAssembly pages, which are 64KiB by default. Use
2793 /// [`MemoryTypeBuilder`][crate::MemoryTypeBuilder] if you want a
2794 /// non-default page size.
2795 ///
2796 /// # Panics
2797 ///
2798 /// Panics if the minimum is greater than the maximum or if the minimum or
2799 /// maximum number of pages can result in a byte size that is not
2800 /// addressable with a 32-bit integer.
2801 pub fn new(minimum: u32, maximum: Option<u32>) -> MemoryType {
2802 MemoryTypeBuilder::default()
2803 .min(minimum.into())
2804 .max(maximum.map(Into::into))
2805 .build()
2806 .unwrap()
2807 }
2808
2809 /// Creates a new descriptor for a 64-bit WebAssembly memory given the
2810 /// specified limits of the memory.
2811 ///
2812 /// The `minimum` and `maximum` values here are specified in units of
2813 /// WebAssembly pages, which are 64KiB by default. Use
2814 /// [`MemoryTypeBuilder`][crate::MemoryTypeBuilder] if you want a
2815 /// non-default page size.
2816 ///
2817 /// Note that 64-bit memories are part of [the memory64
2818 /// proposal](https://github.com/WebAssembly/memory64) for WebAssembly which
2819 /// is not fully standardized yet.
2820 ///
2821 /// # Panics
2822 ///
2823 /// Panics if the minimum is greater than the maximum or if the minimum or
2824 /// maximum number of pages can result in a byte size that is not
2825 /// addressable with a 64-bit integer.
2826 pub fn new64(minimum: u64, maximum: Option<u64>) -> MemoryType {
2827 MemoryTypeBuilder::default()
2828 .memory64(true)
2829 .min(minimum)
2830 .max(maximum)
2831 .build()
2832 .unwrap()
2833 }
2834
2835 /// Creates a new descriptor for shared WebAssembly memory given the
2836 /// specified limits of the memory.
2837 ///
2838 /// The `minimum` and `maximum` values here are specified in units of
2839 /// WebAssembly pages, which are 64KiB by default. Use
2840 /// [`MemoryTypeBuilder`][crate::MemoryTypeBuilder] if you want a
2841 /// non-default page size.
2842 ///
2843 /// Note that shared memories are part of [the threads
2844 /// proposal](https://github.com/WebAssembly/threads) for WebAssembly which
2845 /// is not fully standardized yet.
2846 ///
2847 /// # Panics
2848 ///
2849 /// Panics if the minimum is greater than the maximum or if the minimum or
2850 /// maximum number of pages can result in a byte size that is not
2851 /// addressable with a 32-bit integer.
2852 pub fn shared(minimum: u32, maximum: u32) -> MemoryType {
2853 MemoryTypeBuilder::default()
2854 .shared(true)
2855 .min(minimum.into())
2856 .max(Some(maximum.into()))
2857 .build()
2858 .unwrap()
2859 }
2860
2861 /// Creates a new [`MemoryTypeBuilder`] to configure all the various knobs
2862 /// of the final memory type being created.
2863 ///
2864 /// This is a convenience function for [`MemoryTypeBuilder::new`].
2865 pub fn builder() -> MemoryTypeBuilder {
2866 MemoryTypeBuilder::new()
2867 }
2868
2869 /// Returns whether this is a 64-bit memory or not.
2870 ///
2871 /// Note that 64-bit memories are part of the memory64 proposal for
2872 /// WebAssembly which is not standardized yet.
2873 pub fn is_64(&self) -> bool {
2874 matches!(self.ty.idx_type, IndexType::I64)
2875 }
2876
2877 /// Returns whether this is a shared memory or not.
2878 ///
2879 /// Note that shared memories are part of the threads proposal for
2880 /// WebAssembly which is not standardized yet.
2881 pub fn is_shared(&self) -> bool {
2882 self.ty.shared
2883 }
2884
2885 /// Returns minimum number of WebAssembly pages this memory must have.
2886 ///
2887 /// Note that the return value, while a `u64`, will always fit into a `u32`
2888 /// for 32-bit memories.
2889 pub fn minimum(&self) -> u64 {
2890 self.ty.limits.min
2891 }
2892
2893 /// Returns the optionally-specified maximum number of pages this memory
2894 /// can have.
2895 ///
2896 /// If this returns `None` then the memory is not limited in size.
2897 ///
2898 /// Note that the return value, while a `u64`, will always fit into a `u32`
2899 /// for 32-bit memories.
2900 pub fn maximum(&self) -> Option<u64> {
2901 self.ty.limits.max
2902 }
2903
2904 /// This memory's page size, in bytes.
2905 pub fn page_size(&self) -> u64 {
2906 self.ty.page_size()
2907 }
2908
2909 /// The log2 of this memory's page size, in bytes.
2910 pub fn page_size_log2(&self) -> u8 {
2911 self.ty.page_size_log2
2912 }
2913
2914 pub(crate) fn from_wasmtime_memory(memory: &Memory) -> MemoryType {
2915 MemoryType { ty: *memory }
2916 }
2917
2918 pub(crate) fn wasmtime_memory(&self) -> &Memory {
2919 &self.ty
2920 }
2921}
2922
2923// Import Types
2924
2925/// A descriptor for an imported value into a wasm module.
2926///
2927/// This type is primarily accessed from the
2928/// [`Module::imports`](crate::Module::imports) API. Each [`ImportType`]
2929/// describes an import into the wasm module with the module/name that it's
2930/// imported from as well as the type of item that's being imported.
2931#[derive(Clone)]
2932pub struct ImportType<'module> {
2933 /// The module of the import.
2934 module: &'module str,
2935
2936 /// The field of the import.
2937 name: &'module str,
2938
2939 /// The type of the import.
2940 ty: EntityType,
2941 types: &'module ModuleTypes,
2942 engine: &'module Engine,
2943}
2944
2945impl<'module> ImportType<'module> {
2946 /// Creates a new import descriptor which comes from `module` and `name` and
2947 /// is of type `ty`.
2948 pub(crate) fn new(
2949 module: &'module str,
2950 name: &'module str,
2951 ty: EntityType,
2952 types: &'module ModuleTypes,
2953 engine: &'module Engine,
2954 ) -> ImportType<'module> {
2955 assert!(ty.is_canonicalized_for_runtime_usage());
2956 ImportType {
2957 module,
2958 name,
2959 ty,
2960 types,
2961 engine,
2962 }
2963 }
2964
2965 /// Returns the module name that this import is expected to come from.
2966 pub fn module(&self) -> &'module str {
2967 self.module
2968 }
2969
2970 /// Returns the field name of the module that this import is expected to
2971 /// come from.
2972 pub fn name(&self) -> &'module str {
2973 self.name
2974 }
2975
2976 /// Returns the expected type of this import.
2977 pub fn ty(&self) -> ExternType {
2978 ExternType::from_wasmtime(self.engine, self.types, &self.ty)
2979 }
2980}
2981
2982impl<'module> fmt::Debug for ImportType<'module> {
2983 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2984 f.debug_struct("ImportType")
2985 .field("module", &self.module())
2986 .field("name", &self.name())
2987 .field("ty", &self.ty())
2988 .finish()
2989 }
2990}
2991
2992// Export Types
2993
2994/// A descriptor for an exported WebAssembly value.
2995///
2996/// This type is primarily accessed from the
2997/// [`Module::exports`](crate::Module::exports) accessor and describes what
2998/// names are exported from a wasm module and the type of the item that is
2999/// exported.
3000#[derive(Clone)]
3001pub struct ExportType<'module> {
3002 /// The name of the export.
3003 name: &'module str,
3004
3005 /// The type of the export.
3006 ty: EntityType,
3007 types: &'module ModuleTypes,
3008 engine: &'module Engine,
3009}
3010
3011impl<'module> ExportType<'module> {
3012 /// Creates a new export which is exported with the given `name` and has the
3013 /// given `ty`.
3014 pub(crate) fn new(
3015 name: &'module str,
3016 ty: EntityType,
3017 types: &'module ModuleTypes,
3018 engine: &'module Engine,
3019 ) -> ExportType<'module> {
3020 ExportType {
3021 name,
3022 ty,
3023 types,
3024 engine,
3025 }
3026 }
3027
3028 /// Returns the name by which this export is known.
3029 pub fn name(&self) -> &'module str {
3030 self.name
3031 }
3032
3033 /// Returns the type of this export.
3034 pub fn ty(&self) -> ExternType {
3035 ExternType::from_wasmtime(self.engine, self.types, &self.ty)
3036 }
3037}
3038
3039impl<'module> fmt::Debug for ExportType<'module> {
3040 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3041 f.debug_struct("ExportType")
3042 .field("name", &self.name().to_owned())
3043 .field("ty", &self.ty())
3044 .finish()
3045 }
3046}