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