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