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