1 //! Implementation of `anyref` in Wasmtime. 2 3 use super::{ExternRef, RootedGcRefImpl}; 4 use crate::prelude::*; 5 use crate::runtime::vm::VMGcRef; 6 use crate::{ 7 ArrayRef, ArrayType, AsContext, AsContextMut, EqRef, GcRefImpl, GcRootIndex, HeapType, I31, 8 OwnedRooted, RefType, Result, Rooted, StructRef, StructType, ValRaw, ValType, WasmTy, 9 store::{AutoAssertNoGc, StoreOpaque}, 10 }; 11 use core::mem; 12 use core::mem::MaybeUninit; 13 use 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)] 95 pub struct AnyRef { 96 pub(super) inner: GcRootIndex, 97 } 98 99 impl From<Rooted<EqRef>> for Rooted<AnyRef> { 100 #[inline] 101 fn from(e: Rooted<EqRef>) -> Self { 102 e.to_anyref() 103 } 104 } 105 106 impl From<OwnedRooted<EqRef>> for OwnedRooted<AnyRef> { 107 #[inline] 108 fn from(e: OwnedRooted<EqRef>) -> Self { 109 e.to_anyref() 110 } 111 } 112 113 impl From<Rooted<StructRef>> for Rooted<AnyRef> { 114 #[inline] 115 fn from(s: Rooted<StructRef>) -> Self { 116 s.to_anyref() 117 } 118 } 119 120 impl From<OwnedRooted<StructRef>> for OwnedRooted<AnyRef> { 121 #[inline] 122 fn from(s: OwnedRooted<StructRef>) -> Self { 123 s.to_anyref() 124 } 125 } 126 127 impl From<Rooted<ArrayRef>> for Rooted<AnyRef> { 128 #[inline] 129 fn from(s: Rooted<ArrayRef>) -> Self { 130 s.to_anyref() 131 } 132 } 133 134 impl From<OwnedRooted<ArrayRef>> for OwnedRooted<AnyRef> { 135 #[inline] 136 fn from(s: OwnedRooted<ArrayRef>) -> Self { 137 s.to_anyref() 138 } 139 } 140 141 unsafe 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 158 impl AnyRef { 159 /// Construct an `anyref` from an `i31`. 160 /// 161 /// # Example 162 /// 163 /// ``` 164 /// # use wasmtime::*; 165 /// # fn _foo() -> Result<()> { 166 /// let mut store = Store::<()>::default(); 167 /// 168 /// // Create an `i31`. 169 /// let i31 = I31::wrapping_u32(999); 170 /// 171 /// // Convert it into an `anyref`. 172 /// let anyref = AnyRef::from_i31(&mut store, i31); 173 /// # Ok(()) 174 /// # } 175 /// ``` 176 pub fn from_i31(mut store: impl AsContextMut, value: I31) -> Rooted<Self> { 177 let mut store = AutoAssertNoGc::new(store.as_context_mut().0); 178 Self::_from_i31(&mut store, value) 179 } 180 181 pub(crate) fn _from_i31(store: &mut AutoAssertNoGc<'_>, value: I31) -> Rooted<Self> { 182 let gc_ref = VMGcRef::from_i31(value.runtime_i31()); 183 Rooted::new(store, gc_ref) 184 } 185 186 /// Convert an `externref` into an `anyref`. 187 /// 188 /// This is equivalent to the `any.convert_extern` instruction in Wasm. 189 /// 190 /// You can recover the underlying `externref` again via the 191 /// [`ExternRef::convert_any`] method or the `extern.convert_any` Wasm 192 /// instruction. 193 /// 194 /// Returns an error if the `externref` GC reference has been unrooted (eg 195 /// if you attempt to use a `Rooted<ExternRef>` after exiting the scope it 196 /// was rooted within). See the documentation for 197 /// [`Rooted<T>`][crate::Rooted] for more details. 198 /// 199 /// # Example 200 /// 201 /// ``` 202 /// use wasmtime::*; 203 /// # fn foo() -> Result<()> { 204 /// let engine = Engine::default(); 205 /// let mut store = Store::new(&engine, ()); 206 /// 207 /// // Create an `externref`. 208 /// let externref = ExternRef::new(&mut store, "hello")?; 209 /// 210 /// // Convert that `externref` into an `anyref`. 211 /// let anyref = AnyRef::convert_extern(&mut store, externref)?; 212 /// 213 /// // The converted value is an `anyref` but is not an `eqref`. 214 /// assert_eq!(anyref.matches_ty(&store, &HeapType::Any)?, true); 215 /// assert_eq!(anyref.matches_ty(&store, &HeapType::Eq)?, false); 216 /// 217 /// // We can convert it back to the original `externref` and get its 218 /// // associated host data again. 219 /// let externref = ExternRef::convert_any(&mut store, anyref)?; 220 /// let data = externref 221 /// .data(&store)? 222 /// .expect("externref should have host data") 223 /// .downcast_ref::<&str>() 224 /// .expect("host data should be a str"); 225 /// assert_eq!(*data, "hello"); 226 /// # Ok(()) } 227 /// # foo().unwrap(); 228 pub fn convert_extern( 229 mut store: impl AsContextMut, 230 externref: Rooted<ExternRef>, 231 ) -> Result<Rooted<Self>> { 232 let mut store = AutoAssertNoGc::new(store.as_context_mut().0); 233 Self::_convert_extern(&mut store, externref) 234 } 235 236 pub(crate) fn _convert_extern( 237 store: &mut AutoAssertNoGc<'_>, 238 externref: Rooted<ExternRef>, 239 ) -> Result<Rooted<Self>> { 240 let gc_ref = externref.try_clone_gc_ref(store)?; 241 Ok(Self::from_cloned_gc_ref(store, gc_ref)) 242 } 243 244 /// Creates a new strongly-owned [`AnyRef`] from the raw value provided. 245 /// 246 /// This is intended to be used in conjunction with [`Func::new_unchecked`], 247 /// [`Func::call_unchecked`], and [`ValRaw`] with its `anyref` field. 248 /// 249 /// This function assumes that `raw` is an `anyref` value which is currently 250 /// rooted within the [`Store`]. 251 /// 252 /// # Correctness 253 /// 254 /// This function is tricky to get right because `raw` not only must be a 255 /// valid `anyref` value produced prior by [`AnyRef::to_raw`] but it 256 /// must also be correctly rooted within the store. When arguments are 257 /// provided to a callback with [`Func::new_unchecked`], for example, or 258 /// returned via [`Func::call_unchecked`], if a GC is performed within the 259 /// store then floating `anyref` values are not rooted and will be GC'd, 260 /// meaning that this function will no longer be correct to call with the 261 /// values cleaned up. This function must be invoked *before* possible GC 262 /// operations can happen (such as calling Wasm). 263 /// 264 /// 265 /// When in doubt try to not use this. Instead use the Rust APIs of 266 /// [`TypedFunc`] and friends. Note though that this function is not 267 /// `unsafe` as any value can be passed in. Incorrect values can result in 268 /// runtime panics, however, so care must still be taken with this method. 269 /// 270 /// [`Func::call_unchecked`]: crate::Func::call_unchecked 271 /// [`Func::new_unchecked`]: crate::Func::new_unchecked 272 /// [`Store`]: crate::Store 273 /// [`TypedFunc`]: crate::TypedFunc 274 /// [`ValRaw`]: crate::ValRaw 275 pub fn from_raw(mut store: impl AsContextMut, raw: u32) -> Option<Rooted<Self>> { 276 let mut store = AutoAssertNoGc::new(store.as_context_mut().0); 277 Self::_from_raw(&mut store, raw) 278 } 279 280 // (Not actually memory unsafe since we have indexed GC heaps.) 281 pub(crate) fn _from_raw(store: &mut AutoAssertNoGc, raw: u32) -> Option<Rooted<Self>> { 282 let gc_ref = VMGcRef::from_raw_u32(raw)?; 283 let gc_ref = store.clone_gc_ref(&gc_ref); 284 Some(Self::from_cloned_gc_ref(store, gc_ref)) 285 } 286 287 /// Create a new `Rooted<AnyRef>` from the given GC reference. 288 /// 289 /// `gc_ref` should point to a valid `anyref` and should belong to the 290 /// store's GC heap. Failure to uphold these invariants is memory safe but 291 /// will lead to general incorrectness such as panics or wrong results. 292 pub(crate) fn from_cloned_gc_ref( 293 store: &mut AutoAssertNoGc<'_>, 294 gc_ref: VMGcRef, 295 ) -> Rooted<Self> { 296 debug_assert!( 297 gc_ref.is_i31() 298 || store 299 .unwrap_gc_store() 300 .header(&gc_ref) 301 .kind() 302 .matches(VMGcKind::AnyRef) 303 || store 304 .unwrap_gc_store() 305 .header(&gc_ref) 306 .kind() 307 .matches(VMGcKind::ExternRef) 308 ); 309 Rooted::new(store, gc_ref) 310 } 311 312 #[inline] 313 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool { 314 self.inner.comes_from_same_store(store) 315 } 316 317 /// Converts this [`AnyRef`] to a raw value suitable to store within a 318 /// [`ValRaw`]. 319 /// 320 /// Returns an error if this `anyref` has been unrooted. 321 /// 322 /// # Correctness 323 /// 324 /// Produces a raw value which is only valid to pass into a store if a GC 325 /// doesn't happen between when the value is produce and when it's passed 326 /// into the store. 327 /// 328 /// [`ValRaw`]: crate::ValRaw 329 pub fn to_raw(&self, mut store: impl AsContextMut) -> Result<u32> { 330 let mut store = AutoAssertNoGc::new(store.as_context_mut().0); 331 self._to_raw(&mut store) 332 } 333 334 pub(crate) fn _to_raw(&self, store: &mut AutoAssertNoGc<'_>) -> Result<u32> { 335 let gc_ref = self.inner.try_clone_gc_ref(store)?; 336 let raw = if gc_ref.is_i31() { 337 gc_ref.as_raw_non_zero_u32() 338 } else { 339 store.require_gc_store_mut()?.expose_gc_ref_to_wasm(gc_ref) 340 }; 341 Ok(raw.get()) 342 } 343 344 /// Get the type of this reference. 345 /// 346 /// # Errors 347 /// 348 /// Return an error if this reference has been unrooted. 349 /// 350 /// # Panics 351 /// 352 /// Panics if this reference is associated with a different store. 353 pub fn ty(&self, store: impl AsContext) -> Result<HeapType> { 354 self._ty(store.as_context().0) 355 } 356 357 pub(crate) fn _ty(&self, store: &StoreOpaque) -> Result<HeapType> { 358 let gc_ref = self.inner.try_gc_ref(store)?; 359 if gc_ref.is_i31() { 360 return Ok(HeapType::I31); 361 } 362 363 let header = store.require_gc_store()?.header(gc_ref); 364 365 if header.kind().matches(VMGcKind::ExternRef) { 366 return Ok(HeapType::Any); 367 } 368 369 debug_assert!(header.kind().matches(VMGcKind::AnyRef)); 370 debug_assert!(header.kind().matches(VMGcKind::EqRef)); 371 372 if header.kind().matches(VMGcKind::StructRef) { 373 return Ok(HeapType::ConcreteStruct( 374 StructType::from_shared_type_index(store.engine(), header.ty().unwrap()), 375 )); 376 } 377 378 if header.kind().matches(VMGcKind::ArrayRef) { 379 return Ok(HeapType::ConcreteArray(ArrayType::from_shared_type_index( 380 store.engine(), 381 header.ty().unwrap(), 382 ))); 383 } 384 385 unreachable!("no other kinds of `anyref`s") 386 } 387 388 /// Does this `anyref` match the given type? 389 /// 390 /// That is, is this object's type a subtype of the given type? 391 /// 392 /// # Errors 393 /// 394 /// Return an error if this reference has been unrooted. 395 /// 396 /// # Panics 397 /// 398 /// Panics if this reference is associated with a different store. 399 pub fn matches_ty(&self, store: impl AsContext, ty: &HeapType) -> Result<bool> { 400 self._matches_ty(store.as_context().0, ty) 401 } 402 403 pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &HeapType) -> Result<bool> { 404 assert!(self.comes_from_same_store(store)); 405 Ok(self._ty(store)?.matches(ty)) 406 } 407 408 pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &HeapType) -> Result<()> { 409 if !self.comes_from_same_store(store) { 410 bail!("function used with wrong store"); 411 } 412 if self._matches_ty(store, ty)? { 413 Ok(()) 414 } else { 415 let actual_ty = self._ty(store)?; 416 bail!("type mismatch: expected `(ref {ty})`, found `(ref {actual_ty})`") 417 } 418 } 419 420 /// Is this `anyref` an `eqref`? 421 /// 422 /// # Errors 423 /// 424 /// Return an error if this reference has been unrooted. 425 /// 426 /// # Panics 427 /// 428 /// Panics if this reference is associated with a different store. 429 pub fn is_eqref(&self, store: impl AsContext) -> Result<bool> { 430 self._is_eqref(store.as_context().0) 431 } 432 433 pub(crate) fn _is_eqref(&self, store: &StoreOpaque) -> Result<bool> { 434 assert!(self.comes_from_same_store(store)); 435 let gc_ref = self.inner.try_gc_ref(store)?; 436 Ok(gc_ref.is_i31() 437 || store 438 .require_gc_store()? 439 .kind(gc_ref) 440 .matches(VMGcKind::EqRef)) 441 } 442 443 /// Downcast this `anyref` to an `eqref`. 444 /// 445 /// If this `anyref` is an `eqref`, then `Some(_)` is returned. 446 /// 447 /// If this `anyref` is not an `eqref`, then `None` is returned. 448 /// 449 /// # Errors 450 /// 451 /// Return an error if this reference has been unrooted. 452 /// 453 /// # Panics 454 /// 455 /// Panics if this reference is associated with a different store. 456 pub fn as_eqref(&self, 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() 562 && store 563 .require_gc_store()? 564 .kind(gc_ref) 565 .matches(VMGcKind::StructRef)) 566 } 567 568 /// Downcast this `anyref` to a `structref`. 569 /// 570 /// If this `anyref` is a `structref`, then `Some(_)` is returned. 571 /// 572 /// If this `anyref` is not a `structref`, then `None` is returned. 573 /// 574 /// # Errors 575 /// 576 /// Return an error if this reference has been unrooted. 577 /// 578 /// # Panics 579 /// 580 /// Panics if this reference is associated with a different store. 581 pub fn as_struct(&self, store: impl AsContext) -> Result<Option<Rooted<StructRef>>> { 582 self._as_struct(store.as_context().0) 583 } 584 585 pub(crate) fn _as_struct(&self, store: &StoreOpaque) -> Result<Option<Rooted<StructRef>>> { 586 if self._is_struct(store)? { 587 Ok(Some(Rooted::from_gc_root_index(self.inner))) 588 } else { 589 Ok(None) 590 } 591 } 592 593 /// Downcast this `anyref` to a `structref`, panicking if this `anyref` is 594 /// not a `structref`. 595 /// 596 /// # Errors 597 /// 598 /// Return an error if this reference has been unrooted. 599 /// 600 /// # Panics 601 /// 602 /// Panics if this reference is associated with a different store, or if 603 /// this `anyref` is not a `struct`. 604 pub fn unwrap_struct(&self, store: impl AsContext) -> Result<Rooted<StructRef>> { 605 self._unwrap_struct(store.as_context().0) 606 } 607 608 pub(crate) fn _unwrap_struct(&self, store: &StoreOpaque) -> Result<Rooted<StructRef>> { 609 Ok(self 610 ._as_struct(store)? 611 .expect("AnyRef::unwrap_struct on non-structref")) 612 } 613 614 /// Is this `anyref` an `arrayref`? 615 /// 616 /// # Errors 617 /// 618 /// Return an error if this reference has been unrooted. 619 /// 620 /// # Panics 621 /// 622 /// Panics if this reference is associated with a different store. 623 pub fn is_array(&self, store: impl AsContext) -> Result<bool> { 624 self._is_array(store.as_context().0) 625 } 626 627 pub(crate) fn _is_array(&self, store: &StoreOpaque) -> Result<bool> { 628 let gc_ref = self.inner.try_gc_ref(store)?; 629 Ok(!gc_ref.is_i31() 630 && store 631 .require_gc_store()? 632 .kind(gc_ref) 633 .matches(VMGcKind::ArrayRef)) 634 } 635 636 /// Downcast this `anyref` to an `arrayref`. 637 /// 638 /// If this `anyref` is an `arrayref`, then `Some(_)` is returned. 639 /// 640 /// If this `anyref` is not an `arrayref`, then `None` is returned. 641 /// 642 /// # Errors 643 /// 644 /// Return an error if this reference has been unrooted. 645 /// 646 /// # Panics 647 /// 648 /// Panics if this reference is associated with a different store. 649 pub fn as_array(&self, store: impl AsContext) -> Result<Option<Rooted<ArrayRef>>> { 650 self._as_array(store.as_context().0) 651 } 652 653 pub(crate) fn _as_array(&self, store: &StoreOpaque) -> Result<Option<Rooted<ArrayRef>>> { 654 if self._is_array(store)? { 655 Ok(Some(Rooted::from_gc_root_index(self.inner))) 656 } else { 657 Ok(None) 658 } 659 } 660 661 /// Downcast this `anyref` to an `arrayref`, panicking if this `anyref` is 662 /// not an `arrayref`. 663 /// 664 /// # Errors 665 /// 666 /// Return an error if this reference has been unrooted. 667 /// 668 /// # Panics 669 /// 670 /// Panics if this reference is associated with a different store, or if 671 /// this `anyref` is not an `array`. 672 pub fn unwrap_array(&self, store: impl AsContext) -> Result<Rooted<ArrayRef>> { 673 self._unwrap_array(store.as_context().0) 674 } 675 676 pub(crate) fn _unwrap_array(&self, store: &StoreOpaque) -> Result<Rooted<ArrayRef>> { 677 Ok(self 678 ._as_array(store)? 679 .expect("AnyRef::unwrap_array on non-arrayref")) 680 } 681 } 682 683 unsafe impl WasmTy for Rooted<AnyRef> { 684 #[inline] 685 fn valtype() -> ValType { 686 ValType::Ref(RefType::new(false, HeapType::Any)) 687 } 688 689 #[inline] 690 fn compatible_with_store(&self, store: &StoreOpaque) -> bool { 691 self.comes_from_same_store(store) 692 } 693 694 #[inline] 695 fn dynamic_concrete_type_check( 696 &self, 697 store: &StoreOpaque, 698 _nullable: bool, 699 ty: &HeapType, 700 ) -> Result<()> { 701 self.ensure_matches_ty(store, ty) 702 } 703 704 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> { 705 self.wasm_ty_store(store, ptr, ValRaw::anyref) 706 } 707 708 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self { 709 Self::wasm_ty_load(store, ptr.get_anyref(), AnyRef::from_cloned_gc_ref) 710 } 711 } 712 713 unsafe impl WasmTy for Option<Rooted<AnyRef>> { 714 #[inline] 715 fn valtype() -> ValType { 716 ValType::ANYREF 717 } 718 719 #[inline] 720 fn compatible_with_store(&self, store: &StoreOpaque) -> bool { 721 self.map_or(true, |x| x.comes_from_same_store(store)) 722 } 723 724 #[inline] 725 fn dynamic_concrete_type_check( 726 &self, 727 store: &StoreOpaque, 728 nullable: bool, 729 ty: &HeapType, 730 ) -> Result<()> { 731 match self { 732 Some(a) => a.ensure_matches_ty(store, ty), 733 None => { 734 ensure!( 735 nullable, 736 "expected a non-null reference, but found a null reference" 737 ); 738 Ok(()) 739 } 740 } 741 } 742 743 #[inline] 744 fn is_vmgcref_and_points_to_object(&self) -> bool { 745 self.is_some() 746 } 747 748 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> { 749 <Rooted<AnyRef>>::wasm_ty_option_store(self, store, ptr, ValRaw::anyref) 750 } 751 752 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self { 753 <Rooted<AnyRef>>::wasm_ty_option_load(store, ptr.get_anyref(), AnyRef::from_cloned_gc_ref) 754 } 755 } 756 757 unsafe impl WasmTy for OwnedRooted<AnyRef> { 758 #[inline] 759 fn valtype() -> ValType { 760 ValType::Ref(RefType::new(false, HeapType::Any)) 761 } 762 763 #[inline] 764 fn compatible_with_store(&self, store: &StoreOpaque) -> bool { 765 self.comes_from_same_store(store) 766 } 767 768 #[inline] 769 fn dynamic_concrete_type_check( 770 &self, 771 store: &StoreOpaque, 772 _nullable: bool, 773 ty: &HeapType, 774 ) -> Result<()> { 775 self.ensure_matches_ty(store, ty) 776 } 777 778 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> { 779 self.wasm_ty_store(store, ptr, ValRaw::anyref) 780 } 781 782 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self { 783 Self::wasm_ty_load(store, ptr.get_anyref(), AnyRef::from_cloned_gc_ref) 784 } 785 } 786 787 unsafe impl WasmTy for Option<OwnedRooted<AnyRef>> { 788 #[inline] 789 fn valtype() -> ValType { 790 ValType::ANYREF 791 } 792 793 #[inline] 794 fn compatible_with_store(&self, store: &StoreOpaque) -> bool { 795 self.as_ref() 796 .map_or(true, |x| x.comes_from_same_store(store)) 797 } 798 799 #[inline] 800 fn dynamic_concrete_type_check( 801 &self, 802 store: &StoreOpaque, 803 nullable: bool, 804 ty: &HeapType, 805 ) -> Result<()> { 806 match self { 807 Some(a) => a.ensure_matches_ty(store, ty), 808 None => { 809 ensure!( 810 nullable, 811 "expected a non-null reference, but found a null reference" 812 ); 813 Ok(()) 814 } 815 } 816 } 817 818 #[inline] 819 fn is_vmgcref_and_points_to_object(&self) -> bool { 820 self.is_some() 821 } 822 823 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> { 824 <OwnedRooted<AnyRef>>::wasm_ty_option_store(self, store, ptr, ValRaw::anyref) 825 } 826 827 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self { 828 <OwnedRooted<AnyRef>>::wasm_ty_option_load( 829 store, 830 ptr.get_anyref(), 831 AnyRef::from_cloned_gc_ref, 832 ) 833 } 834 } 835