1 //! Working with GC `eqref`s. 2 3 use crate::{ 4 AnyRef, ArrayRef, ArrayType, AsContext, AsContextMut, GcRefImpl, GcRootIndex, HeapType, I31, 5 OwnedRooted, RefType, Rooted, StructRef, StructType, ValRaw, ValType, WasmTy, 6 prelude::*, 7 runtime::vm::VMGcRef, 8 store::{AutoAssertNoGc, StoreOpaque}, 9 }; 10 use core::mem::{self, MaybeUninit}; 11 use wasmtime_environ::VMGcKind; 12 13 /// A reference to a GC-managed object that can be tested for equality. 14 /// 15 /// The WebAssembly reference types that can be tested for equality, and 16 /// therefore are `eqref`s, include `structref`s, `arrayref`s, and 17 /// `i31ref`s. `funcref`s, `exnref`s, and `externref`s cannot be tested for 18 /// equality by Wasm, and are not `eqref`s. 19 /// 20 /// Use the [`Rooted::ref_eq`][Rooted::ref_eq] method to actually test two 21 /// references for equality. 22 /// 23 /// Like all WebAssembly references, these are opaque to and unforgeable by 24 /// Wasm: they cannot be faked and Wasm cannot, for example, cast the integer 25 /// `0x12345678` into a reference, pretend it is a valid `eqref`, and trick the 26 /// host into dereferencing it and segfaulting or worse. 27 /// 28 /// Note that you can also use `Rooted<EqRef>` and `OwnedRooted<EqRef>` as a 29 /// type parameter with [`Func::typed`][crate::Func::typed]- and 30 /// [`Func::wrap`][crate::Func::wrap]-style APIs. 31 /// 32 /// # Example 33 /// 34 /// ``` 35 /// use wasmtime::*; 36 /// 37 /// # fn foo() -> Result<()> { 38 /// let mut config = Config::new(); 39 /// config.wasm_function_references(true); 40 /// config.wasm_gc(true); 41 /// 42 /// let engine = Engine::new(&config)?; 43 /// let mut store = Store::new(&engine, ()); 44 /// 45 /// // Define a module that exports a function that returns a new `eqref` each 46 /// // time it is invoked. 47 /// let module = Module::new(&engine, r#" 48 /// (module 49 /// (global $g (mut i32) (i32.const 0)) 50 /// (func (export "new-eqref") (result (ref eq)) 51 /// ;; Increment $g. 52 /// global.get $g 53 /// i32.const 1 54 /// i32.add 55 /// global.set $g 56 /// 57 /// ;; Create an `i31ref`, which is a kind of `eqref`, from $g. 58 /// global.get $g 59 /// ref.i31 60 /// ) 61 /// ) 62 /// "#)?; 63 /// 64 /// // Instantiate the module. 65 /// let instance = Instance::new(&mut store, &module, &[])?; 66 /// 67 /// // Get the exported function. 68 /// let new_eqref = instance.get_typed_func::<(), Rooted<EqRef>>(&mut store, "new-eqref")?; 69 /// 70 /// { 71 /// let mut scope = RootScope::new(&mut store); 72 /// 73 /// // Call the function to get an `eqref`. 74 /// let x = new_eqref.call(&mut scope, ())?; 75 /// 76 /// // `x` is equal to itself! 77 /// assert!(Rooted::ref_eq(&scope, &x, &x)?); 78 /// 79 /// // Call the function again to get a new, different `eqref`. 80 /// let y = new_eqref.call(&mut scope, ())?; 81 /// 82 /// // `x` is not equal to `y`! 83 /// assert!(!Rooted::ref_eq(&scope, &x, &y)?); 84 /// } 85 /// # Ok(()) 86 /// # } 87 /// # foo().unwrap(); 88 /// ``` 89 #[derive(Debug)] 90 #[repr(transparent)] 91 pub struct EqRef { 92 pub(super) inner: GcRootIndex, 93 } 94 95 impl From<Rooted<StructRef>> for Rooted<EqRef> { 96 #[inline] from(s: Rooted<StructRef>) -> Self97 fn from(s: Rooted<StructRef>) -> Self { 98 s.to_eqref() 99 } 100 } 101 102 impl From<OwnedRooted<StructRef>> for OwnedRooted<EqRef> { 103 #[inline] from(s: OwnedRooted<StructRef>) -> Self104 fn from(s: OwnedRooted<StructRef>) -> Self { 105 s.to_eqref() 106 } 107 } 108 109 impl From<Rooted<ArrayRef>> for Rooted<EqRef> { 110 #[inline] from(s: Rooted<ArrayRef>) -> Self111 fn from(s: Rooted<ArrayRef>) -> Self { 112 s.to_eqref() 113 } 114 } 115 116 impl From<OwnedRooted<ArrayRef>> for OwnedRooted<EqRef> { 117 #[inline] from(s: OwnedRooted<ArrayRef>) -> Self118 fn from(s: OwnedRooted<ArrayRef>) -> Self { 119 s.to_eqref() 120 } 121 } 122 123 unsafe impl GcRefImpl for EqRef { transmute_ref(index: &GcRootIndex) -> &Self124 fn transmute_ref(index: &GcRootIndex) -> &Self { 125 // Safety: `EqRef` is a newtype of a `GcRootIndex`. 126 let me: &Self = unsafe { mem::transmute(index) }; 127 128 // Assert we really are just a newtype of a `GcRootIndex`. 129 assert!(matches!( 130 me, 131 Self { 132 inner: GcRootIndex { .. }, 133 } 134 )); 135 136 me 137 } 138 } 139 140 impl Rooted<EqRef> { 141 /// Upcast this `eqref` into an `anyref`. 142 #[inline] to_anyref(self) -> Rooted<AnyRef>143 pub fn to_anyref(self) -> Rooted<AnyRef> { 144 self.unchecked_cast() 145 } 146 } 147 148 impl OwnedRooted<EqRef> { 149 /// Upcast this `eqref` into an `anyref`. 150 #[inline] to_anyref(self) -> OwnedRooted<AnyRef>151 pub fn to_anyref(self) -> OwnedRooted<AnyRef> { 152 self.unchecked_cast() 153 } 154 } 155 156 impl EqRef { 157 /// Create a new `Rooted<AnyRef>` from the given GC reference. 158 /// 159 /// `gc_ref` should point to a valid `anyref` and should belong to the 160 /// store's GC heap. Failure to uphold these invariants is memory safe but 161 /// will lead to general incorrectness such as panics or wrong results. from_cloned_gc_ref( store: &mut AutoAssertNoGc<'_>, gc_ref: VMGcRef, ) -> Rooted<Self>162 pub(crate) fn from_cloned_gc_ref( 163 store: &mut AutoAssertNoGc<'_>, 164 gc_ref: VMGcRef, 165 ) -> Rooted<Self> { 166 debug_assert!( 167 gc_ref.is_i31() 168 || store 169 .unwrap_gc_store() 170 .header(&gc_ref) 171 .kind() 172 .matches(VMGcKind::EqRef) 173 ); 174 Rooted::new(store, gc_ref) 175 } 176 177 #[inline] comes_from_same_store(&self, store: &StoreOpaque) -> bool178 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool { 179 self.inner.comes_from_same_store(store) 180 } 181 182 /// Get the type of this reference. 183 /// 184 /// # Errors 185 /// 186 /// Return an error if this reference has been unrooted. 187 /// 188 /// # Panics 189 /// 190 /// Panics if this reference is associated with a different store. ty(&self, store: impl AsContext) -> Result<HeapType>191 pub fn ty(&self, store: impl AsContext) -> Result<HeapType> { 192 self._ty(store.as_context().0) 193 } 194 _ty(&self, store: &StoreOpaque) -> Result<HeapType>195 pub(crate) fn _ty(&self, store: &StoreOpaque) -> Result<HeapType> { 196 let gc_ref = self.inner.try_gc_ref(store)?; 197 if gc_ref.is_i31() { 198 return Ok(HeapType::I31); 199 } 200 201 let header = store.require_gc_store()?.header(gc_ref); 202 203 if header.kind().matches(VMGcKind::StructRef) { 204 return Ok(HeapType::ConcreteStruct( 205 StructType::from_shared_type_index(store.engine(), header.ty().unwrap()), 206 )); 207 } 208 209 if header.kind().matches(VMGcKind::ArrayRef) { 210 return Ok(HeapType::ConcreteArray(ArrayType::from_shared_type_index( 211 store.engine(), 212 header.ty().unwrap(), 213 ))); 214 } 215 216 unreachable!("no other kinds of `eqref`s") 217 } 218 219 /// Does this `eqref` match the given type? 220 /// 221 /// That is, is this object's type a subtype of the given type? 222 /// 223 /// # Errors 224 /// 225 /// Return an error if this reference has been unrooted. 226 /// 227 /// # Panics 228 /// 229 /// Panics if this reference is associated with a different store. matches_ty(&self, store: impl AsContext, ty: &HeapType) -> Result<bool>230 pub fn matches_ty(&self, store: impl AsContext, ty: &HeapType) -> Result<bool> { 231 self._matches_ty(store.as_context().0, ty) 232 } 233 _matches_ty(&self, store: &StoreOpaque, ty: &HeapType) -> Result<bool>234 pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &HeapType) -> Result<bool> { 235 assert!(self.comes_from_same_store(store)); 236 Ok(self._ty(store)?.matches(ty)) 237 } 238 ensure_matches_ty(&self, store: &StoreOpaque, ty: &HeapType) -> Result<()>239 pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &HeapType) -> Result<()> { 240 if !self.comes_from_same_store(store) { 241 bail!("function used with wrong store"); 242 } 243 if self._matches_ty(store, ty)? { 244 Ok(()) 245 } else { 246 let actual_ty = self._ty(store)?; 247 bail!("type mismatch: expected `(ref {ty})`, found `(ref {actual_ty})`") 248 } 249 } 250 251 /// Construct an `eqref` from an `i31`. 252 /// 253 /// # Example 254 /// 255 /// ``` 256 /// # use wasmtime::*; 257 /// # fn _foo() -> Result<()> { 258 /// let mut store = Store::<()>::default(); 259 /// 260 /// // Create an `i31`. 261 /// let i31 = I31::wrapping_u32(999); 262 /// 263 /// // Convert it into an `eqref`. 264 /// let eqref = EqRef::from_i31(&mut store, i31); 265 /// # Ok(()) 266 /// # } 267 /// ``` from_i31(mut store: impl AsContextMut, value: I31) -> Rooted<Self>268 pub fn from_i31(mut store: impl AsContextMut, value: I31) -> Rooted<Self> { 269 let mut store = AutoAssertNoGc::new(store.as_context_mut().0); 270 Self::_from_i31(&mut store, value) 271 } 272 _from_i31(store: &mut AutoAssertNoGc<'_>, value: I31) -> Rooted<Self>273 pub(crate) fn _from_i31(store: &mut AutoAssertNoGc<'_>, value: I31) -> Rooted<Self> { 274 let gc_ref = VMGcRef::from_i31(value.runtime_i31()); 275 Rooted::new(store, gc_ref) 276 } 277 278 /// Is this `eqref` an `i31`? 279 /// 280 /// # Errors 281 /// 282 /// Return an error if this reference has been unrooted. 283 /// 284 /// # Panics 285 /// 286 /// Panics if this reference is associated with a different store. is_i31(&self, store: impl AsContext) -> Result<bool>287 pub fn is_i31(&self, store: impl AsContext) -> Result<bool> { 288 self._is_i31(store.as_context().0) 289 } 290 _is_i31(&self, store: &StoreOpaque) -> Result<bool>291 pub(crate) fn _is_i31(&self, store: &StoreOpaque) -> Result<bool> { 292 assert!(self.comes_from_same_store(store)); 293 let gc_ref = self.inner.try_gc_ref(store)?; 294 Ok(gc_ref.is_i31()) 295 } 296 297 /// Downcast this `eqref` to an `i31`. 298 /// 299 /// If this `eqref` is an `i31`, then `Some(_)` is returned. 300 /// 301 /// If this `eqref` is not an `i31`, then `None` is returned. 302 /// 303 /// # Errors 304 /// 305 /// Return an error if this reference has been unrooted. 306 /// 307 /// # Panics 308 /// 309 /// Panics if this reference is associated with a different store. as_i31(&self, store: impl AsContext) -> Result<Option<I31>>310 pub fn as_i31(&self, store: impl AsContext) -> Result<Option<I31>> { 311 self._as_i31(store.as_context().0) 312 } 313 _as_i31(&self, store: &StoreOpaque) -> Result<Option<I31>>314 pub(crate) fn _as_i31(&self, store: &StoreOpaque) -> Result<Option<I31>> { 315 assert!(self.comes_from_same_store(store)); 316 let gc_ref = self.inner.try_gc_ref(store)?; 317 Ok(gc_ref.as_i31().map(Into::into)) 318 } 319 320 /// Downcast this `eqref` to an `i31`, panicking if this `eqref` is not an 321 /// `i31`. 322 /// 323 /// # Errors 324 /// 325 /// Return an error if this reference has been unrooted. 326 /// 327 /// # Panics 328 /// 329 /// Panics if this reference is associated with a different store, or if 330 /// this `eqref` is not an `i31`. unwrap_i31(&self, store: impl AsContext) -> Result<I31>331 pub fn unwrap_i31(&self, store: impl AsContext) -> Result<I31> { 332 Ok(self.as_i31(store)?.expect("EqRef::unwrap_i31 on non-i31")) 333 } 334 335 /// Is this `eqref` a `structref`? 336 /// 337 /// # Errors 338 /// 339 /// Return an error if this reference has been unrooted. 340 /// 341 /// # Panics 342 /// 343 /// Panics if this reference is associated with a different store. is_struct(&self, store: impl AsContext) -> Result<bool>344 pub fn is_struct(&self, store: impl AsContext) -> Result<bool> { 345 self._is_struct(store.as_context().0) 346 } 347 _is_struct(&self, store: &StoreOpaque) -> Result<bool>348 pub(crate) fn _is_struct(&self, store: &StoreOpaque) -> Result<bool> { 349 let gc_ref = self.inner.try_gc_ref(store)?; 350 Ok(!gc_ref.is_i31() 351 && store 352 .require_gc_store()? 353 .kind(gc_ref) 354 .matches(VMGcKind::StructRef)) 355 } 356 357 /// Downcast this `eqref` to a `structref`. 358 /// 359 /// If this `eqref` is a `structref`, then `Some(_)` is returned. 360 /// 361 /// If this `eqref` is not a `structref`, then `None` is returned. 362 /// 363 /// # Errors 364 /// 365 /// Return an error if this reference has been unrooted. 366 /// 367 /// # Panics 368 /// 369 /// Panics if this reference is associated with a different store. as_struct(&self, store: impl AsContext) -> Result<Option<Rooted<StructRef>>>370 pub fn as_struct(&self, store: impl AsContext) -> Result<Option<Rooted<StructRef>>> { 371 self._as_struct(store.as_context().0) 372 } 373 _as_struct(&self, store: &StoreOpaque) -> Result<Option<Rooted<StructRef>>>374 pub(crate) fn _as_struct(&self, store: &StoreOpaque) -> Result<Option<Rooted<StructRef>>> { 375 if self._is_struct(store)? { 376 Ok(Some(Rooted::from_gc_root_index(self.inner))) 377 } else { 378 Ok(None) 379 } 380 } 381 382 /// Downcast this `eqref` to a `structref`, panicking if this `eqref` is 383 /// not a `structref`. 384 /// 385 /// # Errors 386 /// 387 /// Return an error if this reference has been unrooted. 388 /// 389 /// # Panics 390 /// 391 /// Panics if this reference is associated with a different store, or if 392 /// this `eqref` is not a `struct`. unwrap_struct(&self, store: impl AsContext) -> Result<Rooted<StructRef>>393 pub fn unwrap_struct(&self, store: impl AsContext) -> Result<Rooted<StructRef>> { 394 self._unwrap_struct(store.as_context().0) 395 } 396 _unwrap_struct(&self, store: &StoreOpaque) -> Result<Rooted<StructRef>>397 pub(crate) fn _unwrap_struct(&self, store: &StoreOpaque) -> Result<Rooted<StructRef>> { 398 Ok(self 399 ._as_struct(store)? 400 .expect("EqRef::unwrap_struct on non-structref")) 401 } 402 403 /// Is this `eqref` an `arrayref`? 404 /// 405 /// # Errors 406 /// 407 /// Return an error if this reference has been unrooted. 408 /// 409 /// # Panics 410 /// 411 /// Panics if this reference is associated with a different store. is_array(&self, store: impl AsContext) -> Result<bool>412 pub fn is_array(&self, store: impl AsContext) -> Result<bool> { 413 self._is_array(store.as_context().0) 414 } 415 _is_array(&self, store: &StoreOpaque) -> Result<bool>416 pub(crate) fn _is_array(&self, store: &StoreOpaque) -> Result<bool> { 417 let gc_ref = self.inner.try_gc_ref(store)?; 418 Ok(!gc_ref.is_i31() 419 && store 420 .require_gc_store()? 421 .kind(gc_ref) 422 .matches(VMGcKind::ArrayRef)) 423 } 424 425 /// Downcast this `eqref` to an `arrayref`. 426 /// 427 /// If this `eqref` is an `arrayref`, then `Some(_)` is returned. 428 /// 429 /// If this `eqref` is not an `arrayref`, then `None` is returned. 430 /// 431 /// # Errors 432 /// 433 /// Return an error if this reference has been unrooted. 434 /// 435 /// # Panics 436 /// 437 /// Panics if this reference is associated with a different store. as_array(&self, store: impl AsContext) -> Result<Option<Rooted<ArrayRef>>>438 pub fn as_array(&self, store: impl AsContext) -> Result<Option<Rooted<ArrayRef>>> { 439 self._as_array(store.as_context().0) 440 } 441 _as_array(&self, store: &StoreOpaque) -> Result<Option<Rooted<ArrayRef>>>442 pub(crate) fn _as_array(&self, store: &StoreOpaque) -> Result<Option<Rooted<ArrayRef>>> { 443 if self._is_array(store)? { 444 Ok(Some(Rooted::from_gc_root_index(self.inner))) 445 } else { 446 Ok(None) 447 } 448 } 449 450 /// Downcast this `eqref` to an `arrayref`, panicking if this `eqref` is 451 /// not an `arrayref`. 452 /// 453 /// # Errors 454 /// 455 /// Return an error if this reference has been unrooted. 456 /// 457 /// # Panics 458 /// 459 /// Panics if this reference is associated with a different store, or if 460 /// this `eqref` is not an `array`. unwrap_array(&self, store: impl AsContext) -> Result<Rooted<ArrayRef>>461 pub fn unwrap_array(&self, store: impl AsContext) -> Result<Rooted<ArrayRef>> { 462 self._unwrap_array(store.as_context().0) 463 } 464 _unwrap_array(&self, store: &StoreOpaque) -> Result<Rooted<ArrayRef>>465 pub(crate) fn _unwrap_array(&self, store: &StoreOpaque) -> Result<Rooted<ArrayRef>> { 466 Ok(self 467 ._as_array(store)? 468 .expect("EqRef::unwrap_array on non-arrayref")) 469 } 470 } 471 472 unsafe impl WasmTy for Rooted<EqRef> { 473 #[inline] valtype() -> ValType474 fn valtype() -> ValType { 475 ValType::Ref(RefType::new(false, HeapType::Eq)) 476 } 477 478 #[inline] compatible_with_store(&self, store: &StoreOpaque) -> bool479 fn compatible_with_store(&self, store: &StoreOpaque) -> bool { 480 self.comes_from_same_store(store) 481 } 482 483 #[inline] dynamic_concrete_type_check( &self, store: &StoreOpaque, _nullable: bool, ty: &HeapType, ) -> Result<()>484 fn dynamic_concrete_type_check( 485 &self, 486 store: &StoreOpaque, 487 _nullable: bool, 488 ty: &HeapType, 489 ) -> Result<()> { 490 self.ensure_matches_ty(store, ty) 491 } 492 store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()>493 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> { 494 self.wasm_ty_store(store, ptr, ValRaw::anyref) 495 } 496 load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self497 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self { 498 Self::wasm_ty_load(store, ptr.get_anyref(), EqRef::from_cloned_gc_ref) 499 } 500 } 501 502 unsafe impl WasmTy for Option<Rooted<EqRef>> { 503 #[inline] valtype() -> ValType504 fn valtype() -> ValType { 505 ValType::EQREF 506 } 507 508 #[inline] compatible_with_store(&self, store: &StoreOpaque) -> bool509 fn compatible_with_store(&self, store: &StoreOpaque) -> bool { 510 self.map_or(true, |x| x.comes_from_same_store(store)) 511 } 512 513 #[inline] dynamic_concrete_type_check( &self, store: &StoreOpaque, nullable: bool, ty: &HeapType, ) -> Result<()>514 fn dynamic_concrete_type_check( 515 &self, 516 store: &StoreOpaque, 517 nullable: bool, 518 ty: &HeapType, 519 ) -> Result<()> { 520 match self { 521 Some(s) => Rooted::<EqRef>::dynamic_concrete_type_check(s, store, nullable, ty), 522 None => { 523 ensure!( 524 nullable, 525 "expected a non-null reference, but found a null reference" 526 ); 527 Ok(()) 528 } 529 } 530 } 531 532 #[inline] is_vmgcref_and_points_to_object(&self) -> bool533 fn is_vmgcref_and_points_to_object(&self) -> bool { 534 self.is_some() 535 } 536 store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()>537 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> { 538 <Rooted<EqRef>>::wasm_ty_option_store(self, store, ptr, ValRaw::anyref) 539 } 540 load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self541 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self { 542 <Rooted<EqRef>>::wasm_ty_option_load(store, ptr.get_anyref(), EqRef::from_cloned_gc_ref) 543 } 544 } 545 546 unsafe impl WasmTy for OwnedRooted<EqRef> { 547 #[inline] valtype() -> ValType548 fn valtype() -> ValType { 549 ValType::Ref(RefType::new(false, HeapType::Eq)) 550 } 551 552 #[inline] compatible_with_store(&self, store: &StoreOpaque) -> bool553 fn compatible_with_store(&self, store: &StoreOpaque) -> bool { 554 self.comes_from_same_store(store) 555 } 556 557 #[inline] dynamic_concrete_type_check( &self, store: &StoreOpaque, _: bool, ty: &HeapType, ) -> Result<()>558 fn dynamic_concrete_type_check( 559 &self, 560 store: &StoreOpaque, 561 _: bool, 562 ty: &HeapType, 563 ) -> Result<()> { 564 self.ensure_matches_ty(store, ty) 565 } 566 store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()>567 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> { 568 self.wasm_ty_store(store, ptr, ValRaw::anyref) 569 } 570 load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self571 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self { 572 Self::wasm_ty_load(store, ptr.get_anyref(), EqRef::from_cloned_gc_ref) 573 } 574 } 575 576 unsafe impl WasmTy for Option<OwnedRooted<EqRef>> { 577 #[inline] valtype() -> ValType578 fn valtype() -> ValType { 579 ValType::EQREF 580 } 581 582 #[inline] compatible_with_store(&self, store: &StoreOpaque) -> bool583 fn compatible_with_store(&self, store: &StoreOpaque) -> bool { 584 self.as_ref() 585 .map_or(true, |x| x.comes_from_same_store(store)) 586 } 587 588 #[inline] dynamic_concrete_type_check( &self, store: &StoreOpaque, nullable: bool, ty: &HeapType, ) -> Result<()>589 fn dynamic_concrete_type_check( 590 &self, 591 store: &StoreOpaque, 592 nullable: bool, 593 ty: &HeapType, 594 ) -> Result<()> { 595 match self { 596 Some(s) => OwnedRooted::<EqRef>::dynamic_concrete_type_check(s, store, nullable, ty), 597 None => { 598 ensure!( 599 nullable, 600 "expected a non-null reference, but found a null reference" 601 ); 602 Ok(()) 603 } 604 } 605 } 606 607 #[inline] is_vmgcref_and_points_to_object(&self) -> bool608 fn is_vmgcref_and_points_to_object(&self) -> bool { 609 self.is_some() 610 } 611 store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()>612 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> { 613 <OwnedRooted<EqRef>>::wasm_ty_option_store(self, store, ptr, ValRaw::anyref) 614 } 615 load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self616 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self { 617 <OwnedRooted<EqRef>>::wasm_ty_option_load( 618 store, 619 ptr.get_anyref(), 620 EqRef::from_cloned_gc_ref, 621 ) 622 } 623 } 624