wasmtime/runtime/gc/enabled/anyref.rs
1//! Implementation of `anyref` in Wasmtime.
2
3use super::ExternRef;
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, bail_bug,
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 .kind(&gc_ref)
301 .unwrap()
302 .matches(VMGcKind::AnyRef)
303 || store
304 .unwrap_gc_store()
305 .kind(&gc_ref)
306 .unwrap()
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 self.inner.expose_gc_ref_to_wasm(store).map(|r| r.get())
336 }
337
338 /// Get the type of this reference.
339 ///
340 /// # Errors
341 ///
342 /// Return an error if this reference has been unrooted.
343 ///
344 /// # Panics
345 ///
346 /// Panics if this reference is associated with a different store.
347 pub fn ty(&self, store: impl AsContext) -> Result<HeapType> {
348 self._ty(store.as_context().0)
349 }
350
351 pub(crate) fn _ty(&self, store: &StoreOpaque) -> Result<HeapType> {
352 let gc_ref = self.inner.try_gc_ref(store)?;
353 if gc_ref.is_i31() {
354 return Ok(HeapType::I31);
355 }
356
357 let header = store.require_gc_store()?.header(gc_ref)?;
358 let kind = match header.kind() {
359 Some(kind) => kind,
360 None => bail_bug!("invalid `VMGcKind`"),
361 };
362
363 if kind.matches(VMGcKind::ExternRef) {
364 return Ok(HeapType::Any);
365 }
366
367 debug_assert!(kind.matches(VMGcKind::AnyRef));
368 debug_assert!(kind.matches(VMGcKind::EqRef));
369 let ty = match header.ty() {
370 Some(ty) => ty,
371 None => bail_bug!("ty should be present"),
372 };
373
374 if kind.matches(VMGcKind::StructRef) {
375 return match StructType::from_shared_type_index(store.engine(), ty) {
376 Some(ty) => Ok(HeapType::ConcreteStruct(ty)),
377 None => bail_bug!("invalid struct type index"),
378 };
379 }
380
381 if kind.matches(VMGcKind::ArrayRef) {
382 return match ArrayType::from_shared_type_index(store.engine(), ty) {
383 Some(ty) => Ok(HeapType::ConcreteArray(ty)),
384 None => bail_bug!("invalid array type index"),
385 };
386 }
387
388 bail_bug!("no other kinds of `anyref`s")
389 }
390
391 /// Does this `anyref` match the given type?
392 ///
393 /// That is, is this object's type a subtype of the given type?
394 ///
395 /// # Errors
396 ///
397 /// Return an error if this reference has been unrooted.
398 ///
399 /// # Panics
400 ///
401 /// Panics if this reference is associated with a different store.
402 pub fn matches_ty(&self, store: impl AsContext, ty: &HeapType) -> Result<bool> {
403 self._matches_ty(store.as_context().0, ty)
404 }
405
406 pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &HeapType) -> Result<bool> {
407 assert!(self.comes_from_same_store(store));
408 Ok(self._ty(store)?.matches(ty))
409 }
410
411 pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &HeapType) -> Result<()> {
412 if !self.comes_from_same_store(store) {
413 bail!("function used with wrong store");
414 }
415 if self._matches_ty(store, ty)? {
416 Ok(())
417 } else {
418 let actual_ty = self._ty(store)?;
419 bail!("type mismatch: expected `(ref {ty})`, found `(ref {actual_ty})`")
420 }
421 }
422
423 /// Is this `anyref` an `eqref`?
424 ///
425 /// # Errors
426 ///
427 /// Return an error if this reference has been unrooted.
428 ///
429 /// # Panics
430 ///
431 /// Panics if this reference is associated with a different store.
432 pub fn is_eqref(&self, store: impl AsContext) -> Result<bool> {
433 self._is_eqref(store.as_context().0)
434 }
435
436 pub(crate) fn _is_eqref(&self, store: &StoreOpaque) -> Result<bool> {
437 assert!(self.comes_from_same_store(store));
438 let gc_ref = self.inner.try_gc_ref(store)?;
439 Ok(gc_ref.is_i31()
440 || store
441 .require_gc_store()?
442 .kind(gc_ref)?
443 .matches(VMGcKind::EqRef))
444 }
445
446 /// Downcast this `anyref` to an `eqref`.
447 ///
448 /// If this `anyref` is an `eqref`, then `Some(_)` is returned.
449 ///
450 /// If this `anyref` is not an `eqref`, then `None` is returned.
451 ///
452 /// # Errors
453 ///
454 /// Return an error if this reference has been unrooted.
455 ///
456 /// # Panics
457 ///
458 /// Panics if this reference is associated with a different store.
459 pub fn as_eqref(&self, mut store: impl AsContextMut) -> Result<Option<Rooted<EqRef>>> {
460 self._as_eqref(store.as_context_mut().0)
461 }
462
463 pub(crate) fn _as_eqref(&self, store: &mut StoreOpaque) -> Result<Option<Rooted<EqRef>>> {
464 if self._is_eqref(store)? {
465 let gc_ref = self.inner.try_gc_ref(store)?.unchecked_copy();
466 let gc_ref = store.clone_gc_ref(&gc_ref);
467 let mut store = AutoAssertNoGc::new(store);
468 Ok(Some(Rooted::new(&mut store, gc_ref)))
469 } else {
470 Ok(None)
471 }
472 }
473
474 /// Downcast this `anyref` to an `eqref`, panicking if this `anyref` is not
475 /// an `eqref`.
476 ///
477 /// # Errors
478 ///
479 /// Return an error if this reference has been unrooted.
480 ///
481 /// # Panics
482 ///
483 /// Panics if this reference is associated with a different store, or if
484 /// this `anyref` is not an `eqref`.
485 pub fn unwrap_eqref(&self, mut store: impl AsContextMut) -> Result<Rooted<EqRef>> {
486 self._unwrap_eqref(store.as_context_mut().0)
487 }
488
489 pub(crate) fn _unwrap_eqref(&self, store: &mut StoreOpaque) -> Result<Rooted<EqRef>> {
490 Ok(self
491 ._as_eqref(store)?
492 .expect("AnyRef::unwrap_eqref on non-eqref"))
493 }
494
495 /// Is this `anyref` an `i31`?
496 ///
497 /// # Errors
498 ///
499 /// Return an error if this reference has been unrooted.
500 ///
501 /// # Panics
502 ///
503 /// Panics if this reference is associated with a different store.
504 pub fn is_i31(&self, store: impl AsContext) -> Result<bool> {
505 self._is_i31(store.as_context().0)
506 }
507
508 pub(crate) fn _is_i31(&self, store: &StoreOpaque) -> Result<bool> {
509 assert!(self.comes_from_same_store(store));
510 let gc_ref = self.inner.try_gc_ref(store)?;
511 Ok(gc_ref.is_i31())
512 }
513
514 /// Downcast this `anyref` to an `i31`.
515 ///
516 /// If this `anyref` is an `i31`, then `Some(_)` is returned.
517 ///
518 /// If this `anyref` is not an `i31`, then `None` is returned.
519 ///
520 /// # Errors
521 ///
522 /// Return an error if this reference has been unrooted.
523 ///
524 /// # Panics
525 ///
526 /// Panics if this reference is associated with a different store.
527 pub fn as_i31(&self, store: impl AsContext) -> Result<Option<I31>> {
528 self._as_i31(store.as_context().0)
529 }
530
531 pub(crate) fn _as_i31(&self, store: &StoreOpaque) -> Result<Option<I31>> {
532 assert!(self.comes_from_same_store(store));
533 let gc_ref = self.inner.try_gc_ref(store)?;
534 Ok(gc_ref.as_i31().map(Into::into))
535 }
536
537 /// Downcast this `anyref` to an `i31`, panicking if this `anyref` is not an
538 /// `i31`.
539 ///
540 /// # Errors
541 ///
542 /// Return an error if this reference has been unrooted.
543 ///
544 /// # Panics
545 ///
546 /// Panics if this reference is associated with a different store, or if
547 /// this `anyref` is not an `i31`.
548 pub fn unwrap_i31(&self, store: impl AsContext) -> Result<I31> {
549 Ok(self.as_i31(store)?.expect("AnyRef::unwrap_i31 on non-i31"))
550 }
551
552 /// Is this `anyref` a `structref`?
553 ///
554 /// # Errors
555 ///
556 /// Return an error if this reference has been unrooted.
557 ///
558 /// # Panics
559 ///
560 /// Panics if this reference is associated with a different store.
561 pub fn is_struct(&self, store: impl AsContext) -> Result<bool> {
562 self._is_struct(store.as_context().0)
563 }
564
565 pub(crate) fn _is_struct(&self, store: &StoreOpaque) -> Result<bool> {
566 let gc_ref = self.inner.try_gc_ref(store)?;
567 Ok(!gc_ref.is_i31()
568 && store
569 .require_gc_store()?
570 .kind(gc_ref)?
571 .matches(VMGcKind::StructRef))
572 }
573
574 /// Downcast this `anyref` to a `structref`.
575 ///
576 /// If this `anyref` is a `structref`, then `Some(_)` is returned.
577 ///
578 /// If this `anyref` is not a `structref`, then `None` is returned.
579 ///
580 /// # Errors
581 ///
582 /// Return an error if this reference has been unrooted.
583 ///
584 /// # Panics
585 ///
586 /// Panics if this reference is associated with a different store.
587 pub fn as_struct(&self, store: impl AsContext) -> Result<Option<Rooted<StructRef>>> {
588 self._as_struct(store.as_context().0)
589 }
590
591 pub(crate) fn _as_struct(&self, store: &StoreOpaque) -> Result<Option<Rooted<StructRef>>> {
592 if self._is_struct(store)? {
593 Ok(Some(Rooted::from_gc_root_index(self.inner)))
594 } else {
595 Ok(None)
596 }
597 }
598
599 /// Downcast this `anyref` to a `structref`, panicking if this `anyref` is
600 /// not a `structref`.
601 ///
602 /// # Errors
603 ///
604 /// Return an error if this reference has been unrooted.
605 ///
606 /// # Panics
607 ///
608 /// Panics if this reference is associated with a different store, or if
609 /// this `anyref` is not a `struct`.
610 pub fn unwrap_struct(&self, store: impl AsContext) -> Result<Rooted<StructRef>> {
611 self._unwrap_struct(store.as_context().0)
612 }
613
614 pub(crate) fn _unwrap_struct(&self, store: &StoreOpaque) -> Result<Rooted<StructRef>> {
615 Ok(self
616 ._as_struct(store)?
617 .expect("AnyRef::unwrap_struct on non-structref"))
618 }
619
620 /// Is this `anyref` an `arrayref`?
621 ///
622 /// # Errors
623 ///
624 /// Return an error if this reference has been unrooted.
625 ///
626 /// # Panics
627 ///
628 /// Panics if this reference is associated with a different store.
629 pub fn is_array(&self, store: impl AsContext) -> Result<bool> {
630 self._is_array(store.as_context().0)
631 }
632
633 pub(crate) fn _is_array(&self, store: &StoreOpaque) -> Result<bool> {
634 let gc_ref = self.inner.try_gc_ref(store)?;
635 Ok(!gc_ref.is_i31()
636 && store
637 .require_gc_store()?
638 .kind(gc_ref)?
639 .matches(VMGcKind::ArrayRef))
640 }
641
642 /// Downcast this `anyref` to an `arrayref`.
643 ///
644 /// If this `anyref` is an `arrayref`, then `Some(_)` is returned.
645 ///
646 /// If this `anyref` is not an `arrayref`, then `None` is returned.
647 ///
648 /// # Errors
649 ///
650 /// Return an error if this reference has been unrooted.
651 ///
652 /// # Panics
653 ///
654 /// Panics if this reference is associated with a different store.
655 pub fn as_array(&self, store: impl AsContext) -> Result<Option<Rooted<ArrayRef>>> {
656 self._as_array(store.as_context().0)
657 }
658
659 pub(crate) fn _as_array(&self, store: &StoreOpaque) -> Result<Option<Rooted<ArrayRef>>> {
660 if self._is_array(store)? {
661 Ok(Some(Rooted::from_gc_root_index(self.inner)))
662 } else {
663 Ok(None)
664 }
665 }
666
667 /// Downcast this `anyref` to an `arrayref`, panicking if this `anyref` is
668 /// not an `arrayref`.
669 ///
670 /// # Errors
671 ///
672 /// Return an error if this reference has been unrooted.
673 ///
674 /// # Panics
675 ///
676 /// Panics if this reference is associated with a different store, or if
677 /// this `anyref` is not an `array`.
678 pub fn unwrap_array(&self, store: impl AsContext) -> Result<Rooted<ArrayRef>> {
679 self._unwrap_array(store.as_context().0)
680 }
681
682 pub(crate) fn _unwrap_array(&self, store: &StoreOpaque) -> Result<Rooted<ArrayRef>> {
683 Ok(self
684 ._as_array(store)?
685 .expect("AnyRef::unwrap_array on non-arrayref"))
686 }
687}
688
689unsafe impl WasmTy for Rooted<AnyRef> {
690 #[inline]
691 fn valtype() -> ValType {
692 ValType::Ref(RefType::new(false, HeapType::Any))
693 }
694
695 #[inline]
696 fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
697 self.comes_from_same_store(store)
698 }
699
700 #[inline]
701 fn dynamic_concrete_type_check(
702 &self,
703 store: &StoreOpaque,
704 _nullable: bool,
705 ty: &HeapType,
706 ) -> Result<()> {
707 self.ensure_matches_ty(store, ty)
708 }
709
710 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
711 self.wasm_ty_store(store, ptr, ValRaw::anyref)
712 }
713
714 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
715 Self::wasm_ty_load(store, ptr.get_anyref(), AnyRef::from_cloned_gc_ref)
716 }
717}
718
719unsafe impl WasmTy for Option<Rooted<AnyRef>> {
720 #[inline]
721 fn valtype() -> ValType {
722 ValType::ANYREF
723 }
724
725 #[inline]
726 fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
727 self.map_or(true, |x| x.comes_from_same_store(store))
728 }
729
730 #[inline]
731 fn dynamic_concrete_type_check(
732 &self,
733 store: &StoreOpaque,
734 nullable: bool,
735 ty: &HeapType,
736 ) -> Result<()> {
737 match self {
738 Some(a) => a.ensure_matches_ty(store, ty),
739 None => {
740 ensure!(
741 nullable,
742 "expected a non-null reference, but found a null reference"
743 );
744 Ok(())
745 }
746 }
747 }
748
749 #[inline]
750 fn is_vmgcref_and_points_to_object(&self) -> bool {
751 self.is_some()
752 }
753
754 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
755 <Rooted<AnyRef>>::wasm_ty_option_store(self, store, ptr, ValRaw::anyref)
756 }
757
758 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
759 <Rooted<AnyRef>>::wasm_ty_option_load(store, ptr.get_anyref(), AnyRef::from_cloned_gc_ref)
760 }
761}
762
763unsafe impl WasmTy for OwnedRooted<AnyRef> {
764 #[inline]
765 fn valtype() -> ValType {
766 ValType::Ref(RefType::new(false, HeapType::Any))
767 }
768
769 #[inline]
770 fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
771 self.comes_from_same_store(store)
772 }
773
774 #[inline]
775 fn dynamic_concrete_type_check(
776 &self,
777 store: &StoreOpaque,
778 _nullable: bool,
779 ty: &HeapType,
780 ) -> Result<()> {
781 self.ensure_matches_ty(store, ty)
782 }
783
784 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
785 self.wasm_ty_store(store, ptr, ValRaw::anyref)
786 }
787
788 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
789 Self::wasm_ty_load(store, ptr.get_anyref(), AnyRef::from_cloned_gc_ref)
790 }
791}
792
793unsafe impl WasmTy for Option<OwnedRooted<AnyRef>> {
794 #[inline]
795 fn valtype() -> ValType {
796 ValType::ANYREF
797 }
798
799 #[inline]
800 fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
801 self.as_ref()
802 .map_or(true, |x| x.comes_from_same_store(store))
803 }
804
805 #[inline]
806 fn dynamic_concrete_type_check(
807 &self,
808 store: &StoreOpaque,
809 nullable: bool,
810 ty: &HeapType,
811 ) -> Result<()> {
812 match self {
813 Some(a) => a.ensure_matches_ty(store, ty),
814 None => {
815 ensure!(
816 nullable,
817 "expected a non-null reference, but found a null reference"
818 );
819 Ok(())
820 }
821 }
822 }
823
824 #[inline]
825 fn is_vmgcref_and_points_to_object(&self) -> bool {
826 self.is_some()
827 }
828
829 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
830 <OwnedRooted<AnyRef>>::wasm_ty_option_store(self, store, ptr, ValRaw::anyref)
831 }
832
833 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
834 <OwnedRooted<AnyRef>>::wasm_ty_option_load(
835 store,
836 ptr.get_anyref(),
837 AnyRef::from_cloned_gc_ref,
838 )
839 }
840}