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 OwnedRooted, 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 `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)]
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<OwnedRooted<EqRef>> for OwnedRooted<AnyRef> {
107 #[inline]
108 fn from(e: OwnedRooted<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<OwnedRooted<StructRef>> for OwnedRooted<AnyRef> {
121 #[inline]
122 fn from(s: OwnedRooted<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<OwnedRooted<ArrayRef>> for OwnedRooted<AnyRef> {
135 #[inline]
136 fn from(s: OwnedRooted<ArrayRef>) -> Self {
137 s.to_anyref()
138 }
139}
140
141unsafe 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
158impl 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, mut store: impl AsContextMut) -> Result<Option<Rooted<EqRef>>> {
457 self._as_eqref(store.as_context_mut().0)
458 }
459
460 pub(crate) fn _as_eqref(&self, store: &mut StoreOpaque) -> Result<Option<Rooted<EqRef>>> {
461 if self._is_eqref(store)? {
462 let gc_ref = self.inner.try_gc_ref(store)?.unchecked_copy();
463 let gc_ref = store.clone_gc_ref(&gc_ref);
464 let mut store = AutoAssertNoGc::new(store);
465 Ok(Some(Rooted::new(&mut store, gc_ref)))
466 } else {
467 Ok(None)
468 }
469 }
470
471 /// Downcast this `anyref` to an `eqref`, panicking if this `anyref` is not
472 /// an `eqref`.
473 ///
474 /// # Errors
475 ///
476 /// Return an error if this reference has been unrooted.
477 ///
478 /// # Panics
479 ///
480 /// Panics if this reference is associated with a different store, or if
481 /// this `anyref` is not an `eqref`.
482 pub fn unwrap_eqref(&self, mut store: impl AsContextMut) -> Result<Rooted<EqRef>> {
483 self._unwrap_eqref(store.as_context_mut().0)
484 }
485
486 pub(crate) fn _unwrap_eqref(&self, store: &mut StoreOpaque) -> Result<Rooted<EqRef>> {
487 Ok(self
488 ._as_eqref(store)?
489 .expect("AnyRef::unwrap_eqref on non-eqref"))
490 }
491
492 /// Is this `anyref` an `i31`?
493 ///
494 /// # Errors
495 ///
496 /// Return an error if this reference has been unrooted.
497 ///
498 /// # Panics
499 ///
500 /// Panics if this reference is associated with a different store.
501 pub fn is_i31(&self, store: impl AsContext) -> Result<bool> {
502 self._is_i31(store.as_context().0)
503 }
504
505 pub(crate) fn _is_i31(&self, store: &StoreOpaque) -> Result<bool> {
506 assert!(self.comes_from_same_store(store));
507 let gc_ref = self.inner.try_gc_ref(store)?;
508 Ok(gc_ref.is_i31())
509 }
510
511 /// Downcast this `anyref` to an `i31`.
512 ///
513 /// If this `anyref` is an `i31`, then `Some(_)` is returned.
514 ///
515 /// If this `anyref` is not an `i31`, then `None` is returned.
516 ///
517 /// # Errors
518 ///
519 /// Return an error if this reference has been unrooted.
520 ///
521 /// # Panics
522 ///
523 /// Panics if this reference is associated with a different store.
524 pub fn as_i31(&self, store: impl AsContext) -> Result<Option<I31>> {
525 self._as_i31(store.as_context().0)
526 }
527
528 pub(crate) fn _as_i31(&self, store: &StoreOpaque) -> Result<Option<I31>> {
529 assert!(self.comes_from_same_store(store));
530 let gc_ref = self.inner.try_gc_ref(store)?;
531 Ok(gc_ref.as_i31().map(Into::into))
532 }
533
534 /// Downcast this `anyref` to an `i31`, panicking if this `anyref` is not an
535 /// `i31`.
536 ///
537 /// # Errors
538 ///
539 /// Return an error if this reference has been unrooted.
540 ///
541 /// # Panics
542 ///
543 /// Panics if this reference is associated with a different store, or if
544 /// this `anyref` is not an `i31`.
545 pub fn unwrap_i31(&self, store: impl AsContext) -> Result<I31> {
546 Ok(self.as_i31(store)?.expect("AnyRef::unwrap_i31 on non-i31"))
547 }
548
549 /// Is this `anyref` a `structref`?
550 ///
551 /// # Errors
552 ///
553 /// Return an error if this reference has been unrooted.
554 ///
555 /// # Panics
556 ///
557 /// Panics if this reference is associated with a different store.
558 pub fn is_struct(&self, store: impl AsContext) -> Result<bool> {
559 self._is_struct(store.as_context().0)
560 }
561
562 pub(crate) fn _is_struct(&self, store: &StoreOpaque) -> Result<bool> {
563 let gc_ref = self.inner.try_gc_ref(store)?;
564 Ok(!gc_ref.is_i31()
565 && store
566 .require_gc_store()?
567 .kind(gc_ref)
568 .matches(VMGcKind::StructRef))
569 }
570
571 /// Downcast this `anyref` to a `structref`.
572 ///
573 /// If this `anyref` is a `structref`, then `Some(_)` is returned.
574 ///
575 /// If this `anyref` is not a `structref`, then `None` is returned.
576 ///
577 /// # Errors
578 ///
579 /// Return an error if this reference has been unrooted.
580 ///
581 /// # Panics
582 ///
583 /// Panics if this reference is associated with a different store.
584 pub fn as_struct(&self, store: impl AsContext) -> Result<Option<Rooted<StructRef>>> {
585 self._as_struct(store.as_context().0)
586 }
587
588 pub(crate) fn _as_struct(&self, store: &StoreOpaque) -> Result<Option<Rooted<StructRef>>> {
589 if self._is_struct(store)? {
590 Ok(Some(Rooted::from_gc_root_index(self.inner)))
591 } else {
592 Ok(None)
593 }
594 }
595
596 /// Downcast this `anyref` to a `structref`, panicking if this `anyref` is
597 /// not a `structref`.
598 ///
599 /// # Errors
600 ///
601 /// Return an error if this reference has been unrooted.
602 ///
603 /// # Panics
604 ///
605 /// Panics if this reference is associated with a different store, or if
606 /// this `anyref` is not a `struct`.
607 pub fn unwrap_struct(&self, store: impl AsContext) -> Result<Rooted<StructRef>> {
608 self._unwrap_struct(store.as_context().0)
609 }
610
611 pub(crate) fn _unwrap_struct(&self, store: &StoreOpaque) -> Result<Rooted<StructRef>> {
612 Ok(self
613 ._as_struct(store)?
614 .expect("AnyRef::unwrap_struct on non-structref"))
615 }
616
617 /// Is this `anyref` an `arrayref`?
618 ///
619 /// # Errors
620 ///
621 /// Return an error if this reference has been unrooted.
622 ///
623 /// # Panics
624 ///
625 /// Panics if this reference is associated with a different store.
626 pub fn is_array(&self, store: impl AsContext) -> Result<bool> {
627 self._is_array(store.as_context().0)
628 }
629
630 pub(crate) fn _is_array(&self, store: &StoreOpaque) -> Result<bool> {
631 let gc_ref = self.inner.try_gc_ref(store)?;
632 Ok(!gc_ref.is_i31()
633 && store
634 .require_gc_store()?
635 .kind(gc_ref)
636 .matches(VMGcKind::ArrayRef))
637 }
638
639 /// Downcast this `anyref` to an `arrayref`.
640 ///
641 /// If this `anyref` is an `arrayref`, then `Some(_)` is returned.
642 ///
643 /// If this `anyref` is not an `arrayref`, then `None` is returned.
644 ///
645 /// # Errors
646 ///
647 /// Return an error if this reference has been unrooted.
648 ///
649 /// # Panics
650 ///
651 /// Panics if this reference is associated with a different store.
652 pub fn as_array(&self, store: impl AsContext) -> Result<Option<Rooted<ArrayRef>>> {
653 self._as_array(store.as_context().0)
654 }
655
656 pub(crate) fn _as_array(&self, store: &StoreOpaque) -> Result<Option<Rooted<ArrayRef>>> {
657 if self._is_array(store)? {
658 Ok(Some(Rooted::from_gc_root_index(self.inner)))
659 } else {
660 Ok(None)
661 }
662 }
663
664 /// Downcast this `anyref` to an `arrayref`, panicking if this `anyref` is
665 /// not an `arrayref`.
666 ///
667 /// # Errors
668 ///
669 /// Return an error if this reference has been unrooted.
670 ///
671 /// # Panics
672 ///
673 /// Panics if this reference is associated with a different store, or if
674 /// this `anyref` is not an `array`.
675 pub fn unwrap_array(&self, store: impl AsContext) -> Result<Rooted<ArrayRef>> {
676 self._unwrap_array(store.as_context().0)
677 }
678
679 pub(crate) fn _unwrap_array(&self, store: &StoreOpaque) -> Result<Rooted<ArrayRef>> {
680 Ok(self
681 ._as_array(store)?
682 .expect("AnyRef::unwrap_array on non-arrayref"))
683 }
684}
685
686unsafe impl WasmTy for Rooted<AnyRef> {
687 #[inline]
688 fn valtype() -> ValType {
689 ValType::Ref(RefType::new(false, HeapType::Any))
690 }
691
692 #[inline]
693 fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
694 self.comes_from_same_store(store)
695 }
696
697 #[inline]
698 fn dynamic_concrete_type_check(
699 &self,
700 store: &StoreOpaque,
701 _nullable: bool,
702 ty: &HeapType,
703 ) -> Result<()> {
704 self.ensure_matches_ty(store, ty)
705 }
706
707 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
708 self.wasm_ty_store(store, ptr, ValRaw::anyref)
709 }
710
711 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
712 Self::wasm_ty_load(store, ptr.get_anyref(), AnyRef::from_cloned_gc_ref)
713 }
714}
715
716unsafe impl WasmTy for Option<Rooted<AnyRef>> {
717 #[inline]
718 fn valtype() -> ValType {
719 ValType::ANYREF
720 }
721
722 #[inline]
723 fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
724 self.map_or(true, |x| x.comes_from_same_store(store))
725 }
726
727 #[inline]
728 fn dynamic_concrete_type_check(
729 &self,
730 store: &StoreOpaque,
731 nullable: bool,
732 ty: &HeapType,
733 ) -> Result<()> {
734 match self {
735 Some(a) => a.ensure_matches_ty(store, ty),
736 None => {
737 ensure!(
738 nullable,
739 "expected a non-null reference, but found a null reference"
740 );
741 Ok(())
742 }
743 }
744 }
745
746 #[inline]
747 fn is_vmgcref_and_points_to_object(&self) -> bool {
748 self.is_some()
749 }
750
751 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
752 <Rooted<AnyRef>>::wasm_ty_option_store(self, store, ptr, ValRaw::anyref)
753 }
754
755 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
756 <Rooted<AnyRef>>::wasm_ty_option_load(store, ptr.get_anyref(), AnyRef::from_cloned_gc_ref)
757 }
758}
759
760unsafe impl WasmTy for OwnedRooted<AnyRef> {
761 #[inline]
762 fn valtype() -> ValType {
763 ValType::Ref(RefType::new(false, HeapType::Any))
764 }
765
766 #[inline]
767 fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
768 self.comes_from_same_store(store)
769 }
770
771 #[inline]
772 fn dynamic_concrete_type_check(
773 &self,
774 store: &StoreOpaque,
775 _nullable: bool,
776 ty: &HeapType,
777 ) -> Result<()> {
778 self.ensure_matches_ty(store, ty)
779 }
780
781 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
782 self.wasm_ty_store(store, ptr, ValRaw::anyref)
783 }
784
785 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
786 Self::wasm_ty_load(store, ptr.get_anyref(), AnyRef::from_cloned_gc_ref)
787 }
788}
789
790unsafe impl WasmTy for Option<OwnedRooted<AnyRef>> {
791 #[inline]
792 fn valtype() -> ValType {
793 ValType::ANYREF
794 }
795
796 #[inline]
797 fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
798 self.as_ref()
799 .map_or(true, |x| x.comes_from_same_store(store))
800 }
801
802 #[inline]
803 fn dynamic_concrete_type_check(
804 &self,
805 store: &StoreOpaque,
806 nullable: bool,
807 ty: &HeapType,
808 ) -> Result<()> {
809 match self {
810 Some(a) => a.ensure_matches_ty(store, ty),
811 None => {
812 ensure!(
813 nullable,
814 "expected a non-null reference, but found a null reference"
815 );
816 Ok(())
817 }
818 }
819 }
820
821 #[inline]
822 fn is_vmgcref_and_points_to_object(&self) -> bool {
823 self.is_some()
824 }
825
826 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
827 <OwnedRooted<AnyRef>>::wasm_ty_option_store(self, store, ptr, ValRaw::anyref)
828 }
829
830 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
831 <OwnedRooted<AnyRef>>::wasm_ty_option_load(
832 store,
833 ptr.get_anyref(),
834 AnyRef::from_cloned_gc_ref,
835 )
836 }
837}