wasmtime/runtime/
values.rs

1use crate::runtime::vm::TableElement;
2use crate::store::{AutoAssertNoGc, StoreOpaque};
3use crate::{
4    prelude::*, AnyRef, ArrayRef, AsContext, AsContextMut, ExternRef, Func, HeapType, RefType,
5    Rooted, RootedGcRefImpl, StructRef, ValType, V128,
6};
7use core::ptr;
8
9pub 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)]
17pub 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
52macro_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
78impl 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
445impl From<i32> for Val {
446    #[inline]
447    fn from(val: i32) -> Val {
448        Val::I32(val)
449    }
450}
451
452impl From<i64> for Val {
453    #[inline]
454    fn from(val: i64) -> Val {
455        Val::I64(val)
456    }
457}
458
459impl From<f32> for Val {
460    #[inline]
461    fn from(val: f32) -> Val {
462        Val::F32(val.to_bits())
463    }
464}
465
466impl From<f64> for Val {
467    #[inline]
468    fn from(val: f64) -> Val {
469        Val::F64(val.to_bits())
470    }
471}
472
473impl 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
484impl From<Rooted<ExternRef>> for Val {
485    #[inline]
486    fn from(val: Rooted<ExternRef>) -> Val {
487        Val::ExternRef(Some(val))
488    }
489}
490
491impl From<Option<Rooted<ExternRef>>> for Val {
492    #[inline]
493    fn from(val: Option<Rooted<ExternRef>>) -> Val {
494        Val::ExternRef(val)
495    }
496}
497
498impl From<Rooted<AnyRef>> for Val {
499    #[inline]
500    fn from(val: Rooted<AnyRef>) -> Val {
501        Val::AnyRef(Some(val))
502    }
503}
504
505impl From<Option<Rooted<AnyRef>>> for Val {
506    #[inline]
507    fn from(val: Option<Rooted<AnyRef>>) -> Val {
508        Val::AnyRef(val)
509    }
510}
511
512impl From<Rooted<StructRef>> for Val {
513    #[inline]
514    fn from(val: Rooted<StructRef>) -> Val {
515        Val::AnyRef(Some(val.into()))
516    }
517}
518
519impl 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
526impl From<Rooted<ArrayRef>> for Val {
527    #[inline]
528    fn from(val: Rooted<ArrayRef>) -> Val {
529        Val::AnyRef(Some(val.into()))
530    }
531}
532
533impl 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
540impl From<Func> for Val {
541    #[inline]
542    fn from(val: Func) -> Val {
543        Val::FuncRef(Some(val))
544    }
545}
546
547impl From<Option<Func>> for Val {
548    #[inline]
549    fn from(val: Option<Func>) -> Val {
550        Val::FuncRef(val)
551    }
552}
553
554impl From<u128> for Val {
555    #[inline]
556    fn from(val: u128) -> Val {
557        Val::V128(val.into())
558    }
559}
560
561impl 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)]
593pub 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
654impl From<Func> for Ref {
655    #[inline]
656    fn from(f: Func) -> Ref {
657        Ref::Func(Some(f))
658    }
659}
660
661impl From<Option<Func>> for Ref {
662    #[inline]
663    fn from(f: Option<Func>) -> Ref {
664        Ref::Func(f)
665    }
666}
667
668impl From<Rooted<ExternRef>> for Ref {
669    #[inline]
670    fn from(e: Rooted<ExternRef>) -> Ref {
671        Ref::Extern(Some(e))
672    }
673}
674
675impl From<Option<Rooted<ExternRef>>> for Ref {
676    #[inline]
677    fn from(e: Option<Rooted<ExternRef>>) -> Ref {
678        Ref::Extern(e)
679    }
680}
681
682impl From<Rooted<AnyRef>> for Ref {
683    #[inline]
684    fn from(e: Rooted<AnyRef>) -> Ref {
685        Ref::Any(Some(e))
686    }
687}
688
689impl From<Option<Rooted<AnyRef>>> for Ref {
690    #[inline]
691    fn from(e: Option<Rooted<AnyRef>>) -> Ref {
692        Ref::Any(e)
693    }
694}
695
696impl From<Rooted<StructRef>> for Ref {
697    #[inline]
698    fn from(e: Rooted<StructRef>) -> Ref {
699        Ref::Any(Some(e.into()))
700    }
701}
702
703impl 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
710impl From<Rooted<ArrayRef>> for Ref {
711    #[inline]
712    fn from(e: Rooted<ArrayRef>) -> Ref {
713        Ref::Any(Some(e.into()))
714    }
715}
716
717impl 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
724impl 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)]
1019mod 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}