1 //! Working with GC `eqref`s.
2 
3 use crate::{
4     AnyRef, ArrayRef, ArrayType, AsContext, AsContextMut, GcRefImpl, GcRootIndex, HeapType, I31,
5     OwnedRooted, RefType, Rooted, StructRef, StructType, ValRaw, ValType, WasmTy,
6     prelude::*,
7     runtime::vm::VMGcRef,
8     store::{AutoAssertNoGc, StoreOpaque},
9 };
10 use core::mem::{self, MaybeUninit};
11 use wasmtime_environ::VMGcKind;
12 
13 /// A reference to a GC-managed object that can be tested for equality.
14 ///
15 /// The WebAssembly reference types that can be tested for equality, and
16 /// therefore are `eqref`s, include `structref`s, `arrayref`s, and
17 /// `i31ref`s. `funcref`s, `exnref`s, and `externref`s cannot be tested for
18 /// equality by Wasm, and are not `eqref`s.
19 ///
20 /// Use the [`Rooted::ref_eq`][Rooted::ref_eq] method to actually test two
21 /// references for equality.
22 ///
23 /// Like all WebAssembly references, these are opaque to and unforgeable by
24 /// Wasm: they cannot be faked and Wasm cannot, for example, cast the integer
25 /// `0x12345678` into a reference, pretend it is a valid `eqref`, and trick the
26 /// host into dereferencing it and segfaulting or worse.
27 ///
28 /// Note that you can also use `Rooted<EqRef>` and `OwnedRooted<EqRef>` as a
29 /// type parameter with [`Func::typed`][crate::Func::typed]- and
30 /// [`Func::wrap`][crate::Func::wrap]-style APIs.
31 ///
32 /// # Example
33 ///
34 /// ```
35 /// use wasmtime::*;
36 ///
37 /// # fn foo() -> Result<()> {
38 /// let mut config = Config::new();
39 /// config.wasm_function_references(true);
40 /// config.wasm_gc(true);
41 ///
42 /// let engine = Engine::new(&config)?;
43 /// let mut store = Store::new(&engine, ());
44 ///
45 /// // Define a module that exports a function that returns a new `eqref` each
46 /// // time it is invoked.
47 /// let module = Module::new(&engine, r#"
48 ///     (module
49 ///         (global $g (mut i32) (i32.const 0))
50 ///         (func (export "new-eqref") (result (ref eq))
51 ///             ;; Increment $g.
52 ///             global.get $g
53 ///             i32.const 1
54 ///             i32.add
55 ///             global.set $g
56 ///
57 ///             ;; Create an `i31ref`, which is a kind of `eqref`, from $g.
58 ///             global.get $g
59 ///             ref.i31
60 ///         )
61 ///     )
62 /// "#)?;
63 ///
64 /// // Instantiate the module.
65 /// let instance = Instance::new(&mut store, &module, &[])?;
66 ///
67 /// // Get the exported function.
68 /// let new_eqref = instance.get_typed_func::<(), Rooted<EqRef>>(&mut store, "new-eqref")?;
69 ///
70 /// {
71 ///     let mut scope = RootScope::new(&mut store);
72 ///
73 ///     // Call the function to get an `eqref`.
74 ///     let x = new_eqref.call(&mut scope, ())?;
75 ///
76 ///     // `x` is equal to itself!
77 ///     assert!(Rooted::ref_eq(&scope, &x, &x)?);
78 ///
79 ///     // Call the function again to get a new, different `eqref`.
80 ///     let y = new_eqref.call(&mut scope, ())?;
81 ///
82 ///     // `x` is not equal to `y`!
83 ///     assert!(!Rooted::ref_eq(&scope, &x, &y)?);
84 /// }
85 /// # Ok(())
86 /// # }
87 /// # foo().unwrap();
88 /// ```
89 #[derive(Debug)]
90 #[repr(transparent)]
91 pub struct EqRef {
92     pub(super) inner: GcRootIndex,
93 }
94 
95 impl From<Rooted<StructRef>> for Rooted<EqRef> {
96     #[inline]
from(s: Rooted<StructRef>) -> Self97     fn from(s: Rooted<StructRef>) -> Self {
98         s.to_eqref()
99     }
100 }
101 
102 impl From<OwnedRooted<StructRef>> for OwnedRooted<EqRef> {
103     #[inline]
from(s: OwnedRooted<StructRef>) -> Self104     fn from(s: OwnedRooted<StructRef>) -> Self {
105         s.to_eqref()
106     }
107 }
108 
109 impl From<Rooted<ArrayRef>> for Rooted<EqRef> {
110     #[inline]
from(s: Rooted<ArrayRef>) -> Self111     fn from(s: Rooted<ArrayRef>) -> Self {
112         s.to_eqref()
113     }
114 }
115 
116 impl From<OwnedRooted<ArrayRef>> for OwnedRooted<EqRef> {
117     #[inline]
from(s: OwnedRooted<ArrayRef>) -> Self118     fn from(s: OwnedRooted<ArrayRef>) -> Self {
119         s.to_eqref()
120     }
121 }
122 
123 unsafe impl GcRefImpl for EqRef {
transmute_ref(index: &GcRootIndex) -> &Self124     fn transmute_ref(index: &GcRootIndex) -> &Self {
125         // Safety: `EqRef` is a newtype of a `GcRootIndex`.
126         let me: &Self = unsafe { mem::transmute(index) };
127 
128         // Assert we really are just a newtype of a `GcRootIndex`.
129         assert!(matches!(
130             me,
131             Self {
132                 inner: GcRootIndex { .. },
133             }
134         ));
135 
136         me
137     }
138 }
139 
140 impl Rooted<EqRef> {
141     /// Upcast this `eqref` into an `anyref`.
142     #[inline]
to_anyref(self) -> Rooted<AnyRef>143     pub fn to_anyref(self) -> Rooted<AnyRef> {
144         self.unchecked_cast()
145     }
146 }
147 
148 impl OwnedRooted<EqRef> {
149     /// Upcast this `eqref` into an `anyref`.
150     #[inline]
to_anyref(self) -> OwnedRooted<AnyRef>151     pub fn to_anyref(self) -> OwnedRooted<AnyRef> {
152         self.unchecked_cast()
153     }
154 }
155 
156 impl EqRef {
157     /// Create a new `Rooted<AnyRef>` from the given GC reference.
158     ///
159     /// `gc_ref` should point to a valid `anyref` and should belong to the
160     /// store's GC heap. Failure to uphold these invariants is memory safe but
161     /// will lead to general incorrectness such as panics or wrong results.
from_cloned_gc_ref( store: &mut AutoAssertNoGc<'_>, gc_ref: VMGcRef, ) -> Rooted<Self>162     pub(crate) fn from_cloned_gc_ref(
163         store: &mut AutoAssertNoGc<'_>,
164         gc_ref: VMGcRef,
165     ) -> Rooted<Self> {
166         debug_assert!(
167             gc_ref.is_i31()
168                 || store
169                     .unwrap_gc_store()
170                     .header(&gc_ref)
171                     .kind()
172                     .matches(VMGcKind::EqRef)
173         );
174         Rooted::new(store, gc_ref)
175     }
176 
177     #[inline]
comes_from_same_store(&self, store: &StoreOpaque) -> bool178     pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
179         self.inner.comes_from_same_store(store)
180     }
181 
182     /// Get the type of this reference.
183     ///
184     /// # Errors
185     ///
186     /// Return an error if this reference has been unrooted.
187     ///
188     /// # Panics
189     ///
190     /// Panics if this reference is associated with a different store.
ty(&self, store: impl AsContext) -> Result<HeapType>191     pub fn ty(&self, store: impl AsContext) -> Result<HeapType> {
192         self._ty(store.as_context().0)
193     }
194 
_ty(&self, store: &StoreOpaque) -> Result<HeapType>195     pub(crate) fn _ty(&self, store: &StoreOpaque) -> Result<HeapType> {
196         let gc_ref = self.inner.try_gc_ref(store)?;
197         if gc_ref.is_i31() {
198             return Ok(HeapType::I31);
199         }
200 
201         let header = store.require_gc_store()?.header(gc_ref);
202 
203         if header.kind().matches(VMGcKind::StructRef) {
204             return Ok(HeapType::ConcreteStruct(
205                 StructType::from_shared_type_index(store.engine(), header.ty().unwrap()),
206             ));
207         }
208 
209         if header.kind().matches(VMGcKind::ArrayRef) {
210             return Ok(HeapType::ConcreteArray(ArrayType::from_shared_type_index(
211                 store.engine(),
212                 header.ty().unwrap(),
213             )));
214         }
215 
216         unreachable!("no other kinds of `eqref`s")
217     }
218 
219     /// Does this `eqref` match the given type?
220     ///
221     /// That is, is this object's type a subtype of the given type?
222     ///
223     /// # Errors
224     ///
225     /// Return an error if this reference has been unrooted.
226     ///
227     /// # Panics
228     ///
229     /// Panics if this reference is associated with a different store.
matches_ty(&self, store: impl AsContext, ty: &HeapType) -> Result<bool>230     pub fn matches_ty(&self, store: impl AsContext, ty: &HeapType) -> Result<bool> {
231         self._matches_ty(store.as_context().0, ty)
232     }
233 
_matches_ty(&self, store: &StoreOpaque, ty: &HeapType) -> Result<bool>234     pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &HeapType) -> Result<bool> {
235         assert!(self.comes_from_same_store(store));
236         Ok(self._ty(store)?.matches(ty))
237     }
238 
ensure_matches_ty(&self, store: &StoreOpaque, ty: &HeapType) -> Result<()>239     pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &HeapType) -> Result<()> {
240         if !self.comes_from_same_store(store) {
241             bail!("function used with wrong store");
242         }
243         if self._matches_ty(store, ty)? {
244             Ok(())
245         } else {
246             let actual_ty = self._ty(store)?;
247             bail!("type mismatch: expected `(ref {ty})`, found `(ref {actual_ty})`")
248         }
249     }
250 
251     /// Construct an `eqref` from an `i31`.
252     ///
253     /// # Example
254     ///
255     /// ```
256     /// # use wasmtime::*;
257     /// # fn _foo() -> Result<()> {
258     /// let mut store = Store::<()>::default();
259     ///
260     /// // Create an `i31`.
261     /// let i31 = I31::wrapping_u32(999);
262     ///
263     /// // Convert it into an `eqref`.
264     /// let eqref = EqRef::from_i31(&mut store, i31);
265     /// # Ok(())
266     /// # }
267     /// ```
from_i31(mut store: impl AsContextMut, value: I31) -> Rooted<Self>268     pub fn from_i31(mut store: impl AsContextMut, value: I31) -> Rooted<Self> {
269         let mut store = AutoAssertNoGc::new(store.as_context_mut().0);
270         Self::_from_i31(&mut store, value)
271     }
272 
_from_i31(store: &mut AutoAssertNoGc<'_>, value: I31) -> Rooted<Self>273     pub(crate) fn _from_i31(store: &mut AutoAssertNoGc<'_>, value: I31) -> Rooted<Self> {
274         let gc_ref = VMGcRef::from_i31(value.runtime_i31());
275         Rooted::new(store, gc_ref)
276     }
277 
278     /// Is this `eqref` an `i31`?
279     ///
280     /// # Errors
281     ///
282     /// Return an error if this reference has been unrooted.
283     ///
284     /// # Panics
285     ///
286     /// Panics if this reference is associated with a different store.
is_i31(&self, store: impl AsContext) -> Result<bool>287     pub fn is_i31(&self, store: impl AsContext) -> Result<bool> {
288         self._is_i31(store.as_context().0)
289     }
290 
_is_i31(&self, store: &StoreOpaque) -> Result<bool>291     pub(crate) fn _is_i31(&self, store: &StoreOpaque) -> Result<bool> {
292         assert!(self.comes_from_same_store(store));
293         let gc_ref = self.inner.try_gc_ref(store)?;
294         Ok(gc_ref.is_i31())
295     }
296 
297     /// Downcast this `eqref` to an `i31`.
298     ///
299     /// If this `eqref` is an `i31`, then `Some(_)` is returned.
300     ///
301     /// If this `eqref` is not an `i31`, then `None` is returned.
302     ///
303     /// # Errors
304     ///
305     /// Return an error if this reference has been unrooted.
306     ///
307     /// # Panics
308     ///
309     /// Panics if this reference is associated with a different store.
as_i31(&self, store: impl AsContext) -> Result<Option<I31>>310     pub fn as_i31(&self, store: impl AsContext) -> Result<Option<I31>> {
311         self._as_i31(store.as_context().0)
312     }
313 
_as_i31(&self, store: &StoreOpaque) -> Result<Option<I31>>314     pub(crate) fn _as_i31(&self, store: &StoreOpaque) -> Result<Option<I31>> {
315         assert!(self.comes_from_same_store(store));
316         let gc_ref = self.inner.try_gc_ref(store)?;
317         Ok(gc_ref.as_i31().map(Into::into))
318     }
319 
320     /// Downcast this `eqref` to an `i31`, panicking if this `eqref` is not an
321     /// `i31`.
322     ///
323     /// # Errors
324     ///
325     /// Return an error if this reference has been unrooted.
326     ///
327     /// # Panics
328     ///
329     /// Panics if this reference is associated with a different store, or if
330     /// this `eqref` is not an `i31`.
unwrap_i31(&self, store: impl AsContext) -> Result<I31>331     pub fn unwrap_i31(&self, store: impl AsContext) -> Result<I31> {
332         Ok(self.as_i31(store)?.expect("EqRef::unwrap_i31 on non-i31"))
333     }
334 
335     /// Is this `eqref` a `structref`?
336     ///
337     /// # Errors
338     ///
339     /// Return an error if this reference has been unrooted.
340     ///
341     /// # Panics
342     ///
343     /// Panics if this reference is associated with a different store.
is_struct(&self, store: impl AsContext) -> Result<bool>344     pub fn is_struct(&self, store: impl AsContext) -> Result<bool> {
345         self._is_struct(store.as_context().0)
346     }
347 
_is_struct(&self, store: &StoreOpaque) -> Result<bool>348     pub(crate) fn _is_struct(&self, store: &StoreOpaque) -> Result<bool> {
349         let gc_ref = self.inner.try_gc_ref(store)?;
350         Ok(!gc_ref.is_i31()
351             && store
352                 .require_gc_store()?
353                 .kind(gc_ref)
354                 .matches(VMGcKind::StructRef))
355     }
356 
357     /// Downcast this `eqref` to a `structref`.
358     ///
359     /// If this `eqref` is a `structref`, then `Some(_)` is returned.
360     ///
361     /// If this `eqref` is not a `structref`, then `None` is returned.
362     ///
363     /// # Errors
364     ///
365     /// Return an error if this reference has been unrooted.
366     ///
367     /// # Panics
368     ///
369     /// Panics if this reference is associated with a different store.
as_struct(&self, store: impl AsContext) -> Result<Option<Rooted<StructRef>>>370     pub fn as_struct(&self, store: impl AsContext) -> Result<Option<Rooted<StructRef>>> {
371         self._as_struct(store.as_context().0)
372     }
373 
_as_struct(&self, store: &StoreOpaque) -> Result<Option<Rooted<StructRef>>>374     pub(crate) fn _as_struct(&self, store: &StoreOpaque) -> Result<Option<Rooted<StructRef>>> {
375         if self._is_struct(store)? {
376             Ok(Some(Rooted::from_gc_root_index(self.inner)))
377         } else {
378             Ok(None)
379         }
380     }
381 
382     /// Downcast this `eqref` to a `structref`, panicking if this `eqref` is
383     /// not a `structref`.
384     ///
385     /// # Errors
386     ///
387     /// Return an error if this reference has been unrooted.
388     ///
389     /// # Panics
390     ///
391     /// Panics if this reference is associated with a different store, or if
392     /// this `eqref` is not a `struct`.
unwrap_struct(&self, store: impl AsContext) -> Result<Rooted<StructRef>>393     pub fn unwrap_struct(&self, store: impl AsContext) -> Result<Rooted<StructRef>> {
394         self._unwrap_struct(store.as_context().0)
395     }
396 
_unwrap_struct(&self, store: &StoreOpaque) -> Result<Rooted<StructRef>>397     pub(crate) fn _unwrap_struct(&self, store: &StoreOpaque) -> Result<Rooted<StructRef>> {
398         Ok(self
399             ._as_struct(store)?
400             .expect("EqRef::unwrap_struct on non-structref"))
401     }
402 
403     /// Is this `eqref` an `arrayref`?
404     ///
405     /// # Errors
406     ///
407     /// Return an error if this reference has been unrooted.
408     ///
409     /// # Panics
410     ///
411     /// Panics if this reference is associated with a different store.
is_array(&self, store: impl AsContext) -> Result<bool>412     pub fn is_array(&self, store: impl AsContext) -> Result<bool> {
413         self._is_array(store.as_context().0)
414     }
415 
_is_array(&self, store: &StoreOpaque) -> Result<bool>416     pub(crate) fn _is_array(&self, store: &StoreOpaque) -> Result<bool> {
417         let gc_ref = self.inner.try_gc_ref(store)?;
418         Ok(!gc_ref.is_i31()
419             && store
420                 .require_gc_store()?
421                 .kind(gc_ref)
422                 .matches(VMGcKind::ArrayRef))
423     }
424 
425     /// Downcast this `eqref` to an `arrayref`.
426     ///
427     /// If this `eqref` is an `arrayref`, then `Some(_)` is returned.
428     ///
429     /// If this `eqref` is not an `arrayref`, then `None` is returned.
430     ///
431     /// # Errors
432     ///
433     /// Return an error if this reference has been unrooted.
434     ///
435     /// # Panics
436     ///
437     /// Panics if this reference is associated with a different store.
as_array(&self, store: impl AsContext) -> Result<Option<Rooted<ArrayRef>>>438     pub fn as_array(&self, store: impl AsContext) -> Result<Option<Rooted<ArrayRef>>> {
439         self._as_array(store.as_context().0)
440     }
441 
_as_array(&self, store: &StoreOpaque) -> Result<Option<Rooted<ArrayRef>>>442     pub(crate) fn _as_array(&self, store: &StoreOpaque) -> Result<Option<Rooted<ArrayRef>>> {
443         if self._is_array(store)? {
444             Ok(Some(Rooted::from_gc_root_index(self.inner)))
445         } else {
446             Ok(None)
447         }
448     }
449 
450     /// Downcast this `eqref` to an `arrayref`, panicking if this `eqref` is
451     /// not an `arrayref`.
452     ///
453     /// # Errors
454     ///
455     /// Return an error if this reference has been unrooted.
456     ///
457     /// # Panics
458     ///
459     /// Panics if this reference is associated with a different store, or if
460     /// this `eqref` is not an `array`.
unwrap_array(&self, store: impl AsContext) -> Result<Rooted<ArrayRef>>461     pub fn unwrap_array(&self, store: impl AsContext) -> Result<Rooted<ArrayRef>> {
462         self._unwrap_array(store.as_context().0)
463     }
464 
_unwrap_array(&self, store: &StoreOpaque) -> Result<Rooted<ArrayRef>>465     pub(crate) fn _unwrap_array(&self, store: &StoreOpaque) -> Result<Rooted<ArrayRef>> {
466         Ok(self
467             ._as_array(store)?
468             .expect("EqRef::unwrap_array on non-arrayref"))
469     }
470 }
471 
472 unsafe impl WasmTy for Rooted<EqRef> {
473     #[inline]
valtype() -> ValType474     fn valtype() -> ValType {
475         ValType::Ref(RefType::new(false, HeapType::Eq))
476     }
477 
478     #[inline]
compatible_with_store(&self, store: &StoreOpaque) -> bool479     fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
480         self.comes_from_same_store(store)
481     }
482 
483     #[inline]
dynamic_concrete_type_check( &self, store: &StoreOpaque, _nullable: bool, ty: &HeapType, ) -> Result<()>484     fn dynamic_concrete_type_check(
485         &self,
486         store: &StoreOpaque,
487         _nullable: bool,
488         ty: &HeapType,
489     ) -> Result<()> {
490         self.ensure_matches_ty(store, ty)
491     }
492 
store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()>493     fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
494         self.wasm_ty_store(store, ptr, ValRaw::anyref)
495     }
496 
load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self497     unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
498         Self::wasm_ty_load(store, ptr.get_anyref(), EqRef::from_cloned_gc_ref)
499     }
500 }
501 
502 unsafe impl WasmTy for Option<Rooted<EqRef>> {
503     #[inline]
valtype() -> ValType504     fn valtype() -> ValType {
505         ValType::EQREF
506     }
507 
508     #[inline]
compatible_with_store(&self, store: &StoreOpaque) -> bool509     fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
510         self.map_or(true, |x| x.comes_from_same_store(store))
511     }
512 
513     #[inline]
dynamic_concrete_type_check( &self, store: &StoreOpaque, nullable: bool, ty: &HeapType, ) -> Result<()>514     fn dynamic_concrete_type_check(
515         &self,
516         store: &StoreOpaque,
517         nullable: bool,
518         ty: &HeapType,
519     ) -> Result<()> {
520         match self {
521             Some(s) => Rooted::<EqRef>::dynamic_concrete_type_check(s, store, nullable, ty),
522             None => {
523                 ensure!(
524                     nullable,
525                     "expected a non-null reference, but found a null reference"
526                 );
527                 Ok(())
528             }
529         }
530     }
531 
532     #[inline]
is_vmgcref_and_points_to_object(&self) -> bool533     fn is_vmgcref_and_points_to_object(&self) -> bool {
534         self.is_some()
535     }
536 
store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()>537     fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
538         <Rooted<EqRef>>::wasm_ty_option_store(self, store, ptr, ValRaw::anyref)
539     }
540 
load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self541     unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
542         <Rooted<EqRef>>::wasm_ty_option_load(store, ptr.get_anyref(), EqRef::from_cloned_gc_ref)
543     }
544 }
545 
546 unsafe impl WasmTy for OwnedRooted<EqRef> {
547     #[inline]
valtype() -> ValType548     fn valtype() -> ValType {
549         ValType::Ref(RefType::new(false, HeapType::Eq))
550     }
551 
552     #[inline]
compatible_with_store(&self, store: &StoreOpaque) -> bool553     fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
554         self.comes_from_same_store(store)
555     }
556 
557     #[inline]
dynamic_concrete_type_check( &self, store: &StoreOpaque, _: bool, ty: &HeapType, ) -> Result<()>558     fn dynamic_concrete_type_check(
559         &self,
560         store: &StoreOpaque,
561         _: bool,
562         ty: &HeapType,
563     ) -> Result<()> {
564         self.ensure_matches_ty(store, ty)
565     }
566 
store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()>567     fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
568         self.wasm_ty_store(store, ptr, ValRaw::anyref)
569     }
570 
load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self571     unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
572         Self::wasm_ty_load(store, ptr.get_anyref(), EqRef::from_cloned_gc_ref)
573     }
574 }
575 
576 unsafe impl WasmTy for Option<OwnedRooted<EqRef>> {
577     #[inline]
valtype() -> ValType578     fn valtype() -> ValType {
579         ValType::EQREF
580     }
581 
582     #[inline]
compatible_with_store(&self, store: &StoreOpaque) -> bool583     fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
584         self.as_ref()
585             .map_or(true, |x| x.comes_from_same_store(store))
586     }
587 
588     #[inline]
dynamic_concrete_type_check( &self, store: &StoreOpaque, nullable: bool, ty: &HeapType, ) -> Result<()>589     fn dynamic_concrete_type_check(
590         &self,
591         store: &StoreOpaque,
592         nullable: bool,
593         ty: &HeapType,
594     ) -> Result<()> {
595         match self {
596             Some(s) => OwnedRooted::<EqRef>::dynamic_concrete_type_check(s, store, nullable, ty),
597             None => {
598                 ensure!(
599                     nullable,
600                     "expected a non-null reference, but found a null reference"
601                 );
602                 Ok(())
603             }
604         }
605     }
606 
607     #[inline]
is_vmgcref_and_points_to_object(&self) -> bool608     fn is_vmgcref_and_points_to_object(&self) -> bool {
609         self.is_some()
610     }
611 
store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()>612     fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
613         <OwnedRooted<EqRef>>::wasm_ty_option_store(self, store, ptr, ValRaw::anyref)
614     }
615 
load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self616     unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
617         <OwnedRooted<EqRef>>::wasm_ty_option_load(
618             store,
619             ptr.get_anyref(),
620             EqRef::from_cloned_gc_ref,
621         )
622     }
623 }
624