1 use crate::runtime::vm::TableElement;
2 use crate::store::{AutoAssertNoGc, StoreOpaque};
3 use crate::{
4     prelude::*, AnyRef, ArrayRef, AsContext, AsContextMut, ExternRef, Func, HeapType, RefType,
5     Rooted, RootedGcRefImpl, StructRef, ValType, V128,
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::Extern => ExternRef::_from_raw(store, raw.get_externref()).into(),
284 
285                     HeapType::NoExtern => Ref::Extern(None),
286 
287                     HeapType::Any
288                     | HeapType::Eq
289                     | HeapType::I31
290                     | HeapType::Array
291                     | HeapType::ConcreteArray(_)
292                     | HeapType::Struct
293                     | HeapType::ConcreteStruct(_) => {
294                         AnyRef::_from_raw(store, raw.get_anyref()).into()
295                     }
296 
297                     HeapType::None => Ref::Any(None),
298                 };
299                 assert!(
300                     ref_ty.is_nullable() || !ref_.is_null(),
301                     "if the type is not nullable, we shouldn't get null; got \
302                      type = {ref_ty}, ref = {ref_:?}"
303                 );
304                 ref_.into()
305             }
306         }
307     }
308 
309     accessors! {
310         e
311         (I32(i32) i32 unwrap_i32 *e)
312         (I64(i64) i64 unwrap_i64 *e)
313         (F32(f32) f32 unwrap_f32 f32::from_bits(*e))
314         (F64(f64) f64 unwrap_f64 f64::from_bits(*e))
315         (FuncRef(Option<&Func>) func_ref unwrap_func_ref e.as_ref())
316         (ExternRef(Option<&Rooted<ExternRef>>) extern_ref unwrap_extern_ref e.as_ref())
317         (AnyRef(Option<&Rooted<AnyRef>>) any_ref unwrap_any_ref e.as_ref())
318         (V128(V128) v128 unwrap_v128 *e)
319     }
320 
321     /// Get this value's underlying reference, if any.
322     #[inline]
323     pub fn ref_(self) -> Option<Ref> {
324         match self {
325             Val::FuncRef(f) => Some(Ref::Func(f)),
326             Val::ExternRef(e) => Some(Ref::Extern(e)),
327             Val::AnyRef(a) => Some(Ref::Any(a)),
328             Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => None,
329         }
330     }
331 
332     /// Attempt to access the underlying `externref` value of this `Val`.
333     ///
334     /// If this is not an `externref`, then `None` is returned.
335     ///
336     /// If this is a null `externref`, then `Some(None)` is returned.
337     ///
338     /// If this is a non-null `externref`, then `Some(Some(..))` is returned.
339     #[inline]
340     pub fn externref(&self) -> Option<Option<&Rooted<ExternRef>>> {
341         match self {
342             Val::ExternRef(None) => Some(None),
343             Val::ExternRef(Some(e)) => Some(Some(e)),
344             _ => None,
345         }
346     }
347 
348     /// Returns the underlying `externref` value of this `Val`, panicking if it's the
349     /// wrong type.
350     ///
351     /// If this is a null `externref`, then `None` is returned.
352     ///
353     /// If this is a non-null `externref`, then `Some(..)` is returned.
354     ///
355     /// # Panics
356     ///
357     /// Panics if `self` is not a (nullable) `externref`.
358     #[inline]
359     pub fn unwrap_externref(&self) -> Option<&Rooted<ExternRef>> {
360         self.externref().expect("expected externref")
361     }
362 
363     /// Attempt to access the underlying `anyref` value of this `Val`.
364     ///
365     /// If this is not an `anyref`, then `None` is returned.
366     ///
367     /// If this is a null `anyref`, then `Some(None)` is returned.
368     ///
369     /// If this is a non-null `anyref`, then `Some(Some(..))` is returned.
370     #[inline]
371     pub fn anyref(&self) -> Option<Option<&Rooted<AnyRef>>> {
372         match self {
373             Val::AnyRef(None) => Some(None),
374             Val::AnyRef(Some(e)) => Some(Some(e)),
375             _ => None,
376         }
377     }
378 
379     /// Returns the underlying `anyref` value of this `Val`, panicking if it's the
380     /// wrong type.
381     ///
382     /// If this is a null `anyref`, then `None` is returned.
383     ///
384     /// If this is a non-null `anyref`, then `Some(..)` is returned.
385     ///
386     /// # Panics
387     ///
388     /// Panics if `self` is not a (nullable) `anyref`.
389     #[inline]
390     pub fn unwrap_anyref(&self) -> Option<&Rooted<AnyRef>> {
391         self.anyref().expect("expected anyref")
392     }
393 
394     /// Attempt to access the underlying `funcref` value of this `Val`.
395     ///
396     /// If this is not an `funcref`, then `None` is returned.
397     ///
398     /// If this is a null `funcref`, then `Some(None)` is returned.
399     ///
400     /// If this is a non-null `funcref`, then `Some(Some(..))` is returned.
401     #[inline]
402     pub fn funcref(&self) -> Option<Option<&Func>> {
403         match self {
404             Val::FuncRef(None) => Some(None),
405             Val::FuncRef(Some(f)) => Some(Some(f)),
406             _ => None,
407         }
408     }
409 
410     /// Returns the underlying `funcref` value of this `Val`, panicking if it's the
411     /// wrong type.
412     ///
413     /// If this is a null `funcref`, then `None` is returned.
414     ///
415     /// If this is a non-null `funcref`, then `Some(..)` is returned.
416     ///
417     /// # Panics
418     ///
419     /// Panics if `self` is not a (nullable) `funcref`.
420     #[inline]
421     pub fn unwrap_funcref(&self) -> Option<&Func> {
422         self.funcref().expect("expected funcref")
423     }
424 
425     #[inline]
426     pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
427         match self {
428             Val::FuncRef(Some(f)) => f.comes_from_same_store(store),
429             Val::FuncRef(None) => true,
430 
431             Val::ExternRef(Some(x)) => x.comes_from_same_store(store),
432             Val::ExternRef(None) => true,
433 
434             Val::AnyRef(Some(a)) => a.comes_from_same_store(store),
435             Val::AnyRef(None) => true,
436 
437             // Integers, floats, and vectors have no association with any
438             // particular store, so they're always considered as "yes I came
439             // from that store",
440             Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => true,
441         }
442     }
443 }
444 
445 impl From<i32> for Val {
446     #[inline]
447     fn from(val: i32) -> Val {
448         Val::I32(val)
449     }
450 }
451 
452 impl From<i64> for Val {
453     #[inline]
454     fn from(val: i64) -> Val {
455         Val::I64(val)
456     }
457 }
458 
459 impl From<f32> for Val {
460     #[inline]
461     fn from(val: f32) -> Val {
462         Val::F32(val.to_bits())
463     }
464 }
465 
466 impl From<f64> for Val {
467     #[inline]
468     fn from(val: f64) -> Val {
469         Val::F64(val.to_bits())
470     }
471 }
472 
473 impl From<Ref> for Val {
474     #[inline]
475     fn from(val: Ref) -> Val {
476         match val {
477             Ref::Extern(e) => Val::ExternRef(e),
478             Ref::Func(f) => Val::FuncRef(f),
479             Ref::Any(a) => Val::AnyRef(a),
480         }
481     }
482 }
483 
484 impl From<Rooted<ExternRef>> for Val {
485     #[inline]
486     fn from(val: Rooted<ExternRef>) -> Val {
487         Val::ExternRef(Some(val))
488     }
489 }
490 
491 impl From<Option<Rooted<ExternRef>>> for Val {
492     #[inline]
493     fn from(val: Option<Rooted<ExternRef>>) -> Val {
494         Val::ExternRef(val)
495     }
496 }
497 
498 impl From<Rooted<AnyRef>> for Val {
499     #[inline]
500     fn from(val: Rooted<AnyRef>) -> Val {
501         Val::AnyRef(Some(val))
502     }
503 }
504 
505 impl From<Option<Rooted<AnyRef>>> for Val {
506     #[inline]
507     fn from(val: Option<Rooted<AnyRef>>) -> Val {
508         Val::AnyRef(val)
509     }
510 }
511 
512 impl From<Rooted<StructRef>> for Val {
513     #[inline]
514     fn from(val: Rooted<StructRef>) -> Val {
515         Val::AnyRef(Some(val.into()))
516     }
517 }
518 
519 impl From<Option<Rooted<StructRef>>> for Val {
520     #[inline]
521     fn from(val: Option<Rooted<StructRef>>) -> Val {
522         Val::AnyRef(val.map(Into::into))
523     }
524 }
525 
526 impl From<Rooted<ArrayRef>> for Val {
527     #[inline]
528     fn from(val: Rooted<ArrayRef>) -> Val {
529         Val::AnyRef(Some(val.into()))
530     }
531 }
532 
533 impl From<Option<Rooted<ArrayRef>>> for Val {
534     #[inline]
535     fn from(val: Option<Rooted<ArrayRef>>) -> Val {
536         Val::AnyRef(val.map(Into::into))
537     }
538 }
539 
540 impl From<Func> for Val {
541     #[inline]
542     fn from(val: Func) -> Val {
543         Val::FuncRef(Some(val))
544     }
545 }
546 
547 impl From<Option<Func>> for Val {
548     #[inline]
549     fn from(val: Option<Func>) -> Val {
550         Val::FuncRef(val)
551     }
552 }
553 
554 impl From<u128> for Val {
555     #[inline]
556     fn from(val: u128) -> Val {
557         Val::V128(val.into())
558     }
559 }
560 
561 impl From<V128> for Val {
562     #[inline]
563     fn from(val: V128) -> Val {
564         Val::V128(val)
565     }
566 }
567 
568 /// A reference.
569 ///
570 /// References come in three broad flavors:
571 ///
572 /// 1. Function references. These are references to a function that can be
573 ///    invoked.
574 ///
575 /// 2. External references. These are references to data that is external
576 ///    and opaque to the Wasm guest, provided by the host.
577 ///
578 /// 3. Internal references. These are references to allocations inside the
579 ///    Wasm's heap, such as structs and arrays. These are part of the GC
580 ///    proposal, and not yet implemented in Wasmtime.
581 ///
582 /// At the Wasm level, there are nullable and non-nullable variants of each type
583 /// of reference. Both variants are represented with `Ref` at the Wasmtime API
584 /// level. For example, values of both `(ref extern)` and `(ref null extern)`
585 /// types will be represented as `Ref::Extern(Option<ExternRef>)` in the
586 /// Wasmtime API. Nullable references are represented as `Option<Ref>` where
587 /// null references are represented as `None`. Wasm can construct null
588 /// references via the `ref.null <heap-type>` instruction.
589 ///
590 /// References are non-forgable: Wasm cannot create invalid references, for
591 /// example, by claiming that the integer `0xbad1bad2` is actually a reference.
592 #[derive(Debug, Clone)]
593 pub enum Ref {
594     // NB: We have a variant for each of the type hierarchies defined in Wasm,
595     // and push the `Option` that provides nullability into each variant. This
596     // allows us to get the most-precise type of any reference value, whether it
597     // is null or not, without any additional metadata.
598     //
599     // Consider if we instead had the nullability inside `Val::Ref` and each of
600     // the `Ref` variants did not have an `Option`:
601     //
602     //     enum Val {
603     //         Ref(Option<Ref>),
604     //         // Etc...
605     //     }
606     //     enum Ref {
607     //         Func(Func),
608     //         External(ExternRef),
609     //         // Etc...
610     //     }
611     //
612     // In this scenario, what type would we return from `Val::ty` for
613     // `Val::Ref(None)`? Because Wasm has multiple separate type hierarchies,
614     // there is no single common bottom type for all the different kinds of
615     // references. So in this scenario, `Val::Ref(None)` doesn't have enough
616     // information to reconstruct the value's type. That's a problem for us
617     // because we need to get a value's type at various times all over the code
618     // base.
619     //
620     /// A first-class reference to a WebAssembly function.
621     ///
622     /// The host, or the Wasm guest, can invoke this function.
623     ///
624     /// The host can create function references via [`Func::new`] or
625     /// [`Func::wrap`].
626     ///
627     /// The Wasm guest can create non-null function references via the
628     /// `ref.func` instruction, or null references via the `ref.null func`
629     /// instruction.
630     Func(Option<Func>),
631 
632     /// A reference to an value outside of the Wasm heap.
633     ///
634     /// These references are opaque to the Wasm itself. Wasm can't create
635     /// non-null external references, nor do anything with them accept pass them
636     /// around as function arguments and returns and place them into globals and
637     /// tables.
638     ///
639     /// Wasm can create null external references via the `ref.null extern`
640     /// instruction.
641     Extern(Option<Rooted<ExternRef>>),
642 
643     /// An internal reference.
644     ///
645     /// The `AnyRef` type represents WebAssembly `anyref` values. These can be
646     /// references to `struct`s and `array`s or inline/unboxed 31-bit
647     /// integers.
648     ///
649     /// Unlike `externref`, Wasm guests can directly allocate `anyref`s, and
650     /// does not need to rely on the host to do that.
651     Any(Option<Rooted<AnyRef>>),
652 }
653 
654 impl From<Func> for Ref {
655     #[inline]
656     fn from(f: Func) -> Ref {
657         Ref::Func(Some(f))
658     }
659 }
660 
661 impl From<Option<Func>> for Ref {
662     #[inline]
663     fn from(f: Option<Func>) -> Ref {
664         Ref::Func(f)
665     }
666 }
667 
668 impl From<Rooted<ExternRef>> for Ref {
669     #[inline]
670     fn from(e: Rooted<ExternRef>) -> Ref {
671         Ref::Extern(Some(e))
672     }
673 }
674 
675 impl From<Option<Rooted<ExternRef>>> for Ref {
676     #[inline]
677     fn from(e: Option<Rooted<ExternRef>>) -> Ref {
678         Ref::Extern(e)
679     }
680 }
681 
682 impl From<Rooted<AnyRef>> for Ref {
683     #[inline]
684     fn from(e: Rooted<AnyRef>) -> Ref {
685         Ref::Any(Some(e))
686     }
687 }
688 
689 impl From<Option<Rooted<AnyRef>>> for Ref {
690     #[inline]
691     fn from(e: Option<Rooted<AnyRef>>) -> Ref {
692         Ref::Any(e)
693     }
694 }
695 
696 impl From<Rooted<StructRef>> for Ref {
697     #[inline]
698     fn from(e: Rooted<StructRef>) -> Ref {
699         Ref::Any(Some(e.into()))
700     }
701 }
702 
703 impl From<Option<Rooted<StructRef>>> for Ref {
704     #[inline]
705     fn from(e: Option<Rooted<StructRef>>) -> Ref {
706         Ref::Any(e.map(Into::into))
707     }
708 }
709 
710 impl From<Rooted<ArrayRef>> for Ref {
711     #[inline]
712     fn from(e: Rooted<ArrayRef>) -> Ref {
713         Ref::Any(Some(e.into()))
714     }
715 }
716 
717 impl From<Option<Rooted<ArrayRef>>> for Ref {
718     #[inline]
719     fn from(e: Option<Rooted<ArrayRef>>) -> Ref {
720         Ref::Any(e.map(Into::into))
721     }
722 }
723 
724 impl Ref {
725     /// Create a null reference to the given heap type.
726     #[inline]
727     pub fn null(heap_type: &HeapType) -> Self {
728         match heap_type.top() {
729             HeapType::Any => Ref::Any(None),
730             HeapType::Extern => Ref::Extern(None),
731             HeapType::Func => Ref::Func(None),
732             ty => unreachable!("not a heap type: {ty:?}"),
733         }
734     }
735 
736     /// Is this a null reference?
737     #[inline]
738     pub fn is_null(&self) -> bool {
739         match self {
740             Ref::Any(None) | Ref::Extern(None) | Ref::Func(None) => true,
741             Ref::Any(Some(_)) | Ref::Extern(Some(_)) | Ref::Func(Some(_)) => false,
742         }
743     }
744 
745     /// Is this a non-null reference?
746     #[inline]
747     pub fn is_non_null(&self) -> bool {
748         !self.is_null()
749     }
750 
751     /// Is this an `extern` reference?
752     #[inline]
753     pub fn is_extern(&self) -> bool {
754         matches!(self, Ref::Extern(_))
755     }
756 
757     /// Get the underlying `extern` reference, if any.
758     ///
759     /// Returns `None` if this `Ref` is not an `extern` reference, eg it is a
760     /// `func` reference.
761     ///
762     /// Returns `Some(None)` if this `Ref` is a null `extern` reference.
763     ///
764     /// Returns `Some(Some(_))` if this `Ref` is a non-null `extern` reference.
765     #[inline]
766     pub fn as_extern(&self) -> Option<Option<&Rooted<ExternRef>>> {
767         match self {
768             Ref::Extern(e) => Some(e.as_ref()),
769             _ => None,
770         }
771     }
772 
773     /// Get the underlying `extern` reference, panicking if this is a different
774     /// kind of reference.
775     ///
776     /// Returns `None` if this `Ref` is a null `extern` reference.
777     ///
778     /// Returns `Some(_)` if this `Ref` is a non-null `extern` reference.
779     #[inline]
780     pub fn unwrap_extern(&self) -> Option<&Rooted<ExternRef>> {
781         self.as_extern()
782             .expect("Ref::unwrap_extern on non-extern reference")
783     }
784 
785     /// Is this an `any` reference?
786     #[inline]
787     pub fn is_any(&self) -> bool {
788         matches!(self, Ref::Any(_))
789     }
790 
791     /// Get the underlying `any` reference, if any.
792     ///
793     /// Returns `None` if this `Ref` is not an `any` reference, eg it is a
794     /// `func` reference.
795     ///
796     /// Returns `Some(None)` if this `Ref` is a null `any` reference.
797     ///
798     /// Returns `Some(Some(_))` if this `Ref` is a non-null `any` reference.
799     #[inline]
800     pub fn as_any(&self) -> Option<Option<&Rooted<AnyRef>>> {
801         match self {
802             Ref::Any(e) => Some(e.as_ref()),
803             _ => None,
804         }
805     }
806 
807     /// Get the underlying `any` reference, panicking if this is a different
808     /// kind of reference.
809     ///
810     /// Returns `None` if this `Ref` is a null `any` reference.
811     ///
812     /// Returns `Some(_)` if this `Ref` is a non-null `any` reference.
813     #[inline]
814     pub fn unwrap_any(&self) -> Option<&Rooted<AnyRef>> {
815         self.as_any().expect("Ref::unwrap_any on non-any reference")
816     }
817 
818     /// Is this a `func` reference?
819     #[inline]
820     pub fn is_func(&self) -> bool {
821         matches!(self, Ref::Func(_))
822     }
823 
824     /// Get the underlying `func` reference, if any.
825     ///
826     /// Returns `None` if this `Ref` is not an `func` reference, eg it is an
827     /// `extern` reference.
828     ///
829     /// Returns `Some(None)` if this `Ref` is a null `func` reference.
830     ///
831     /// Returns `Some(Some(_))` if this `Ref` is a non-null `func` reference.
832     #[inline]
833     pub fn as_func(&self) -> Option<Option<&Func>> {
834         match self {
835             Ref::Func(f) => Some(f.as_ref()),
836             _ => None,
837         }
838     }
839 
840     /// Get the underlying `func` reference, panicking if this is a different
841     /// kind of reference.
842     ///
843     /// Returns `None` if this `Ref` is a null `func` reference.
844     ///
845     /// Returns `Some(_)` if this `Ref` is a non-null `func` reference.
846     #[inline]
847     pub fn unwrap_func(&self) -> Option<&Func> {
848         self.as_func()
849             .expect("Ref::unwrap_func on non-func reference")
850     }
851 
852     /// Get the type of this reference.
853     ///
854     /// # Errors
855     ///
856     /// Return an error if this reference has been unrooted.
857     ///
858     /// # Panics
859     ///
860     /// Panics if this reference is associated with a different store.
861     pub fn ty(&self, store: impl AsContext) -> Result<RefType> {
862         self.load_ty(&store.as_context().0)
863     }
864 
865     pub(crate) fn load_ty(&self, store: &StoreOpaque) -> Result<RefType> {
866         assert!(self.comes_from_same_store(store));
867         Ok(RefType::new(
868             self.is_null(),
869             // NB: We choose the most-specific heap type we can here and let
870             // subtyping do its thing if callers are matching against a
871             // `HeapType::Func`.
872             match self {
873                 Ref::Extern(None) => HeapType::NoExtern,
874                 Ref::Extern(Some(_)) => HeapType::Extern,
875 
876                 Ref::Func(None) => HeapType::NoFunc,
877                 Ref::Func(Some(f)) => HeapType::ConcreteFunc(f.load_ty(store)),
878 
879                 Ref::Any(None) => HeapType::None,
880                 Ref::Any(Some(a)) => a._ty(store)?,
881             },
882         ))
883     }
884 
885     /// Does this reference value match the given type?
886     ///
887     /// Returns an error if the underlying `Rooted` has been unrooted.
888     ///
889     /// # Panics
890     ///
891     /// Panics if this reference is not associated with the given store.
892     pub fn matches_ty(&self, store: impl AsContext, ty: &RefType) -> Result<bool> {
893         self._matches_ty(&store.as_context().0, ty)
894     }
895 
896     pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &RefType) -> Result<bool> {
897         assert!(self.comes_from_same_store(store));
898         assert!(ty.comes_from_same_engine(store.engine()));
899         if self.is_null() && !ty.is_nullable() {
900             return Ok(false);
901         }
902         Ok(match (self, ty.heap_type()) {
903             (Ref::Extern(_), HeapType::Extern) => true,
904             (Ref::Extern(None), HeapType::NoExtern) => true,
905             (Ref::Extern(_), _) => false,
906 
907             (Ref::Func(_), HeapType::Func) => true,
908             (Ref::Func(None), HeapType::NoFunc | HeapType::ConcreteFunc(_)) => true,
909             (Ref::Func(Some(f)), HeapType::ConcreteFunc(func_ty)) => f._matches_ty(store, func_ty),
910             (Ref::Func(_), _) => false,
911 
912             (Ref::Any(_), HeapType::Any) => true,
913             (Ref::Any(Some(a)), HeapType::I31) => a._is_i31(store)?,
914             (Ref::Any(Some(a)), HeapType::Struct) => a._is_struct(store)?,
915             (Ref::Any(Some(a)), HeapType::ConcreteStruct(_ty)) => match a._as_struct(store)? {
916                 None => false,
917                 #[cfg_attr(not(feature = "gc"), allow(unreachable_patterns))]
918                 Some(s) => s._matches_ty(store, _ty)?,
919             },
920             (Ref::Any(Some(a)), HeapType::Eq) => a._is_eqref(store)?,
921             (Ref::Any(Some(a)), HeapType::Array) => a._is_array(store)?,
922             (Ref::Any(Some(a)), HeapType::ConcreteArray(_ty)) => match a._as_array(store)? {
923                 None => false,
924                 #[cfg_attr(not(feature = "gc"), allow(unreachable_patterns))]
925                 Some(a) => a._matches_ty(store, _ty)?,
926             },
927             (
928                 Ref::Any(None),
929                 HeapType::None
930                 | HeapType::I31
931                 | HeapType::ConcreteStruct(_)
932                 | HeapType::Struct
933                 | HeapType::ConcreteArray(_)
934                 | HeapType::Array
935                 | HeapType::Eq,
936             ) => true,
937             (Ref::Any(_), _) => false,
938         })
939     }
940 
941     pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &RefType) -> Result<()> {
942         if !self.comes_from_same_store(store) {
943             bail!("reference used with wrong store")
944         }
945         if !ty.comes_from_same_engine(store.engine()) {
946             bail!("type used with wrong engine")
947         }
948         if self._matches_ty(store, ty)? {
949             Ok(())
950         } else {
951             let actual_ty = self.load_ty(store)?;
952             bail!("type mismatch: expected {ty}, found {actual_ty}")
953         }
954     }
955 
956     pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
957         match self {
958             Ref::Func(Some(f)) => f.comes_from_same_store(store),
959             Ref::Func(None) => true,
960             Ref::Extern(Some(x)) => x.comes_from_same_store(store),
961             Ref::Extern(None) => true,
962             Ref::Any(Some(a)) => a.comes_from_same_store(store),
963             Ref::Any(None) => true,
964         }
965     }
966 
967     pub(crate) fn into_table_element(
968         self,
969         store: &mut StoreOpaque,
970         ty: &RefType,
971     ) -> Result<TableElement> {
972         let mut store = AutoAssertNoGc::new(store);
973         self.ensure_matches_ty(&store, &ty)
974             .context("type mismatch: value does not match table element type")?;
975 
976         match (self, ty.heap_type().top()) {
977             (Ref::Func(None), HeapType::Func) => {
978                 assert!(ty.is_nullable());
979                 Ok(TableElement::FuncRef(None))
980             }
981             (Ref::Func(Some(f)), HeapType::Func) => {
982                 debug_assert!(
983                     f.comes_from_same_store(&store),
984                     "checked in `ensure_matches_ty`"
985                 );
986                 Ok(TableElement::FuncRef(Some(f.vm_func_ref(&mut store))))
987             }
988 
989             (Ref::Extern(e), HeapType::Extern) => match e {
990                 None => {
991                     assert!(ty.is_nullable());
992                     Ok(TableElement::GcRef(None))
993                 }
994                 #[cfg_attr(not(feature = "gc"), allow(unreachable_patterns))]
995                 Some(e) => {
996                     let gc_ref = e.try_clone_gc_ref(&mut store)?;
997                     Ok(TableElement::GcRef(Some(gc_ref)))
998                 }
999             },
1000 
1001             (Ref::Any(a), HeapType::Any) => match a {
1002                 None => {
1003                     assert!(ty.is_nullable());
1004                     Ok(TableElement::GcRef(None))
1005                 }
1006                 #[cfg_attr(not(feature = "gc"), allow(unreachable_patterns))]
1007                 Some(a) => {
1008                     let gc_ref = a.try_clone_gc_ref(&mut store)?;
1009                     Ok(TableElement::GcRef(Some(gc_ref)))
1010                 }
1011             },
1012 
1013             _ => unreachable!("checked that the value matches the type above"),
1014         }
1015     }
1016 }
1017 
1018 #[cfg(test)]
1019 mod tests {
1020     use crate::*;
1021 
1022     #[test]
1023     fn size_of_val() {
1024         // Try to keep tabs on the size of `Val` and make sure we don't grow its
1025         // size.
1026         let expected = if cfg!(target_arch = "x86_64")
1027             || cfg!(target_arch = "aarch64")
1028             || cfg!(target_arch = "s390x")
1029             || cfg!(target_arch = "riscv64")
1030             || cfg!(target_arch = "arm")
1031         {
1032             24
1033         } else if cfg!(target_arch = "x86") {
1034             20
1035         } else {
1036             panic!("unsupported architecture")
1037         };
1038         assert_eq!(std::mem::size_of::<Val>(), expected);
1039     }
1040 
1041     #[test]
1042     fn size_of_ref() {
1043         // Try to keep tabs on the size of `Ref` and make sure we don't grow its
1044         // size.
1045         let expected = if cfg!(target_arch = "x86_64")
1046             || cfg!(target_arch = "aarch64")
1047             || cfg!(target_arch = "s390x")
1048             || cfg!(target_arch = "riscv64")
1049             || cfg!(target_arch = "arm")
1050         {
1051             24
1052         } else if cfg!(target_arch = "x86") {
1053             20
1054         } else {
1055             panic!("unsupported architecture")
1056         };
1057         assert_eq!(std::mem::size_of::<Ref>(), expected);
1058     }
1059 
1060     #[test]
1061     #[should_panic]
1062     fn val_matches_ty_wrong_engine() {
1063         let e1 = Engine::default();
1064         let e2 = Engine::default();
1065 
1066         let t1 = FuncType::new(&e1, None, None);
1067         let t2 = FuncType::new(&e2, None, None);
1068 
1069         let mut s1 = Store::new(&e1, ());
1070         let f = Func::new(&mut s1, t1.clone(), |_caller, _args, _results| Ok(()));
1071 
1072         // Should panic.
1073         let _ = Val::FuncRef(Some(f)).matches_ty(
1074             &s1,
1075             &ValType::Ref(RefType::new(true, HeapType::ConcreteFunc(t2))),
1076         );
1077     }
1078 
1079     #[test]
1080     #[should_panic]
1081     fn ref_matches_ty_wrong_engine() {
1082         let e1 = Engine::default();
1083         let e2 = Engine::default();
1084 
1085         let t1 = FuncType::new(&e1, None, None);
1086         let t2 = FuncType::new(&e2, None, None);
1087 
1088         let mut s1 = Store::new(&e1, ());
1089         let f = Func::new(&mut s1, t1.clone(), |_caller, _args, _results| Ok(()));
1090 
1091         // Should panic.
1092         let _ = Ref::Func(Some(f)).matches_ty(&s1, &RefType::new(true, HeapType::ConcreteFunc(t2)));
1093     }
1094 }
1095