1 use crate::runtime::vm::TableElement;
2 use crate::store::{AutoAssertNoGc, StoreOpaque};
3 use crate::{
4     AnyRef, ArrayRef, AsContext, AsContextMut, ExternRef, Func, HeapType, RefType, Rooted,
5     RootedGcRefImpl, StructRef, V128, ValType, prelude::*,
6 };
7 use core::ptr;
8 
9 pub use crate::runtime::vm::ValRaw;
10 
11 /// Possible runtime values that a WebAssembly module can either consume or
12 /// produce.
13 ///
14 /// Note that we inline the `enum Ref { ... }` variants into `enum Val { ... }`
15 /// here as a size optimization.
16 #[derive(Debug, Clone, Copy)]
17 pub enum Val {
18     // NB: the ordering here is intended to match the ordering in
19     // `ValType` to improve codegen when learning the type of a value.
20     //
21     /// A 32-bit integer.
22     I32(i32),
23 
24     /// A 64-bit integer.
25     I64(i64),
26 
27     /// A 32-bit float.
28     ///
29     /// Note that the raw bits of the float are stored here, and you can use
30     /// `f32::from_bits` to create an `f32` value.
31     F32(u32),
32 
33     /// A 64-bit float.
34     ///
35     /// Note that the raw bits of the float are stored here, and you can use
36     /// `f64::from_bits` to create an `f64` value.
37     F64(u64),
38 
39     /// A 128-bit number.
40     V128(V128),
41 
42     /// A function reference.
43     FuncRef(Option<Func>),
44 
45     /// An external reference.
46     ExternRef(Option<Rooted<ExternRef>>),
47 
48     /// An internal reference.
49     AnyRef(Option<Rooted<AnyRef>>),
50 }
51 
52 macro_rules! accessors {
53     ($bind:ident $(($variant:ident($ty:ty) $get:ident $unwrap:ident $cvt:expr))*) => ($(
54         /// Attempt to access the underlying value of this `Val`, returning
55         /// `None` if it is not the correct type.
56         #[inline]
57         pub fn $get(&self) -> Option<$ty> {
58             if let Val::$variant($bind) = self {
59                 Some($cvt)
60             } else {
61                 None
62             }
63         }
64 
65         /// Returns the underlying value of this `Val`, panicking if it's the
66         /// wrong type.
67         ///
68         /// # Panics
69         ///
70         /// Panics if `self` is not of the right type.
71         #[inline]
72         pub fn $unwrap(&self) -> $ty {
73             self.$get().expect(concat!("expected ", stringify!($ty)))
74         }
75     )*)
76 }
77 
78 impl Val {
79     /// Returns the null reference for the given heap type.
80     #[inline]
81     pub fn null_ref(heap_type: &HeapType) -> Val {
82         Ref::null(&heap_type).into()
83     }
84 
85     /// Returns the null function reference value.
86     ///
87     /// The return value has type `(ref null nofunc)` aka `nullfuncref` and is a
88     /// subtype of all function references.
89     #[inline]
90     pub const fn null_func_ref() -> Val {
91         Val::FuncRef(None)
92     }
93 
94     /// Returns the null function reference value.
95     ///
96     /// The return value has type `(ref null extern)` aka `nullexternref` and is
97     /// a subtype of all external references.
98     #[inline]
99     pub const fn null_extern_ref() -> Val {
100         Val::ExternRef(None)
101     }
102 
103     /// Returns the null function reference value.
104     ///
105     /// The return value has type `(ref null any)` aka `nullref` and is a
106     /// subtype of all internal references.
107     #[inline]
108     pub const fn null_any_ref() -> Val {
109         Val::AnyRef(None)
110     }
111 
112     /// Returns the default value for the given type, if any exists.
113     ///
114     /// Returns `None` if there is no default value for the given type (for
115     /// example, non-nullable reference types do not have a default value).
116     pub fn default_for_ty(ty: &ValType) -> Option<Val> {
117         match ty {
118             ValType::I32 => Some(Val::I32(0)),
119             ValType::I64 => Some(Val::I64(0)),
120             ValType::F32 => Some(Val::F32(0)),
121             ValType::F64 => Some(Val::F64(0)),
122             ValType::V128 => Some(Val::V128(V128::from(0))),
123             ValType::Ref(ref_ty) => {
124                 if ref_ty.is_nullable() {
125                     Some(Val::null_ref(ref_ty.heap_type()))
126                 } else {
127                     None
128                 }
129             }
130         }
131     }
132 
133     /// Returns the corresponding [`ValType`] for this `Val`.
134     ///
135     /// # Errors
136     ///
137     /// Returns an error if this value is a GC reference that has since been
138     /// unrooted.
139     ///
140     /// # Panics
141     ///
142     /// Panics if this value is associated with a different store.
143     #[inline]
144     pub fn ty(&self, store: impl AsContext) -> Result<ValType> {
145         self.load_ty(&store.as_context().0)
146     }
147 
148     #[inline]
149     pub(crate) fn load_ty(&self, store: &StoreOpaque) -> Result<ValType> {
150         Ok(match self {
151             Val::I32(_) => ValType::I32,
152             Val::I64(_) => ValType::I64,
153             Val::F32(_) => ValType::F32,
154             Val::F64(_) => ValType::F64,
155             Val::V128(_) => ValType::V128,
156             Val::ExternRef(Some(_)) => ValType::EXTERNREF,
157             Val::ExternRef(None) => ValType::NULLFUNCREF,
158             Val::FuncRef(None) => ValType::NULLFUNCREF,
159             Val::FuncRef(Some(f)) => ValType::Ref(RefType::new(
160                 false,
161                 HeapType::ConcreteFunc(f.load_ty(store)),
162             )),
163             Val::AnyRef(None) => ValType::NULLREF,
164             Val::AnyRef(Some(a)) => ValType::Ref(RefType::new(false, a._ty(store)?)),
165         })
166     }
167 
168     /// Does this value match the given type?
169     ///
170     /// Returns an error is an underlying `Rooted` has been unrooted.
171     ///
172     /// # Panics
173     ///
174     /// Panics if this value is not associated with the given store.
175     pub fn matches_ty(&self, store: impl AsContext, ty: &ValType) -> Result<bool> {
176         self._matches_ty(&store.as_context().0, ty)
177     }
178 
179     pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &ValType) -> Result<bool> {
180         assert!(self.comes_from_same_store(store));
181         assert!(ty.comes_from_same_engine(store.engine()));
182         Ok(match (self, ty) {
183             (Val::I32(_), ValType::I32)
184             | (Val::I64(_), ValType::I64)
185             | (Val::F32(_), ValType::F32)
186             | (Val::F64(_), ValType::F64)
187             | (Val::V128(_), ValType::V128) => true,
188 
189             (Val::FuncRef(f), ValType::Ref(ref_ty)) => Ref::from(*f)._matches_ty(store, ref_ty)?,
190             (Val::ExternRef(e), ValType::Ref(ref_ty)) => {
191                 Ref::from(*e)._matches_ty(store, ref_ty)?
192             }
193             (Val::AnyRef(a), ValType::Ref(ref_ty)) => Ref::from(*a)._matches_ty(store, ref_ty)?,
194 
195             (Val::I32(_), _)
196             | (Val::I64(_), _)
197             | (Val::F32(_), _)
198             | (Val::F64(_), _)
199             | (Val::V128(_), _)
200             | (Val::FuncRef(_), _)
201             | (Val::ExternRef(_), _)
202             | (Val::AnyRef(_), _) => false,
203         })
204     }
205 
206     pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &ValType) -> Result<()> {
207         if !self.comes_from_same_store(store) {
208             bail!("value used with wrong store")
209         }
210         if !ty.comes_from_same_engine(store.engine()) {
211             bail!("type used with wrong engine")
212         }
213         if self._matches_ty(store, ty)? {
214             Ok(())
215         } else {
216             let actual_ty = self.load_ty(store)?;
217             bail!("type mismatch: expected {ty}, found {actual_ty}")
218         }
219     }
220 
221     /// Convenience method to convert this [`Val`] into a [`ValRaw`].
222     ///
223     /// Returns an error if this value is a GC reference and the GC reference
224     /// has been unrooted.
225     ///
226     /// # Unsafety
227     ///
228     /// This method is unsafe for the reasons that [`ExternRef::to_raw`] and
229     /// [`Func::to_raw`] are unsafe.
230     pub unsafe fn to_raw(&self, store: impl AsContextMut) -> Result<ValRaw> {
231         match self {
232             Val::I32(i) => Ok(ValRaw::i32(*i)),
233             Val::I64(i) => Ok(ValRaw::i64(*i)),
234             Val::F32(u) => Ok(ValRaw::f32(*u)),
235             Val::F64(u) => Ok(ValRaw::f64(*u)),
236             Val::V128(b) => Ok(ValRaw::v128(b.as_u128())),
237             Val::ExternRef(e) => Ok(ValRaw::externref(match e {
238                 None => 0,
239                 Some(e) => e.to_raw(store)?,
240             })),
241             Val::AnyRef(e) => Ok(ValRaw::anyref(match e {
242                 None => 0,
243                 Some(e) => e.to_raw(store)?,
244             })),
245             Val::FuncRef(f) => Ok(ValRaw::funcref(match f {
246                 Some(f) => f.to_raw(store),
247                 None => ptr::null_mut(),
248             })),
249         }
250     }
251 
252     /// Convenience method to convert a [`ValRaw`] into a [`Val`].
253     ///
254     /// # Unsafety
255     ///
256     /// This method is unsafe for the reasons that [`ExternRef::from_raw`] and
257     /// [`Func::from_raw`] are unsafe. Additionally there's no guarantee
258     /// otherwise that `raw` should have the type `ty` specified.
259     pub unsafe fn from_raw(mut store: impl AsContextMut, raw: ValRaw, ty: ValType) -> Val {
260         let mut store = AutoAssertNoGc::new(store.as_context_mut().0);
261         Self::_from_raw(&mut store, raw, &ty)
262     }
263 
264     pub(crate) unsafe fn _from_raw(
265         store: &mut AutoAssertNoGc<'_>,
266         raw: ValRaw,
267         ty: &ValType,
268     ) -> Val {
269         match ty {
270             ValType::I32 => Val::I32(raw.get_i32()),
271             ValType::I64 => Val::I64(raw.get_i64()),
272             ValType::F32 => Val::F32(raw.get_f32()),
273             ValType::F64 => Val::F64(raw.get_f64()),
274             ValType::V128 => Val::V128(raw.get_v128().into()),
275             ValType::Ref(ref_ty) => {
276                 let ref_ = match ref_ty.heap_type() {
277                     HeapType::Func | HeapType::ConcreteFunc(_) => {
278                         Func::_from_raw(store, raw.get_funcref()).into()
279                     }
280 
281                     HeapType::NoFunc => Ref::Func(None),
282 
283                     HeapType::NoCont | HeapType::ConcreteCont(_) | HeapType::Cont => {
284                         // TODO(#10248): Required to support stack switching in the embedder API.
285                         unimplemented!()
286                     }
287 
288                     HeapType::Extern => ExternRef::_from_raw(store, raw.get_externref()).into(),
289 
290                     HeapType::NoExtern => Ref::Extern(None),
291 
292                     HeapType::Any
293                     | HeapType::Eq
294                     | HeapType::I31
295                     | HeapType::Array
296                     | HeapType::ConcreteArray(_)
297                     | HeapType::Struct
298                     | HeapType::ConcreteStruct(_) => {
299                         AnyRef::_from_raw(store, raw.get_anyref()).into()
300                     }
301 
302                     HeapType::None => Ref::Any(None),
303                 };
304                 assert!(
305                     ref_ty.is_nullable() || !ref_.is_null(),
306                     "if the type is not nullable, we shouldn't get null; got \
307                      type = {ref_ty}, ref = {ref_:?}"
308                 );
309                 ref_.into()
310             }
311         }
312     }
313 
314     accessors! {
315         e
316         (I32(i32) i32 unwrap_i32 *e)
317         (I64(i64) i64 unwrap_i64 *e)
318         (F32(f32) f32 unwrap_f32 f32::from_bits(*e))
319         (F64(f64) f64 unwrap_f64 f64::from_bits(*e))
320         (FuncRef(Option<&Func>) func_ref unwrap_func_ref e.as_ref())
321         (ExternRef(Option<&Rooted<ExternRef>>) extern_ref unwrap_extern_ref e.as_ref())
322         (AnyRef(Option<&Rooted<AnyRef>>) any_ref unwrap_any_ref e.as_ref())
323         (V128(V128) v128 unwrap_v128 *e)
324     }
325 
326     /// Get this value's underlying reference, if any.
327     #[inline]
328     pub fn ref_(self) -> Option<Ref> {
329         match self {
330             Val::FuncRef(f) => Some(Ref::Func(f)),
331             Val::ExternRef(e) => Some(Ref::Extern(e)),
332             Val::AnyRef(a) => Some(Ref::Any(a)),
333             Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => None,
334         }
335     }
336 
337     /// Attempt to access the underlying `externref` value of this `Val`.
338     ///
339     /// If this is not an `externref`, then `None` is returned.
340     ///
341     /// If this is a null `externref`, then `Some(None)` is returned.
342     ///
343     /// If this is a non-null `externref`, then `Some(Some(..))` is returned.
344     #[inline]
345     pub fn externref(&self) -> Option<Option<&Rooted<ExternRef>>> {
346         match self {
347             Val::ExternRef(None) => Some(None),
348             Val::ExternRef(Some(e)) => Some(Some(e)),
349             _ => None,
350         }
351     }
352 
353     /// Returns the underlying `externref` value of this `Val`, panicking if it's the
354     /// wrong type.
355     ///
356     /// If this is a null `externref`, then `None` is returned.
357     ///
358     /// If this is a non-null `externref`, then `Some(..)` is returned.
359     ///
360     /// # Panics
361     ///
362     /// Panics if `self` is not a (nullable) `externref`.
363     #[inline]
364     pub fn unwrap_externref(&self) -> Option<&Rooted<ExternRef>> {
365         self.externref().expect("expected externref")
366     }
367 
368     /// Attempt to access the underlying `anyref` value of this `Val`.
369     ///
370     /// If this is not an `anyref`, then `None` is returned.
371     ///
372     /// If this is a null `anyref`, then `Some(None)` is returned.
373     ///
374     /// If this is a non-null `anyref`, then `Some(Some(..))` is returned.
375     #[inline]
376     pub fn anyref(&self) -> Option<Option<&Rooted<AnyRef>>> {
377         match self {
378             Val::AnyRef(None) => Some(None),
379             Val::AnyRef(Some(e)) => Some(Some(e)),
380             _ => None,
381         }
382     }
383 
384     /// Returns the underlying `anyref` value of this `Val`, panicking if it's the
385     /// wrong type.
386     ///
387     /// If this is a null `anyref`, then `None` is returned.
388     ///
389     /// If this is a non-null `anyref`, then `Some(..)` is returned.
390     ///
391     /// # Panics
392     ///
393     /// Panics if `self` is not a (nullable) `anyref`.
394     #[inline]
395     pub fn unwrap_anyref(&self) -> Option<&Rooted<AnyRef>> {
396         self.anyref().expect("expected anyref")
397     }
398 
399     /// Attempt to access the underlying `funcref` value of this `Val`.
400     ///
401     /// If this is not an `funcref`, then `None` is returned.
402     ///
403     /// If this is a null `funcref`, then `Some(None)` is returned.
404     ///
405     /// If this is a non-null `funcref`, then `Some(Some(..))` is returned.
406     #[inline]
407     pub fn funcref(&self) -> Option<Option<&Func>> {
408         match self {
409             Val::FuncRef(None) => Some(None),
410             Val::FuncRef(Some(f)) => Some(Some(f)),
411             _ => None,
412         }
413     }
414 
415     /// Returns the underlying `funcref` value of this `Val`, panicking if it's the
416     /// wrong type.
417     ///
418     /// If this is a null `funcref`, then `None` is returned.
419     ///
420     /// If this is a non-null `funcref`, then `Some(..)` is returned.
421     ///
422     /// # Panics
423     ///
424     /// Panics if `self` is not a (nullable) `funcref`.
425     #[inline]
426     pub fn unwrap_funcref(&self) -> Option<&Func> {
427         self.funcref().expect("expected funcref")
428     }
429 
430     #[inline]
431     pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
432         match self {
433             Val::FuncRef(Some(f)) => f.comes_from_same_store(store),
434             Val::FuncRef(None) => true,
435 
436             Val::ExternRef(Some(x)) => x.comes_from_same_store(store),
437             Val::ExternRef(None) => true,
438 
439             Val::AnyRef(Some(a)) => a.comes_from_same_store(store),
440             Val::AnyRef(None) => true,
441 
442             // Integers, floats, and vectors have no association with any
443             // particular store, so they're always considered as "yes I came
444             // from that store",
445             Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => true,
446         }
447     }
448 }
449 
450 impl From<i32> for Val {
451     #[inline]
452     fn from(val: i32) -> Val {
453         Val::I32(val)
454     }
455 }
456 
457 impl From<i64> for Val {
458     #[inline]
459     fn from(val: i64) -> Val {
460         Val::I64(val)
461     }
462 }
463 
464 impl From<f32> for Val {
465     #[inline]
466     fn from(val: f32) -> Val {
467         Val::F32(val.to_bits())
468     }
469 }
470 
471 impl From<f64> for Val {
472     #[inline]
473     fn from(val: f64) -> Val {
474         Val::F64(val.to_bits())
475     }
476 }
477 
478 impl From<Ref> for Val {
479     #[inline]
480     fn from(val: Ref) -> Val {
481         match val {
482             Ref::Extern(e) => Val::ExternRef(e),
483             Ref::Func(f) => Val::FuncRef(f),
484             Ref::Any(a) => Val::AnyRef(a),
485         }
486     }
487 }
488 
489 impl From<Rooted<ExternRef>> for Val {
490     #[inline]
491     fn from(val: Rooted<ExternRef>) -> Val {
492         Val::ExternRef(Some(val))
493     }
494 }
495 
496 impl From<Option<Rooted<ExternRef>>> for Val {
497     #[inline]
498     fn from(val: Option<Rooted<ExternRef>>) -> Val {
499         Val::ExternRef(val)
500     }
501 }
502 
503 impl From<Rooted<AnyRef>> for Val {
504     #[inline]
505     fn from(val: Rooted<AnyRef>) -> Val {
506         Val::AnyRef(Some(val))
507     }
508 }
509 
510 impl From<Option<Rooted<AnyRef>>> for Val {
511     #[inline]
512     fn from(val: Option<Rooted<AnyRef>>) -> Val {
513         Val::AnyRef(val)
514     }
515 }
516 
517 impl From<Rooted<StructRef>> for Val {
518     #[inline]
519     fn from(val: Rooted<StructRef>) -> Val {
520         Val::AnyRef(Some(val.into()))
521     }
522 }
523 
524 impl From<Option<Rooted<StructRef>>> for Val {
525     #[inline]
526     fn from(val: Option<Rooted<StructRef>>) -> Val {
527         Val::AnyRef(val.map(Into::into))
528     }
529 }
530 
531 impl From<Rooted<ArrayRef>> for Val {
532     #[inline]
533     fn from(val: Rooted<ArrayRef>) -> Val {
534         Val::AnyRef(Some(val.into()))
535     }
536 }
537 
538 impl From<Option<Rooted<ArrayRef>>> for Val {
539     #[inline]
540     fn from(val: Option<Rooted<ArrayRef>>) -> Val {
541         Val::AnyRef(val.map(Into::into))
542     }
543 }
544 
545 impl From<Func> for Val {
546     #[inline]
547     fn from(val: Func) -> Val {
548         Val::FuncRef(Some(val))
549     }
550 }
551 
552 impl From<Option<Func>> for Val {
553     #[inline]
554     fn from(val: Option<Func>) -> Val {
555         Val::FuncRef(val)
556     }
557 }
558 
559 impl From<u128> for Val {
560     #[inline]
561     fn from(val: u128) -> Val {
562         Val::V128(val.into())
563     }
564 }
565 
566 impl From<V128> for Val {
567     #[inline]
568     fn from(val: V128) -> Val {
569         Val::V128(val)
570     }
571 }
572 
573 /// A reference.
574 ///
575 /// References come in three broad flavors:
576 ///
577 /// 1. Function references. These are references to a function that can be
578 ///    invoked.
579 ///
580 /// 2. External references. These are references to data that is external
581 ///    and opaque to the Wasm guest, provided by the host.
582 ///
583 /// 3. Internal references. These are references to allocations inside the
584 ///    Wasm's heap, such as structs and arrays. These are part of the GC
585 ///    proposal, and not yet implemented in Wasmtime.
586 ///
587 /// At the Wasm level, there are nullable and non-nullable variants of each type
588 /// of reference. Both variants are represented with `Ref` at the Wasmtime API
589 /// level. For example, values of both `(ref extern)` and `(ref null extern)`
590 /// types will be represented as `Ref::Extern(Option<ExternRef>)` in the
591 /// Wasmtime API. Nullable references are represented as `Option<Ref>` where
592 /// null references are represented as `None`. Wasm can construct null
593 /// references via the `ref.null <heap-type>` instruction.
594 ///
595 /// References are non-forgable: Wasm cannot create invalid references, for
596 /// example, by claiming that the integer `0xbad1bad2` is actually a reference.
597 #[derive(Debug, Clone)]
598 pub enum Ref {
599     // NB: We have a variant for each of the type hierarchies defined in Wasm,
600     // and push the `Option` that provides nullability into each variant. This
601     // allows us to get the most-precise type of any reference value, whether it
602     // is null or not, without any additional metadata.
603     //
604     // Consider if we instead had the nullability inside `Val::Ref` and each of
605     // the `Ref` variants did not have an `Option`:
606     //
607     //     enum Val {
608     //         Ref(Option<Ref>),
609     //         // Etc...
610     //     }
611     //     enum Ref {
612     //         Func(Func),
613     //         External(ExternRef),
614     //         // Etc...
615     //     }
616     //
617     // In this scenario, what type would we return from `Val::ty` for
618     // `Val::Ref(None)`? Because Wasm has multiple separate type hierarchies,
619     // there is no single common bottom type for all the different kinds of
620     // references. So in this scenario, `Val::Ref(None)` doesn't have enough
621     // information to reconstruct the value's type. That's a problem for us
622     // because we need to get a value's type at various times all over the code
623     // base.
624     //
625     /// A first-class reference to a WebAssembly function.
626     ///
627     /// The host, or the Wasm guest, can invoke this function.
628     ///
629     /// The host can create function references via [`Func::new`] or
630     /// [`Func::wrap`].
631     ///
632     /// The Wasm guest can create non-null function references via the
633     /// `ref.func` instruction, or null references via the `ref.null func`
634     /// instruction.
635     Func(Option<Func>),
636 
637     /// A reference to an value outside of the Wasm heap.
638     ///
639     /// These references are opaque to the Wasm itself. Wasm can't create
640     /// non-null external references, nor do anything with them accept pass them
641     /// around as function arguments and returns and place them into globals and
642     /// tables.
643     ///
644     /// Wasm can create null external references via the `ref.null extern`
645     /// instruction.
646     Extern(Option<Rooted<ExternRef>>),
647 
648     /// An internal reference.
649     ///
650     /// The `AnyRef` type represents WebAssembly `anyref` values. These can be
651     /// references to `struct`s and `array`s or inline/unboxed 31-bit
652     /// integers.
653     ///
654     /// Unlike `externref`, Wasm guests can directly allocate `anyref`s, and
655     /// does not need to rely on the host to do that.
656     Any(Option<Rooted<AnyRef>>),
657 }
658 
659 impl From<Func> for Ref {
660     #[inline]
661     fn from(f: Func) -> Ref {
662         Ref::Func(Some(f))
663     }
664 }
665 
666 impl From<Option<Func>> for Ref {
667     #[inline]
668     fn from(f: Option<Func>) -> Ref {
669         Ref::Func(f)
670     }
671 }
672 
673 impl From<Rooted<ExternRef>> for Ref {
674     #[inline]
675     fn from(e: Rooted<ExternRef>) -> Ref {
676         Ref::Extern(Some(e))
677     }
678 }
679 
680 impl From<Option<Rooted<ExternRef>>> for Ref {
681     #[inline]
682     fn from(e: Option<Rooted<ExternRef>>) -> Ref {
683         Ref::Extern(e)
684     }
685 }
686 
687 impl From<Rooted<AnyRef>> for Ref {
688     #[inline]
689     fn from(e: Rooted<AnyRef>) -> Ref {
690         Ref::Any(Some(e))
691     }
692 }
693 
694 impl From<Option<Rooted<AnyRef>>> for Ref {
695     #[inline]
696     fn from(e: Option<Rooted<AnyRef>>) -> Ref {
697         Ref::Any(e)
698     }
699 }
700 
701 impl From<Rooted<StructRef>> for Ref {
702     #[inline]
703     fn from(e: Rooted<StructRef>) -> Ref {
704         Ref::Any(Some(e.into()))
705     }
706 }
707 
708 impl From<Option<Rooted<StructRef>>> for Ref {
709     #[inline]
710     fn from(e: Option<Rooted<StructRef>>) -> Ref {
711         Ref::Any(e.map(Into::into))
712     }
713 }
714 
715 impl From<Rooted<ArrayRef>> for Ref {
716     #[inline]
717     fn from(e: Rooted<ArrayRef>) -> Ref {
718         Ref::Any(Some(e.into()))
719     }
720 }
721 
722 impl From<Option<Rooted<ArrayRef>>> for Ref {
723     #[inline]
724     fn from(e: Option<Rooted<ArrayRef>>) -> Ref {
725         Ref::Any(e.map(Into::into))
726     }
727 }
728 
729 impl Ref {
730     /// Create a null reference to the given heap type.
731     #[inline]
732     pub fn null(heap_type: &HeapType) -> Self {
733         match heap_type.top() {
734             HeapType::Any => Ref::Any(None),
735             HeapType::Extern => Ref::Extern(None),
736             HeapType::Func => Ref::Func(None),
737             ty => unreachable!("not a heap type: {ty:?}"),
738         }
739     }
740 
741     /// Is this a null reference?
742     #[inline]
743     pub fn is_null(&self) -> bool {
744         match self {
745             Ref::Any(None) | Ref::Extern(None) | Ref::Func(None) => true,
746             Ref::Any(Some(_)) | Ref::Extern(Some(_)) | Ref::Func(Some(_)) => false,
747         }
748     }
749 
750     /// Is this a non-null reference?
751     #[inline]
752     pub fn is_non_null(&self) -> bool {
753         !self.is_null()
754     }
755 
756     /// Is this an `extern` reference?
757     #[inline]
758     pub fn is_extern(&self) -> bool {
759         matches!(self, Ref::Extern(_))
760     }
761 
762     /// Get the underlying `extern` reference, if any.
763     ///
764     /// Returns `None` if this `Ref` is not an `extern` reference, eg it is a
765     /// `func` reference.
766     ///
767     /// Returns `Some(None)` if this `Ref` is a null `extern` reference.
768     ///
769     /// Returns `Some(Some(_))` if this `Ref` is a non-null `extern` reference.
770     #[inline]
771     pub fn as_extern(&self) -> Option<Option<&Rooted<ExternRef>>> {
772         match self {
773             Ref::Extern(e) => Some(e.as_ref()),
774             _ => None,
775         }
776     }
777 
778     /// Get the underlying `extern` reference, panicking if this is a different
779     /// kind of reference.
780     ///
781     /// Returns `None` if this `Ref` is a null `extern` reference.
782     ///
783     /// Returns `Some(_)` if this `Ref` is a non-null `extern` reference.
784     #[inline]
785     pub fn unwrap_extern(&self) -> Option<&Rooted<ExternRef>> {
786         self.as_extern()
787             .expect("Ref::unwrap_extern on non-extern reference")
788     }
789 
790     /// Is this an `any` reference?
791     #[inline]
792     pub fn is_any(&self) -> bool {
793         matches!(self, Ref::Any(_))
794     }
795 
796     /// Get the underlying `any` reference, if any.
797     ///
798     /// Returns `None` if this `Ref` is not an `any` reference, eg it is a
799     /// `func` reference.
800     ///
801     /// Returns `Some(None)` if this `Ref` is a null `any` reference.
802     ///
803     /// Returns `Some(Some(_))` if this `Ref` is a non-null `any` reference.
804     #[inline]
805     pub fn as_any(&self) -> Option<Option<&Rooted<AnyRef>>> {
806         match self {
807             Ref::Any(e) => Some(e.as_ref()),
808             _ => None,
809         }
810     }
811 
812     /// Get the underlying `any` reference, panicking if this is a different
813     /// kind of reference.
814     ///
815     /// Returns `None` if this `Ref` is a null `any` reference.
816     ///
817     /// Returns `Some(_)` if this `Ref` is a non-null `any` reference.
818     #[inline]
819     pub fn unwrap_any(&self) -> Option<&Rooted<AnyRef>> {
820         self.as_any().expect("Ref::unwrap_any on non-any reference")
821     }
822 
823     /// Is this a `func` reference?
824     #[inline]
825     pub fn is_func(&self) -> bool {
826         matches!(self, Ref::Func(_))
827     }
828 
829     /// Get the underlying `func` reference, if any.
830     ///
831     /// Returns `None` if this `Ref` is not an `func` reference, eg it is an
832     /// `extern` reference.
833     ///
834     /// Returns `Some(None)` if this `Ref` is a null `func` reference.
835     ///
836     /// Returns `Some(Some(_))` if this `Ref` is a non-null `func` reference.
837     #[inline]
838     pub fn as_func(&self) -> Option<Option<&Func>> {
839         match self {
840             Ref::Func(f) => Some(f.as_ref()),
841             _ => None,
842         }
843     }
844 
845     /// Get the underlying `func` reference, panicking if this is a different
846     /// kind of reference.
847     ///
848     /// Returns `None` if this `Ref` is a null `func` reference.
849     ///
850     /// Returns `Some(_)` if this `Ref` is a non-null `func` reference.
851     #[inline]
852     pub fn unwrap_func(&self) -> Option<&Func> {
853         self.as_func()
854             .expect("Ref::unwrap_func on non-func reference")
855     }
856 
857     /// Get the type of this reference.
858     ///
859     /// # Errors
860     ///
861     /// Return an error if this reference has been unrooted.
862     ///
863     /// # Panics
864     ///
865     /// Panics if this reference is associated with a different store.
866     pub fn ty(&self, store: impl AsContext) -> Result<RefType> {
867         self.load_ty(&store.as_context().0)
868     }
869 
870     pub(crate) fn load_ty(&self, store: &StoreOpaque) -> Result<RefType> {
871         assert!(self.comes_from_same_store(store));
872         Ok(RefType::new(
873             self.is_null(),
874             // NB: We choose the most-specific heap type we can here and let
875             // subtyping do its thing if callers are matching against a
876             // `HeapType::Func`.
877             match self {
878                 Ref::Extern(None) => HeapType::NoExtern,
879                 Ref::Extern(Some(_)) => HeapType::Extern,
880 
881                 Ref::Func(None) => HeapType::NoFunc,
882                 Ref::Func(Some(f)) => HeapType::ConcreteFunc(f.load_ty(store)),
883 
884                 Ref::Any(None) => HeapType::None,
885                 Ref::Any(Some(a)) => a._ty(store)?,
886             },
887         ))
888     }
889 
890     /// Does this reference value match the given type?
891     ///
892     /// Returns an error if the underlying `Rooted` has been unrooted.
893     ///
894     /// # Panics
895     ///
896     /// Panics if this reference is not associated with the given store.
897     pub fn matches_ty(&self, store: impl AsContext, ty: &RefType) -> Result<bool> {
898         self._matches_ty(&store.as_context().0, ty)
899     }
900 
901     pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &RefType) -> Result<bool> {
902         assert!(self.comes_from_same_store(store));
903         assert!(ty.comes_from_same_engine(store.engine()));
904         if self.is_null() && !ty.is_nullable() {
905             return Ok(false);
906         }
907         Ok(match (self, ty.heap_type()) {
908             (Ref::Extern(_), HeapType::Extern) => true,
909             (Ref::Extern(None), HeapType::NoExtern) => true,
910             (Ref::Extern(_), _) => false,
911 
912             (Ref::Func(_), HeapType::Func) => true,
913             (Ref::Func(None), HeapType::NoFunc | HeapType::ConcreteFunc(_)) => true,
914             (Ref::Func(Some(f)), HeapType::ConcreteFunc(func_ty)) => f._matches_ty(store, func_ty),
915             (Ref::Func(_), _) => false,
916 
917             (Ref::Any(_), HeapType::Any) => true,
918             (Ref::Any(Some(a)), HeapType::I31) => a._is_i31(store)?,
919             (Ref::Any(Some(a)), HeapType::Struct) => a._is_struct(store)?,
920             (Ref::Any(Some(a)), HeapType::ConcreteStruct(_ty)) => match a._as_struct(store)? {
921                 None => false,
922                 #[cfg_attr(not(feature = "gc"), allow(unreachable_patterns))]
923                 Some(s) => s._matches_ty(store, _ty)?,
924             },
925             (Ref::Any(Some(a)), HeapType::Eq) => a._is_eqref(store)?,
926             (Ref::Any(Some(a)), HeapType::Array) => a._is_array(store)?,
927             (Ref::Any(Some(a)), HeapType::ConcreteArray(_ty)) => match a._as_array(store)? {
928                 None => false,
929                 #[cfg_attr(not(feature = "gc"), allow(unreachable_patterns))]
930                 Some(a) => a._matches_ty(store, _ty)?,
931             },
932             (
933                 Ref::Any(None),
934                 HeapType::None
935                 | HeapType::I31
936                 | HeapType::ConcreteStruct(_)
937                 | HeapType::Struct
938                 | HeapType::ConcreteArray(_)
939                 | HeapType::Array
940                 | HeapType::Eq,
941             ) => true,
942             (Ref::Any(_), _) => false,
943         })
944     }
945 
946     pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &RefType) -> Result<()> {
947         if !self.comes_from_same_store(store) {
948             bail!("reference used with wrong store")
949         }
950         if !ty.comes_from_same_engine(store.engine()) {
951             bail!("type used with wrong engine")
952         }
953         if self._matches_ty(store, ty)? {
954             Ok(())
955         } else {
956             let actual_ty = self.load_ty(store)?;
957             bail!("type mismatch: expected {ty}, found {actual_ty}")
958         }
959     }
960 
961     pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
962         match self {
963             Ref::Func(Some(f)) => f.comes_from_same_store(store),
964             Ref::Func(None) => true,
965             Ref::Extern(Some(x)) => x.comes_from_same_store(store),
966             Ref::Extern(None) => true,
967             Ref::Any(Some(a)) => a.comes_from_same_store(store),
968             Ref::Any(None) => true,
969         }
970     }
971 
972     pub(crate) fn into_table_element(
973         self,
974         store: &mut StoreOpaque,
975         ty: &RefType,
976     ) -> Result<TableElement> {
977         let mut store = AutoAssertNoGc::new(store);
978         self.ensure_matches_ty(&store, &ty)
979             .context("type mismatch: value does not match table element type")?;
980 
981         match (self, ty.heap_type().top()) {
982             (Ref::Func(None), HeapType::Func) => {
983                 assert!(ty.is_nullable());
984                 Ok(TableElement::FuncRef(None))
985             }
986             (Ref::Func(Some(f)), HeapType::Func) => {
987                 debug_assert!(
988                     f.comes_from_same_store(&store),
989                     "checked in `ensure_matches_ty`"
990                 );
991                 Ok(TableElement::FuncRef(Some(f.vm_func_ref(&store))))
992             }
993 
994             (Ref::Extern(e), HeapType::Extern) => match e {
995                 None => {
996                     assert!(ty.is_nullable());
997                     Ok(TableElement::GcRef(None))
998                 }
999                 #[cfg_attr(not(feature = "gc"), allow(unreachable_patterns))]
1000                 Some(e) => {
1001                     let gc_ref = e.try_clone_gc_ref(&mut store)?;
1002                     Ok(TableElement::GcRef(Some(gc_ref)))
1003                 }
1004             },
1005 
1006             (Ref::Any(a), HeapType::Any) => match a {
1007                 None => {
1008                     assert!(ty.is_nullable());
1009                     Ok(TableElement::GcRef(None))
1010                 }
1011                 #[cfg_attr(not(feature = "gc"), allow(unreachable_patterns))]
1012                 Some(a) => {
1013                     let gc_ref = a.try_clone_gc_ref(&mut store)?;
1014                     Ok(TableElement::GcRef(Some(gc_ref)))
1015                 }
1016             },
1017 
1018             _ => unreachable!("checked that the value matches the type above"),
1019         }
1020     }
1021 }
1022 
1023 #[cfg(test)]
1024 mod tests {
1025     use crate::*;
1026 
1027     #[test]
1028     fn size_of_val() {
1029         // Try to keep tabs on the size of `Val` and make sure we don't grow its
1030         // size.
1031         let expected = if cfg!(target_arch = "x86_64")
1032             || cfg!(target_arch = "aarch64")
1033             || cfg!(target_arch = "s390x")
1034             || cfg!(target_arch = "riscv64")
1035             || cfg!(target_arch = "arm")
1036         {
1037             24
1038         } else if cfg!(target_arch = "x86") {
1039             20
1040         } else {
1041             panic!("unsupported architecture")
1042         };
1043         assert_eq!(std::mem::size_of::<Val>(), expected);
1044     }
1045 
1046     #[test]
1047     fn size_of_ref() {
1048         // Try to keep tabs on the size of `Ref` and make sure we don't grow its
1049         // size.
1050         let expected = if cfg!(target_arch = "x86_64")
1051             || cfg!(target_arch = "aarch64")
1052             || cfg!(target_arch = "s390x")
1053             || cfg!(target_arch = "riscv64")
1054             || cfg!(target_arch = "arm")
1055         {
1056             24
1057         } else if cfg!(target_arch = "x86") {
1058             20
1059         } else {
1060             panic!("unsupported architecture")
1061         };
1062         assert_eq!(std::mem::size_of::<Ref>(), expected);
1063     }
1064 
1065     #[test]
1066     #[should_panic]
1067     fn val_matches_ty_wrong_engine() {
1068         let e1 = Engine::default();
1069         let e2 = Engine::default();
1070 
1071         let t1 = FuncType::new(&e1, None, None);
1072         let t2 = FuncType::new(&e2, None, None);
1073 
1074         let mut s1 = Store::new(&e1, ());
1075         let f = Func::new(&mut s1, t1.clone(), |_caller, _args, _results| Ok(()));
1076 
1077         // Should panic.
1078         let _ = Val::FuncRef(Some(f)).matches_ty(
1079             &s1,
1080             &ValType::Ref(RefType::new(true, HeapType::ConcreteFunc(t2))),
1081         );
1082     }
1083 
1084     #[test]
1085     #[should_panic]
1086     fn ref_matches_ty_wrong_engine() {
1087         let e1 = Engine::default();
1088         let e2 = Engine::default();
1089 
1090         let t1 = FuncType::new(&e1, None, None);
1091         let t2 = FuncType::new(&e2, None, None);
1092 
1093         let mut s1 = Store::new(&e1, ());
1094         let f = Func::new(&mut s1, t1.clone(), |_caller, _args, _results| Ok(()));
1095 
1096         // Should panic.
1097         let _ = Ref::Func(Some(f)).matches_ty(&s1, &RefType::new(true, HeapType::ConcreteFunc(t2)));
1098     }
1099 }
1100