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