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