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