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