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