wasmtime/runtime/gc/enabled/
anyref.rs

1//! Implementation of `anyref` in Wasmtime.
2
3use super::{ExternRef, RootedGcRefImpl};
4use crate::prelude::*;
5use crate::runtime::vm::VMGcRef;
6use crate::{
7    ArrayRef, ArrayType, AsContext, AsContextMut, EqRef, GcRefImpl, GcRootIndex, HeapType, I31,
8    ManuallyRooted, RefType, Result, Rooted, StructRef, StructType, ValRaw, ValType, WasmTy,
9    store::{AutoAssertNoGc, StoreOpaque},
10};
11use core::mem;
12use core::mem::MaybeUninit;
13use wasmtime_environ::VMGcKind;
14
15/// An `anyref` GC reference.
16///
17/// The `AnyRef` type represents WebAssembly `anyref` values. These can be
18/// references to `struct`s and `array`s or inline/unboxed 31-bit
19/// integers. Unlike `externref`, Wasm guests can directly allocate `anyref`s.
20///
21/// Like all WebAssembly references, these are opaque and unforgable to Wasm:
22/// they cannot be faked and Wasm cannot, for example, cast the integer
23/// `0x12345678` into a reference, pretend it is a valid `anyref`, and trick the
24/// host into dereferencing it and segfaulting or worse.
25///
26/// Note that you can also use `Rooted<AnyRef>` and `ManuallyRooted<AnyRef>` as
27/// a type parameter with [`Func::typed`][crate::Func::typed]- and
28/// [`Func::wrap`][crate::Func::wrap]-style APIs.
29///
30/// # Example
31///
32/// ```
33/// # use wasmtime::*;
34/// # fn _foo() -> Result<()> {
35/// let mut config = Config::new();
36/// config.wasm_gc(true);
37///
38/// let engine = Engine::new(&config)?;
39///
40/// // Define a module which does stuff with `anyref`s.
41/// let module = Module::new(&engine, r#"
42///     (module
43///         (func (export "increment-if-i31") (param (ref null any)) (result (ref null any))
44///             block
45///                 ;; Try to cast the arg to an `i31`, otherwise branch out
46///                 ;; of this `block`.
47///                 local.get 0
48///                 br_on_cast_fail (ref null any) (ref i31) 0
49///                 ;; Get the `i31`'s inner value and add one to it.
50///                 i31.get_u
51///                 i32.const 1
52///                 i32.add
53///                 ;; Wrap the incremented value back into an `i31` reference and
54///                 ;; return it.
55///                 ref.i31
56///                 return
57///             end
58///
59///             ;; If the `anyref` we were given is not an `i31`, just return it
60///             ;; as-is.
61///             local.get 0
62///         )
63///     )
64/// "#)?;
65///
66/// // Instantiate the module.
67/// let mut store = Store::new(&engine, ());
68/// let instance = Instance::new(&mut store, &module, &[])?;
69///
70/// // Extract the function.
71/// let increment_if_i31 = instance
72///     .get_typed_func::<Option<Rooted<AnyRef>>, Option<Rooted<AnyRef>>>(
73///         &mut store,
74///         "increment-if-i31",
75///     )?;
76///
77/// {
78///     // Create a new scope for the `Rooted` arguments and returns.
79///     let mut scope = RootScope::new(&mut store);
80///
81///     // Call the function with an `i31`.
82///     let arg = AnyRef::from_i31(&mut scope, I31::wrapping_u32(419));
83///     let result = increment_if_i31.call(&mut scope, Some(arg))?;
84///     assert_eq!(result.unwrap().as_i31(&scope)?, Some(I31::wrapping_u32(420)));
85///
86///     // Call the function with something that isn't an `i31`.
87///     let result = increment_if_i31.call(&mut scope, None)?;
88///     assert!(result.is_none());
89/// }
90/// # Ok(())
91/// # }
92/// ```
93#[derive(Debug)]
94#[repr(transparent)]
95pub struct AnyRef {
96    pub(super) inner: GcRootIndex,
97}
98
99impl From<Rooted<EqRef>> for Rooted<AnyRef> {
100    #[inline]
101    fn from(e: Rooted<EqRef>) -> Self {
102        e.to_anyref()
103    }
104}
105
106impl From<ManuallyRooted<EqRef>> for ManuallyRooted<AnyRef> {
107    #[inline]
108    fn from(e: ManuallyRooted<EqRef>) -> Self {
109        e.to_anyref()
110    }
111}
112
113impl From<Rooted<StructRef>> for Rooted<AnyRef> {
114    #[inline]
115    fn from(s: Rooted<StructRef>) -> Self {
116        s.to_anyref()
117    }
118}
119
120impl From<ManuallyRooted<StructRef>> for ManuallyRooted<AnyRef> {
121    #[inline]
122    fn from(s: ManuallyRooted<StructRef>) -> Self {
123        s.to_anyref()
124    }
125}
126
127impl From<Rooted<ArrayRef>> for Rooted<AnyRef> {
128    #[inline]
129    fn from(s: Rooted<ArrayRef>) -> Self {
130        s.to_anyref()
131    }
132}
133
134impl From<ManuallyRooted<ArrayRef>> for ManuallyRooted<AnyRef> {
135    #[inline]
136    fn from(s: ManuallyRooted<ArrayRef>) -> Self {
137        s.to_anyref()
138    }
139}
140
141unsafe impl GcRefImpl for AnyRef {
142    #[allow(private_interfaces)]
143    fn transmute_ref(index: &GcRootIndex) -> &Self {
144        // Safety: `AnyRef` is a newtype of a `GcRootIndex`.
145        let me: &Self = unsafe { mem::transmute(index) };
146
147        // Assert we really are just a newtype of a `GcRootIndex`.
148        assert!(matches!(
149            me,
150            Self {
151                inner: GcRootIndex { .. },
152            }
153        ));
154
155        me
156    }
157}
158
159impl AnyRef {
160    /// Construct an `anyref` from an `i31`.
161    ///
162    /// # Example
163    ///
164    /// ```
165    /// # use wasmtime::*;
166    /// # fn _foo() -> Result<()> {
167    /// let mut store = Store::<()>::default();
168    ///
169    /// // Create an `i31`.
170    /// let i31 = I31::wrapping_u32(999);
171    ///
172    /// // Convert it into an `anyref`.
173    /// let anyref = AnyRef::from_i31(&mut store, i31);
174    /// # Ok(())
175    /// # }
176    /// ```
177    pub fn from_i31(mut store: impl AsContextMut, value: I31) -> Rooted<Self> {
178        let mut store = AutoAssertNoGc::new(store.as_context_mut().0);
179        Self::_from_i31(&mut store, value)
180    }
181
182    pub(crate) fn _from_i31(store: &mut AutoAssertNoGc<'_>, value: I31) -> Rooted<Self> {
183        let gc_ref = VMGcRef::from_i31(value.runtime_i31());
184        Rooted::new(store, gc_ref)
185    }
186
187    /// Convert an `externref` into an `anyref`.
188    ///
189    /// This is equivalent to the `any.convert_extern` instruction in Wasm.
190    ///
191    /// You can recover the underlying `externref` again via the
192    /// [`ExternRef::convert_any`] method or the `extern.convert_any` Wasm
193    /// instruction.
194    ///
195    /// Returns an error if the `externref` GC reference has been unrooted (eg
196    /// if you attempt to use a `Rooted<ExternRef>` after exiting the scope it
197    /// was rooted within). See the documentation for
198    /// [`Rooted<T>`][crate::Rooted] for more details.
199    ///
200    /// # Example
201    ///
202    /// ```
203    /// use wasmtime::*;
204    /// # fn foo() -> Result<()> {
205    /// let engine = Engine::default();
206    /// let mut store = Store::new(&engine, ());
207    ///
208    /// // Create an `externref`.
209    /// let externref = ExternRef::new(&mut store, "hello")?;
210    ///
211    /// // Convert that `externref` into an `anyref`.
212    /// let anyref = AnyRef::convert_extern(&mut store, externref)?;
213    ///
214    /// // The converted value is an `anyref` but is not an `eqref`.
215    /// assert_eq!(anyref.matches_ty(&store, &HeapType::Any)?, true);
216    /// assert_eq!(anyref.matches_ty(&store, &HeapType::Eq)?, false);
217    ///
218    /// // We can convert it back to the original `externref` and get its
219    /// // associated host data again.
220    /// let externref = ExternRef::convert_any(&mut store, anyref)?;
221    /// let data = externref
222    ///     .data(&store)?
223    ///     .expect("externref should have host data")
224    ///     .downcast_ref::<&str>()
225    ///     .expect("host data should be a str");
226    /// assert_eq!(*data, "hello");
227    /// # Ok(()) }
228    /// # foo().unwrap();
229    pub fn convert_extern(
230        mut store: impl AsContextMut,
231        externref: Rooted<ExternRef>,
232    ) -> Result<Rooted<Self>> {
233        let mut store = AutoAssertNoGc::new(store.as_context_mut().0);
234        Self::_convert_extern(&mut store, externref)
235    }
236
237    pub(crate) fn _convert_extern(
238        store: &mut AutoAssertNoGc<'_>,
239        externref: Rooted<ExternRef>,
240    ) -> Result<Rooted<Self>> {
241        let gc_ref = externref.try_clone_gc_ref(store)?;
242        Ok(Self::from_cloned_gc_ref(store, gc_ref))
243    }
244
245    /// Creates a new strongly-owned [`AnyRef`] from the raw value provided.
246    ///
247    /// This is intended to be used in conjunction with [`Func::new_unchecked`],
248    /// [`Func::call_unchecked`], and [`ValRaw`] with its `anyref` field.
249    ///
250    /// This function assumes that `raw` is an `anyref` value which is currently
251    /// rooted within the [`Store`].
252    ///
253    /// # Unsafety
254    ///
255    /// This function is particularly `unsafe` because `raw` not only must be a
256    /// valid `anyref` value produced prior by [`AnyRef::to_raw`] but it must
257    /// also be correctly rooted within the store. When arguments are provided
258    /// to a callback with [`Func::new_unchecked`], for example, or returned via
259    /// [`Func::call_unchecked`], if a GC is performed within the store then
260    /// floating `anyref` values are not rooted and will be GC'd, meaning that
261    /// this function will no longer be safe to call with the values cleaned up.
262    /// This function must be invoked *before* possible GC operations can happen
263    /// (such as calling Wasm).
264    ///
265    /// When in doubt try to not use this. Instead use the safe Rust APIs of
266    /// [`TypedFunc`] and friends.
267    ///
268    /// [`Func::call_unchecked`]: crate::Func::call_unchecked
269    /// [`Func::new_unchecked`]: crate::Func::new_unchecked
270    /// [`Store`]: crate::Store
271    /// [`TypedFunc`]: crate::TypedFunc
272    /// [`ValRaw`]: crate::ValRaw
273    pub unsafe fn from_raw(mut store: impl AsContextMut, raw: u32) -> Option<Rooted<Self>> {
274        let mut store = AutoAssertNoGc::new(store.as_context_mut().0);
275        Self::_from_raw(&mut store, raw)
276    }
277
278    // (Not actually memory unsafe since we have indexed GC heaps.)
279    pub(crate) fn _from_raw(store: &mut AutoAssertNoGc, raw: u32) -> Option<Rooted<Self>> {
280        let gc_ref = VMGcRef::from_raw_u32(raw)?;
281        let gc_ref = if gc_ref.is_i31() {
282            gc_ref.copy_i31()
283        } else {
284            store.unwrap_gc_store_mut().clone_gc_ref(&gc_ref)
285        };
286        Some(Self::from_cloned_gc_ref(store, gc_ref))
287    }
288
289    /// Create a new `Rooted<AnyRef>` from the given GC reference.
290    ///
291    /// `gc_ref` should point to a valid `anyref` and should belong to the
292    /// store's GC heap. Failure to uphold these invariants is memory safe but
293    /// will lead to general incorrectness such as panics or wrong results.
294    pub(crate) fn from_cloned_gc_ref(
295        store: &mut AutoAssertNoGc<'_>,
296        gc_ref: VMGcRef,
297    ) -> Rooted<Self> {
298        debug_assert!(
299            gc_ref.is_i31()
300                || store
301                    .unwrap_gc_store()
302                    .header(&gc_ref)
303                    .kind()
304                    .matches(VMGcKind::AnyRef)
305                || store
306                    .unwrap_gc_store()
307                    .header(&gc_ref)
308                    .kind()
309                    .matches(VMGcKind::ExternRef)
310        );
311        Rooted::new(store, gc_ref)
312    }
313
314    #[inline]
315    pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
316        self.inner.comes_from_same_store(store)
317    }
318
319    /// Converts this [`AnyRef`] to a raw value suitable to store within a
320    /// [`ValRaw`].
321    ///
322    /// Returns an error if this `anyref` has been unrooted.
323    ///
324    /// # Unsafety
325    ///
326    /// Produces a raw value which is only safe to pass into a store if a GC
327    /// doesn't happen between when the value is produce and when it's passed
328    /// into the store.
329    ///
330    /// [`ValRaw`]: crate::ValRaw
331    pub unsafe fn to_raw(&self, mut store: impl AsContextMut) -> Result<u32> {
332        let mut store = AutoAssertNoGc::new(store.as_context_mut().0);
333        self._to_raw(&mut store)
334    }
335
336    pub(crate) unsafe fn _to_raw(&self, store: &mut AutoAssertNoGc<'_>) -> Result<u32> {
337        let gc_ref = self.inner.try_clone_gc_ref(store)?;
338        let raw = if gc_ref.is_i31() {
339            gc_ref.as_raw_non_zero_u32()
340        } else {
341            store.gc_store_mut()?.expose_gc_ref_to_wasm(gc_ref)
342        };
343        Ok(raw.get())
344    }
345
346    /// Get the type of this reference.
347    ///
348    /// # Errors
349    ///
350    /// Return an error if this reference has been unrooted.
351    ///
352    /// # Panics
353    ///
354    /// Panics if this reference is associated with a different store.
355    pub fn ty(&self, store: impl AsContext) -> Result<HeapType> {
356        self._ty(store.as_context().0)
357    }
358
359    pub(crate) fn _ty(&self, store: &StoreOpaque) -> Result<HeapType> {
360        let gc_ref = self.inner.try_gc_ref(store)?;
361        if gc_ref.is_i31() {
362            return Ok(HeapType::I31);
363        }
364
365        let header = store.gc_store()?.header(gc_ref);
366
367        if header.kind().matches(VMGcKind::ExternRef) {
368            return Ok(HeapType::Any);
369        }
370
371        debug_assert!(header.kind().matches(VMGcKind::AnyRef));
372        debug_assert!(header.kind().matches(VMGcKind::EqRef));
373
374        if header.kind().matches(VMGcKind::StructRef) {
375            return Ok(HeapType::ConcreteStruct(
376                StructType::from_shared_type_index(store.engine(), header.ty().unwrap()),
377            ));
378        }
379
380        if header.kind().matches(VMGcKind::ArrayRef) {
381            return Ok(HeapType::ConcreteArray(ArrayType::from_shared_type_index(
382                store.engine(),
383                header.ty().unwrap(),
384            )));
385        }
386
387        unreachable!("no other kinds of `anyref`s")
388    }
389
390    /// Does this `anyref` match the given type?
391    ///
392    /// That is, is this object's type a subtype of the given type?
393    ///
394    /// # Errors
395    ///
396    /// Return an error if this reference has been unrooted.
397    ///
398    /// # Panics
399    ///
400    /// Panics if this reference is associated with a different store.
401    pub fn matches_ty(&self, store: impl AsContext, ty: &HeapType) -> Result<bool> {
402        self._matches_ty(store.as_context().0, ty)
403    }
404
405    pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &HeapType) -> Result<bool> {
406        assert!(self.comes_from_same_store(store));
407        Ok(self._ty(store)?.matches(ty))
408    }
409
410    pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &HeapType) -> Result<()> {
411        if !self.comes_from_same_store(store) {
412            bail!("function used with wrong store");
413        }
414        if self._matches_ty(store, ty)? {
415            Ok(())
416        } else {
417            let actual_ty = self._ty(store)?;
418            bail!("type mismatch: expected `(ref {ty})`, found `(ref {actual_ty})`")
419        }
420    }
421
422    /// Is this `anyref` an `eqref`?
423    ///
424    /// # Errors
425    ///
426    /// Return an error if this reference has been unrooted.
427    ///
428    /// # Panics
429    ///
430    /// Panics if this reference is associated with a different store.
431    pub fn is_eqref(&self, store: impl AsContext) -> Result<bool> {
432        self._is_eqref(store.as_context().0)
433    }
434
435    pub(crate) fn _is_eqref(&self, store: &StoreOpaque) -> Result<bool> {
436        assert!(self.comes_from_same_store(store));
437        let gc_ref = self.inner.try_gc_ref(store)?;
438        Ok(gc_ref.is_i31() || store.gc_store()?.kind(gc_ref).matches(VMGcKind::EqRef))
439    }
440
441    /// Downcast this `anyref` to an `eqref`.
442    ///
443    /// If this `anyref` is an `eqref`, then `Some(_)` is returned.
444    ///
445    /// If this `anyref` is not an `eqref`, then `None` is returned.
446    ///
447    /// # Errors
448    ///
449    /// Return an error if this reference has been unrooted.
450    ///
451    /// # Panics
452    ///
453    /// Panics if this reference is associated with a different store.
454    pub fn as_eqref(&self, store: impl AsContext) -> Result<Option<Rooted<EqRef>>> {
455        self._as_eqref(store.as_context().0)
456    }
457
458    pub(crate) fn _as_eqref(&self, store: &StoreOpaque) -> Result<Option<Rooted<EqRef>>> {
459        if self._is_eqref(store)? {
460            Ok(Some(Rooted::from_gc_root_index(self.inner)))
461        } else {
462            Ok(None)
463        }
464    }
465
466    /// Downcast this `anyref` to an `eqref`, panicking if this `anyref` is not
467    /// an `eqref`.
468    ///
469    /// # Errors
470    ///
471    /// Return an error if this reference has been unrooted.
472    ///
473    /// # Panics
474    ///
475    /// Panics if this reference is associated with a different store, or if
476    /// this `anyref` is not an `eqref`.
477    pub fn unwrap_eqref(&self, store: impl AsContext) -> Result<Rooted<EqRef>> {
478        self._unwrap_eqref(store.as_context().0)
479    }
480
481    pub(crate) fn _unwrap_eqref(&self, store: &StoreOpaque) -> Result<Rooted<EqRef>> {
482        Ok(self
483            ._as_eqref(store)?
484            .expect("AnyRef::unwrap_eqref on non-eqref"))
485    }
486
487    /// Is this `anyref` an `i31`?
488    ///
489    /// # Errors
490    ///
491    /// Return an error if this reference has been unrooted.
492    ///
493    /// # Panics
494    ///
495    /// Panics if this reference is associated with a different store.
496    pub fn is_i31(&self, store: impl AsContext) -> Result<bool> {
497        self._is_i31(store.as_context().0)
498    }
499
500    pub(crate) fn _is_i31(&self, store: &StoreOpaque) -> Result<bool> {
501        assert!(self.comes_from_same_store(store));
502        let gc_ref = self.inner.try_gc_ref(store)?;
503        Ok(gc_ref.is_i31())
504    }
505
506    /// Downcast this `anyref` to an `i31`.
507    ///
508    /// If this `anyref` is an `i31`, then `Some(_)` is returned.
509    ///
510    /// If this `anyref` is not an `i31`, then `None` is returned.
511    ///
512    /// # Errors
513    ///
514    /// Return an error if this reference has been unrooted.
515    ///
516    /// # Panics
517    ///
518    /// Panics if this reference is associated with a different store.
519    pub fn as_i31(&self, store: impl AsContext) -> Result<Option<I31>> {
520        self._as_i31(store.as_context().0)
521    }
522
523    pub(crate) fn _as_i31(&self, store: &StoreOpaque) -> Result<Option<I31>> {
524        assert!(self.comes_from_same_store(store));
525        let gc_ref = self.inner.try_gc_ref(store)?;
526        Ok(gc_ref.as_i31().map(Into::into))
527    }
528
529    /// Downcast this `anyref` to an `i31`, panicking if this `anyref` is not an
530    /// `i31`.
531    ///
532    /// # Errors
533    ///
534    /// Return an error if this reference has been unrooted.
535    ///
536    /// # Panics
537    ///
538    /// Panics if this reference is associated with a different store, or if
539    /// this `anyref` is not an `i31`.
540    pub fn unwrap_i31(&self, store: impl AsContext) -> Result<I31> {
541        Ok(self.as_i31(store)?.expect("AnyRef::unwrap_i31 on non-i31"))
542    }
543
544    /// Is this `anyref` a `structref`?
545    ///
546    /// # Errors
547    ///
548    /// Return an error if this reference has been unrooted.
549    ///
550    /// # Panics
551    ///
552    /// Panics if this reference is associated with a different store.
553    pub fn is_struct(&self, store: impl AsContext) -> Result<bool> {
554        self._is_struct(store.as_context().0)
555    }
556
557    pub(crate) fn _is_struct(&self, store: &StoreOpaque) -> Result<bool> {
558        let gc_ref = self.inner.try_gc_ref(store)?;
559        Ok(!gc_ref.is_i31() && store.gc_store()?.kind(gc_ref).matches(VMGcKind::StructRef))
560    }
561
562    /// Downcast this `anyref` to a `structref`.
563    ///
564    /// If this `anyref` is a `structref`, then `Some(_)` is returned.
565    ///
566    /// If this `anyref` is not a `structref`, then `None` is returned.
567    ///
568    /// # Errors
569    ///
570    /// Return an error if this reference has been unrooted.
571    ///
572    /// # Panics
573    ///
574    /// Panics if this reference is associated with a different store.
575    pub fn as_struct(&self, store: impl AsContext) -> Result<Option<Rooted<StructRef>>> {
576        self._as_struct(store.as_context().0)
577    }
578
579    pub(crate) fn _as_struct(&self, store: &StoreOpaque) -> Result<Option<Rooted<StructRef>>> {
580        if self._is_struct(store)? {
581            Ok(Some(Rooted::from_gc_root_index(self.inner)))
582        } else {
583            Ok(None)
584        }
585    }
586
587    /// Downcast this `anyref` to a `structref`, panicking if this `anyref` is
588    /// not a `structref`.
589    ///
590    /// # Errors
591    ///
592    /// Return an error if this reference has been unrooted.
593    ///
594    /// # Panics
595    ///
596    /// Panics if this reference is associated with a different store, or if
597    /// this `anyref` is not a `struct`.
598    pub fn unwrap_struct(&self, store: impl AsContext) -> Result<Rooted<StructRef>> {
599        self._unwrap_struct(store.as_context().0)
600    }
601
602    pub(crate) fn _unwrap_struct(&self, store: &StoreOpaque) -> Result<Rooted<StructRef>> {
603        Ok(self
604            ._as_struct(store)?
605            .expect("AnyRef::unwrap_struct on non-structref"))
606    }
607
608    /// Is this `anyref` an `arrayref`?
609    ///
610    /// # Errors
611    ///
612    /// Return an error if this reference has been unrooted.
613    ///
614    /// # Panics
615    ///
616    /// Panics if this reference is associated with a different store.
617    pub fn is_array(&self, store: impl AsContext) -> Result<bool> {
618        self._is_array(store.as_context().0)
619    }
620
621    pub(crate) fn _is_array(&self, store: &StoreOpaque) -> Result<bool> {
622        let gc_ref = self.inner.try_gc_ref(store)?;
623        Ok(!gc_ref.is_i31() && store.gc_store()?.kind(gc_ref).matches(VMGcKind::ArrayRef))
624    }
625
626    /// Downcast this `anyref` to an `arrayref`.
627    ///
628    /// If this `anyref` is an `arrayref`, then `Some(_)` is returned.
629    ///
630    /// If this `anyref` is not an `arrayref`, then `None` is returned.
631    ///
632    /// # Errors
633    ///
634    /// Return an error if this reference has been unrooted.
635    ///
636    /// # Panics
637    ///
638    /// Panics if this reference is associated with a different store.
639    pub fn as_array(&self, store: impl AsContext) -> Result<Option<Rooted<ArrayRef>>> {
640        self._as_array(store.as_context().0)
641    }
642
643    pub(crate) fn _as_array(&self, store: &StoreOpaque) -> Result<Option<Rooted<ArrayRef>>> {
644        if self._is_array(store)? {
645            Ok(Some(Rooted::from_gc_root_index(self.inner)))
646        } else {
647            Ok(None)
648        }
649    }
650
651    /// Downcast this `anyref` to an `arrayref`, panicking if this `anyref` is
652    /// not an `arrayref`.
653    ///
654    /// # Errors
655    ///
656    /// Return an error if this reference has been unrooted.
657    ///
658    /// # Panics
659    ///
660    /// Panics if this reference is associated with a different store, or if
661    /// this `anyref` is not an `array`.
662    pub fn unwrap_array(&self, store: impl AsContext) -> Result<Rooted<ArrayRef>> {
663        self._unwrap_array(store.as_context().0)
664    }
665
666    pub(crate) fn _unwrap_array(&self, store: &StoreOpaque) -> Result<Rooted<ArrayRef>> {
667        Ok(self
668            ._as_array(store)?
669            .expect("AnyRef::unwrap_array on non-arrayref"))
670    }
671}
672
673unsafe impl WasmTy for Rooted<AnyRef> {
674    #[inline]
675    fn valtype() -> ValType {
676        ValType::Ref(RefType::new(false, HeapType::Any))
677    }
678
679    #[inline]
680    fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
681        self.comes_from_same_store(store)
682    }
683
684    #[inline]
685    fn dynamic_concrete_type_check(
686        &self,
687        store: &StoreOpaque,
688        _nullable: bool,
689        ty: &HeapType,
690    ) -> Result<()> {
691        self.ensure_matches_ty(store, ty)
692    }
693
694    fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
695        self.wasm_ty_store(store, ptr, ValRaw::anyref)
696    }
697
698    unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
699        Self::wasm_ty_load(store, ptr.get_anyref(), AnyRef::from_cloned_gc_ref)
700    }
701}
702
703unsafe impl WasmTy for Option<Rooted<AnyRef>> {
704    #[inline]
705    fn valtype() -> ValType {
706        ValType::ANYREF
707    }
708
709    #[inline]
710    fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
711        self.map_or(true, |x| x.comes_from_same_store(store))
712    }
713
714    #[inline]
715    fn dynamic_concrete_type_check(
716        &self,
717        store: &StoreOpaque,
718        nullable: bool,
719        ty: &HeapType,
720    ) -> Result<()> {
721        match self {
722            Some(a) => a.ensure_matches_ty(store, ty),
723            None => {
724                ensure!(
725                    nullable,
726                    "expected a non-null reference, but found a null reference"
727                );
728                Ok(())
729            }
730        }
731    }
732
733    #[inline]
734    fn is_vmgcref_and_points_to_object(&self) -> bool {
735        self.is_some()
736    }
737
738    fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
739        <Rooted<AnyRef>>::wasm_ty_option_store(self, store, ptr, ValRaw::anyref)
740    }
741
742    unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
743        <Rooted<AnyRef>>::wasm_ty_option_load(store, ptr.get_anyref(), AnyRef::from_cloned_gc_ref)
744    }
745}
746
747unsafe impl WasmTy for ManuallyRooted<AnyRef> {
748    #[inline]
749    fn valtype() -> ValType {
750        ValType::Ref(RefType::new(false, HeapType::Any))
751    }
752
753    #[inline]
754    fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
755        self.comes_from_same_store(store)
756    }
757
758    #[inline]
759    fn dynamic_concrete_type_check(
760        &self,
761        store: &StoreOpaque,
762        _nullable: bool,
763        ty: &HeapType,
764    ) -> Result<()> {
765        self.ensure_matches_ty(store, ty)
766    }
767
768    fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
769        self.wasm_ty_store(store, ptr, ValRaw::anyref)
770    }
771
772    unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
773        Self::wasm_ty_load(store, ptr.get_anyref(), AnyRef::from_cloned_gc_ref)
774    }
775}
776
777unsafe impl WasmTy for Option<ManuallyRooted<AnyRef>> {
778    #[inline]
779    fn valtype() -> ValType {
780        ValType::ANYREF
781    }
782
783    #[inline]
784    fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
785        self.as_ref()
786            .map_or(true, |x| x.comes_from_same_store(store))
787    }
788
789    #[inline]
790    fn dynamic_concrete_type_check(
791        &self,
792        store: &StoreOpaque,
793        nullable: bool,
794        ty: &HeapType,
795    ) -> Result<()> {
796        match self {
797            Some(a) => a.ensure_matches_ty(store, ty),
798            None => {
799                ensure!(
800                    nullable,
801                    "expected a non-null reference, but found a null reference"
802                );
803                Ok(())
804            }
805        }
806    }
807
808    #[inline]
809    fn is_vmgcref_and_points_to_object(&self) -> bool {
810        self.is_some()
811    }
812
813    fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
814        <ManuallyRooted<AnyRef>>::wasm_ty_option_store(self, store, ptr, ValRaw::anyref)
815    }
816
817    unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
818        <ManuallyRooted<AnyRef>>::wasm_ty_option_load(
819            store,
820            ptr.get_anyref(),
821            AnyRef::from_cloned_gc_ref,
822        )
823    }
824}