1 //! Implementation of `externref` in Wasmtime. 2 3 use super::{AnyRef, RootedGcRefImpl}; 4 use crate::prelude::*; 5 use crate::runtime::vm::{self, VMGcRef, VMStore}; 6 use crate::{ 7 AsContextMut, GcHeapOutOfMemory, GcRefImpl, GcRootIndex, HeapType, OwnedRooted, RefType, 8 Result, Rooted, StoreContext, StoreContextMut, ValRaw, ValType, WasmTy, 9 store::{AutoAssertNoGc, StoreOpaque, StoreResourceLimiter}, 10 }; 11 use core::any::Any; 12 use core::mem; 13 use core::mem::MaybeUninit; 14 15 /// An opaque, GC-managed reference to some host data that can be passed to 16 /// WebAssembly. 17 /// 18 /// The `ExternRef` type represents WebAssembly `externref` values. Wasm can't 19 /// do anything with the `externref`s other than put them in tables, globals, 20 /// and locals or pass them to other functions (such as imported functions from 21 /// the host). Unlike `anyref`s, Wasm guests cannot directly allocate new 22 /// `externref`s; only the host can. 23 /// 24 /// You can use `ExternRef` to give access to host objects and control the 25 /// operations that Wasm can perform on them via what functions you allow Wasm 26 /// to import. 27 /// 28 /// Like all WebAssembly references, these are opaque and unforgeable to Wasm: 29 /// they cannot be faked and Wasm cannot, for example, cast the integer 30 /// `0x12345678` into a reference, pretend it is a valid `externref`, and trick 31 /// the host into dereferencing it and segfaulting or worse. 32 /// 33 /// Note that you can also use `Rooted<ExternRef>` and 34 /// `OwnedRooted<ExternRef>` as a type parameter with 35 /// [`Func::typed`][crate::Func::typed]- and 36 /// [`Func::wrap`][crate::Func::wrap]-style APIs. 37 /// 38 /// # Example 39 /// 40 /// ``` 41 /// # use wasmtime::*; 42 /// # use std::borrow::Cow; 43 /// # fn _foo() -> Result<()> { 44 /// let engine = Engine::default(); 45 /// let mut store = Store::new(&engine, ()); 46 /// 47 /// // Define some APIs for working with host strings from Wasm via `externref`. 48 /// let mut linker = Linker::new(&engine); 49 /// linker.func_wrap( 50 /// "host-string", 51 /// "new", 52 /// |caller: Caller<'_, ()>| -> Result<Rooted<ExternRef>> { 53 /// ExternRef::new(caller, Cow::from("")) 54 /// }, 55 /// )?; 56 /// linker.func_wrap( 57 /// "host-string", 58 /// "concat", 59 /// |mut caller: Caller<'_, ()>, a: Rooted<ExternRef>, b: Rooted<ExternRef>| -> Result<Rooted<ExternRef>> { 60 /// let mut s = a 61 /// .data(&caller)? 62 /// .ok_or_else(|| Error::msg("externref has no host data"))? 63 /// .downcast_ref::<Cow<str>>() 64 /// .ok_or_else(|| Error::msg("externref was not a string"))? 65 /// .clone() 66 /// .into_owned(); 67 /// let b = b 68 /// .data(&caller)? 69 /// .ok_or_else(|| Error::msg("externref has no host data"))? 70 /// .downcast_ref::<Cow<str>>() 71 /// .ok_or_else(|| Error::msg("externref was not a string"))?; 72 /// s.push_str(&b); 73 /// ExternRef::new(&mut caller, s) 74 /// }, 75 /// )?; 76 /// 77 /// // Here is a Wasm module that uses those APIs. 78 /// let module = Module::new( 79 /// &engine, 80 /// r#" 81 /// (module 82 /// (import "host-string" "concat" (func $concat (param externref externref) 83 /// (result externref))) 84 /// (func (export "run") (param externref externref) (result externref) 85 /// local.get 0 86 /// local.get 1 87 /// call $concat 88 /// ) 89 /// ) 90 /// "#, 91 /// )?; 92 /// 93 /// // Create a couple `externref`s wrapping `Cow<str>`s. 94 /// let hello = ExternRef::new(&mut store, Cow::from("Hello, "))?; 95 /// let world = ExternRef::new(&mut store, Cow::from("World!"))?; 96 /// 97 /// // Instantiate the module and pass the `externref`s into it. 98 /// let instance = linker.instantiate(&mut store, &module)?; 99 /// let result = instance 100 /// .get_typed_func::<(Rooted<ExternRef>, Rooted<ExternRef>), Rooted<ExternRef>>(&mut store, "run")? 101 /// .call(&mut store, (hello, world))?; 102 /// 103 /// // The module should have concatenated the strings together! 104 /// assert_eq!( 105 /// result 106 /// .data(&store)? 107 /// .expect("externref should have host data") 108 /// .downcast_ref::<Cow<str>>() 109 /// .expect("host data should be a `Cow<str>`"), 110 /// "Hello, World!" 111 /// ); 112 /// # Ok(()) 113 /// # } 114 /// ``` 115 #[derive(Debug, Clone)] 116 #[repr(transparent)] 117 pub struct ExternRef { 118 pub(crate) inner: GcRootIndex, 119 } 120 121 unsafe impl GcRefImpl for ExternRef { 122 fn transmute_ref(index: &GcRootIndex) -> &Self { 123 // Safety: `ExternRef` is a newtype of a `GcRootIndex`. 124 let me: &Self = unsafe { mem::transmute(index) }; 125 126 // Assert we really are just a newtype of a `GcRootIndex`. 127 assert!(matches!( 128 me, 129 Self { 130 inner: GcRootIndex { .. }, 131 } 132 )); 133 134 me 135 } 136 } 137 138 impl ExternRef { 139 /// Synchronously allocates a new `ExternRef` wrapping the given value. 140 /// 141 /// The resulting value is automatically unrooted when the given `context`'s 142 /// scope is exited. If you need to hold the reference past the `context`'s 143 /// scope, convert the result into an 144 /// [`OwnedRooted<T>`][crate::OwnedRooted]. See the documentation for 145 /// [`Rooted<T>`][crate::Rooted] and 146 /// [`OwnedRooted<T>`][crate::OwnedRooted] for more details. 147 /// 148 /// # Automatic Garbage Collection 149 /// 150 /// If the GC heap is at capacity, and there isn't room for allocating a new 151 /// `externref`, this method will automatically trigger a synchronous 152 /// collection in an attempt to free up space in the GC heap. 153 /// 154 /// # Errors 155 /// 156 /// If the allocation cannot be satisfied because the GC heap is currently 157 /// out of memory, then a [`GcHeapOutOfMemory<T>`][crate::GcHeapOutOfMemory] 158 /// error is returned. The allocation might succeed on a second attempt if 159 /// you drop some rooted GC references and try again. 160 /// 161 /// The [`GcHeapOutOfMemory<T>`][crate::GcHeapOutOfMemory] error contains 162 /// the host value that the `externref` would have wrapped. You can extract 163 /// that value from the error and reuse it when attempting to allocate an 164 /// `externref` again after dropping rooted GC references and then 165 /// performing a collection or otherwise do with it whatever you see fit. 166 /// 167 /// # Example 168 /// 169 /// ``` 170 /// # use wasmtime::*; 171 /// # fn _foo() -> Result<()> { 172 /// let mut store = Store::<()>::default(); 173 /// 174 /// { 175 /// let mut scope = RootScope::new(&mut store); 176 /// 177 /// // Allocate an `externref` wrapping a `String`. 178 /// let externref = match ExternRef::new(&mut scope, "hello!".to_string()) { 179 /// // The allocation succeeded. 180 /// Ok(x) => x, 181 /// // The allocation failed. 182 /// Err(e) => match e.downcast::<GcHeapOutOfMemory<String>>() { 183 /// // The allocation failed because the GC heap does not have 184 /// // capacity for this allocation. 185 /// Ok(oom) => { 186 /// // Take back ownership of our `String`. 187 /// let s = oom.into_inner(); 188 /// // Drop some rooted GC refs from our system to potentially 189 /// // free up space for Wasmtime to make this allocation. 190 /// # let drop_some_gc_refs = || {}; 191 /// drop_some_gc_refs(); 192 /// // Finally, try to allocate again, reusing the original 193 /// // string. 194 /// ExternRef::new(&mut scope, s)? 195 /// } 196 /// Err(e) => return Err(e), 197 /// }, 198 /// }; 199 /// 200 /// // Use the `externref`, pass it to Wasm, etc... 201 /// } 202 /// 203 /// // The `externref` is automatically unrooted when we exit the scope. 204 /// # Ok(()) 205 /// # } 206 /// ``` 207 /// 208 /// # Panics 209 /// 210 /// Panics if the `context` is configured for async; use 211 /// [`ExternRef::new_async`][crate::ExternRef::new_async] to perform 212 /// asynchronous allocation instead. 213 pub fn new<T>(mut store: impl AsContextMut, value: T) -> Result<Rooted<ExternRef>> 214 where 215 T: 'static + Any + Send + Sync, 216 { 217 let (mut limiter, store) = store.as_context_mut().0.resource_limiter_and_store_opaque(); 218 assert!(!store.async_support()); 219 vm::assert_ready(Self::_new_async(store, limiter.as_mut(), value)) 220 } 221 222 /// Asynchronously allocates a new `ExternRef` wrapping the given value. 223 /// 224 /// The resulting value is automatically unrooted when the given `context`'s 225 /// scope is exited. If you need to hold the reference past the `context`'s 226 /// scope, convert the result into an 227 /// [`OwnedRooted<T>`][crate::OwnedRooted]. See the documentation for 228 /// [`Rooted<T>`][crate::Rooted] and 229 /// [`OwnedRooted<T>`][crate::OwnedRooted] for more details. 230 /// 231 /// # Automatic Garbage Collection 232 /// 233 /// If the GC heap is at capacity, and there isn't room for allocating a new 234 /// `externref`, this method will automatically trigger an asynchronous 235 /// collection in an attempt to free up space in the GC heap. 236 /// 237 /// # Errors 238 /// 239 /// If the allocation cannot be satisfied because the GC heap is currently 240 /// out of memory, then a [`GcHeapOutOfMemory<T>`][crate::GcHeapOutOfMemory] 241 /// error is returned. The allocation might succeed on a second attempt if 242 /// you drop some rooted GC references and try again. 243 /// 244 /// The [`GcHeapOutOfMemory<T>`][crate::GcHeapOutOfMemory] error contains 245 /// the host value that the `externref` would have wrapped. You can extract 246 /// that value from the error and reuse it when attempting to allocate an 247 /// `externref` again after dropping rooted GC references and then 248 /// performing a collection or otherwise do with it whatever you see fit. 249 /// 250 /// # Example 251 /// 252 /// ``` 253 /// use wasmtime::*; 254 /// 255 /// # async fn _foo() -> Result<()> { 256 /// let mut store = Store::<()>::default(); 257 /// 258 /// { 259 /// let mut scope = RootScope::new(&mut store); 260 /// 261 /// // Create an `externref` wrapping a `String`. 262 /// let externref = match ExternRef::new_async(&mut scope, "hello!".to_string()).await { 263 /// // The allocation succeeded. 264 /// Ok(x) => x, 265 /// // The allocation failed. 266 /// Err(e) => match e.downcast::<GcHeapOutOfMemory<String>>() { 267 /// // The allocation failed because the GC heap does not have 268 /// // capacity for this allocation. 269 /// Ok(oom) => { 270 /// // Take back ownership of our `String`. 271 /// let s = oom.into_inner(); 272 /// // Drop some rooted GC refs from our system to potentially 273 /// // free up space for Wasmtime to make this allocation. 274 /// # let drop_some_gc_refs = || {}; 275 /// drop_some_gc_refs(); 276 /// // Finally, try to allocate again, reusing the original 277 /// // string. 278 /// ExternRef::new_async(&mut scope, s).await? 279 /// } 280 /// Err(e) => return Err(e), 281 /// }, 282 /// }; 283 /// 284 /// // Use the `externref`, pass it to Wasm, etc... 285 /// } 286 /// 287 /// // The `externref` is automatically unrooted when we exit the scope. 288 /// # Ok(()) 289 /// # } 290 /// ``` 291 /// 292 /// # Panics 293 /// 294 /// Panics if the `context` is not configured for async; use 295 /// [`ExternRef::new`][crate::ExternRef::new] to perform synchronous 296 /// allocation instead. 297 #[cfg(feature = "async")] 298 pub async fn new_async<T>(mut store: impl AsContextMut, value: T) -> Result<Rooted<ExternRef>> 299 where 300 T: 'static + Any + Send + Sync, 301 { 302 let (mut limiter, store) = store.as_context_mut().0.resource_limiter_and_store_opaque(); 303 Self::_new_async(store, limiter.as_mut(), value).await 304 } 305 306 pub(crate) async fn _new_async<T>( 307 store: &mut StoreOpaque, 308 limiter: Option<&mut StoreResourceLimiter<'_>>, 309 value: T, 310 ) -> Result<Rooted<ExternRef>> 311 where 312 T: 'static + Any + Send + Sync, 313 { 314 // Allocate the box once, regardless how many gc-and-retry attempts we 315 // make. 316 let value: Box<dyn Any + Send + Sync> = Box::new(value); 317 318 let gc_ref = store 319 .retry_after_gc_async(limiter, value, |store, value| { 320 store 321 .require_gc_store_mut()? 322 .alloc_externref(value) 323 .context("unrecoverable error when allocating new `externref`")? 324 .map_err(|(x, n)| GcHeapOutOfMemory::new(x, n).into()) 325 }) 326 .await 327 // Translate the `GcHeapOutOfMemory`'s inner value from the boxed 328 // trait object into `T`. 329 .map_err( 330 |e| match e.downcast::<GcHeapOutOfMemory<Box<dyn Any + Send + Sync>>>() { 331 Ok(oom) => oom.map_inner(|x| *x.downcast::<T>().unwrap()).into(), 332 Err(e) => e, 333 }, 334 )?; 335 336 let mut ctx = AutoAssertNoGc::new(store); 337 Ok(Self::from_cloned_gc_ref(&mut ctx, gc_ref.into())) 338 } 339 340 /// Convert an `anyref` into an `externref`. 341 /// 342 /// This is equivalent to the `extern.convert_any` instruction in Wasm. 343 /// 344 /// You can get the underlying `anyref` again via the 345 /// [`AnyRef::convert_extern`] method or the `any.convert_extern` Wasm 346 /// instruction. 347 /// 348 /// The resulting `ExternRef` will not have any host data associated with 349 /// it, so [`ExternRef::data`] and [`ExternRef::data_mut`] will both return 350 /// `None`. 351 /// 352 /// Returns an error if the `anyref` GC reference has been unrooted (eg if 353 /// you attempt to use a `Rooted<AnyRef>` after exiting the scope it was 354 /// rooted within). See the documentation for [`Rooted<T>`][crate::Rooted] 355 /// for more details. 356 /// 357 /// # Example 358 /// 359 /// ``` 360 /// use wasmtime::*; 361 /// # fn foo() -> Result<()> { 362 /// let engine = Engine::default(); 363 /// let mut store = Store::new(&engine, ()); 364 /// 365 /// // Create an `anyref`. 366 /// let i31 = I31::wrapping_u32(0x1234); 367 /// let anyref = AnyRef::from_i31(&mut store, i31); 368 /// 369 /// // Convert that `anyref` into an `externref`. 370 /// let externref = ExternRef::convert_any(&mut store, anyref)?; 371 /// 372 /// // This `externref` doesn't have any associated host data. 373 /// assert!(externref.data(&store)?.is_none()); 374 /// 375 /// // We can convert it back to an `anyref` and get its underlying `i31` 376 /// // data. 377 /// let anyref = AnyRef::convert_extern(&mut store, externref)?; 378 /// assert_eq!(anyref.unwrap_i31(&store)?.get_u32(), 0x1234); 379 /// # Ok(()) } 380 /// # foo().unwrap(); 381 pub fn convert_any( 382 mut context: impl AsContextMut, 383 anyref: Rooted<AnyRef>, 384 ) -> Result<Rooted<ExternRef>> { 385 let mut store = AutoAssertNoGc::new(context.as_context_mut().0); 386 Self::_convert_any(&mut store, anyref) 387 } 388 389 pub(crate) fn _convert_any( 390 store: &mut AutoAssertNoGc<'_>, 391 anyref: Rooted<AnyRef>, 392 ) -> Result<Rooted<ExternRef>> { 393 let gc_ref = anyref.try_clone_gc_ref(store)?; 394 Ok(Self::from_cloned_gc_ref(store, gc_ref)) 395 } 396 397 /// Create a new `Rooted<ExternRef>` from the given GC reference. 398 /// 399 /// Does not invoke the `GcRuntime`'s clone hook; callers should ensure it 400 /// has been called. 401 /// 402 /// `gc_ref` should be a GC reference pointing to an instance of `externref` 403 /// that is in this store's GC heap. Failure to uphold this invariant is 404 /// memory safe but will result in general incorrectness such as panics and 405 /// wrong results. 406 pub(crate) fn from_cloned_gc_ref( 407 store: &mut AutoAssertNoGc<'_>, 408 gc_ref: VMGcRef, 409 ) -> Rooted<Self> { 410 if !gc_ref.is_i31() { 411 assert!( 412 gc_ref.is_extern_ref(&*store.unwrap_gc_store().gc_heap) 413 || gc_ref.is_any_ref(&*store.unwrap_gc_store().gc_heap), 414 "GC reference {gc_ref:#p} should be an externref or anyref" 415 ); 416 } 417 Rooted::new(store, gc_ref) 418 } 419 420 /// Get a shared borrow of the underlying data for this `ExternRef`. 421 /// 422 /// Returns `None` if this is an `externref` wrapper of an `anyref` created 423 /// by the `extern.convert_any` instruction or the 424 /// [`ExternRef::convert_any`] method. 425 /// 426 /// Returns an error if this `externref` GC reference has been unrooted (eg 427 /// if you attempt to use a `Rooted<ExternRef>` after exiting the scope it 428 /// was rooted within). See the documentation for 429 /// [`Rooted<T>`][crate::Rooted] for more details. 430 /// 431 /// # Example 432 /// 433 /// ``` 434 /// # use wasmtime::*; 435 /// # fn _foo() -> Result<()> { 436 /// let mut store = Store::<()>::default(); 437 /// 438 /// let externref = ExternRef::new(&mut store, "hello")?; 439 /// 440 /// // Access the `externref`'s host data. 441 /// let data = externref.data(&store)?.ok_or_else(|| Error::msg("no host data"))?; 442 /// // Dowcast it to a `&str`. 443 /// let data = data.downcast_ref::<&str>().ok_or_else(|| Error::msg("not a str"))?; 444 /// // We should have got the data we created the `externref` with! 445 /// assert_eq!(*data, "hello"); 446 /// # Ok(()) 447 /// # } 448 /// ``` 449 pub fn data<'a, T>( 450 &self, 451 store: impl Into<StoreContext<'a, T>>, 452 ) -> Result<Option<&'a (dyn Any + Send + Sync)>> 453 where 454 T: 'static, 455 { 456 let store = store.into().0; 457 let gc_ref = self.inner.try_gc_ref(&store)?; 458 if gc_ref.is_i31() { 459 return Ok(None); 460 } 461 let gc_store = store.require_gc_store()?; 462 if let Some(externref) = gc_ref.as_externref(&*gc_store.gc_heap) { 463 Ok(Some(gc_store.externref_host_data(externref))) 464 } else { 465 Ok(None) 466 } 467 } 468 469 /// Get an exclusive borrow of the underlying data for this `ExternRef`. 470 /// 471 /// Returns `None` if this is an `externref` wrapper of an `anyref` created 472 /// by the `extern.convert_any` instruction or the 473 /// [`ExternRef::convert_any`] constructor. 474 /// 475 /// Returns an error if this `externref` GC reference has been unrooted (eg 476 /// if you attempt to use a `Rooted<ExternRef>` after exiting the scope it 477 /// was rooted within). See the documentation for 478 /// [`Rooted<T>`][crate::Rooted] for more details. 479 /// 480 /// # Example 481 /// 482 /// ``` 483 /// # use wasmtime::*; 484 /// # fn _foo() -> Result<()> { 485 /// let mut store = Store::<()>::default(); 486 /// 487 /// let externref = ExternRef::new::<usize>(&mut store, 0)?; 488 /// 489 /// // Access the `externref`'s host data. 490 /// let data = externref.data_mut(&mut store)?.ok_or_else(|| Error::msg("no host data"))?; 491 /// // Dowcast it to a `usize`. 492 /// let data = data.downcast_mut::<usize>().ok_or_else(|| Error::msg("not a usize"))?; 493 /// // We initialized to zero. 494 /// assert_eq!(*data, 0); 495 /// // And we can mutate the value! 496 /// *data += 10; 497 /// # Ok(()) 498 /// # } 499 /// ``` 500 pub fn data_mut<'a, T>( 501 &self, 502 store: impl Into<StoreContextMut<'a, T>>, 503 ) -> Result<Option<&'a mut (dyn Any + Send + Sync)>> 504 where 505 T: 'static, 506 { 507 let store = store.into().0; 508 // NB: need to do an unchecked copy to release the borrow on the store 509 // so that we can get the store's GC store. But importantly we cannot 510 // trigger a GC while we are working with `gc_ref` here. 511 let gc_ref = self.inner.try_gc_ref(store)?.unchecked_copy(); 512 if gc_ref.is_i31() { 513 return Ok(None); 514 } 515 let gc_store = store.require_gc_store_mut()?; 516 if let Some(externref) = gc_ref.as_externref(&*gc_store.gc_heap) { 517 Ok(Some(gc_store.externref_host_data_mut(externref))) 518 } else { 519 Ok(None) 520 } 521 } 522 523 /// Creates a new strongly-owned [`ExternRef`] from the raw value provided. 524 /// 525 /// This is intended to be used in conjunction with [`Func::new_unchecked`], 526 /// [`Func::call_unchecked`], and [`ValRaw`] with its `externref` field. 527 /// 528 /// This function assumes that `raw` is an externref value which is 529 /// currently rooted within the [`Store`]. 530 /// 531 /// # Correctness 532 /// 533 /// This function is tricky to get right because `raw` not only must be a 534 /// valid `externref` value produced prior by [`ExternRef::to_raw`] but it 535 /// must also be correctly rooted within the store. When arguments are 536 /// provided to a callback with [`Func::new_unchecked`], for example, or 537 /// returned via [`Func::call_unchecked`], if a GC is performed within the 538 /// store then floating `externref` values are not rooted and will be GC'd, 539 /// meaning that this function will no longer be correct to call with the 540 /// values cleaned up. This function must be invoked *before* possible GC 541 /// operations can happen (such as calling Wasm). 542 /// 543 /// 544 /// When in doubt try to not use this. Instead use the Rust APIs of 545 /// [`TypedFunc`] and friends. Note though that this function is not 546 /// `unsafe` as any value can be passed in. Incorrect values can result in 547 /// runtime panics, however, so care must still be taken with this method. 548 /// 549 /// [`Func::call_unchecked`]: crate::Func::call_unchecked 550 /// [`Func::new_unchecked`]: crate::Func::new_unchecked 551 /// [`Store`]: crate::Store 552 /// [`TypedFunc`]: crate::TypedFunc 553 /// [`ValRaw`]: crate::ValRaw 554 pub fn from_raw(mut store: impl AsContextMut, raw: u32) -> Option<Rooted<ExternRef>> { 555 let mut store = AutoAssertNoGc::new(store.as_context_mut().0); 556 Self::_from_raw(&mut store, raw) 557 } 558 559 // (Not actually memory unsafe since we have indexed GC heaps.) 560 pub(crate) fn _from_raw(store: &mut AutoAssertNoGc, raw: u32) -> Option<Rooted<ExternRef>> { 561 let gc_ref = VMGcRef::from_raw_u32(raw)?; 562 let gc_ref = store.clone_gc_ref(&gc_ref); 563 Some(Self::from_cloned_gc_ref(store, gc_ref)) 564 } 565 566 /// Converts this [`ExternRef`] to a raw value suitable to store within a 567 /// [`ValRaw`]. 568 /// 569 /// Returns an error if this `externref` has been unrooted. 570 /// 571 /// # Correctness 572 /// 573 /// Produces a raw value which is only valid to pass into a store if a GC 574 /// doesn't happen between when the value is produce and when it's passed 575 /// into the store. 576 /// 577 /// [`ValRaw`]: crate::ValRaw 578 pub fn to_raw(&self, mut store: impl AsContextMut) -> Result<u32> { 579 let mut store = AutoAssertNoGc::new(store.as_context_mut().0); 580 self._to_raw(&mut store) 581 } 582 583 pub(crate) fn _to_raw(&self, store: &mut AutoAssertNoGc) -> Result<u32> { 584 let gc_ref = self.inner.try_clone_gc_ref(store)?; 585 let raw = store.unwrap_gc_store_mut().expose_gc_ref_to_wasm(gc_ref); 586 Ok(raw.get()) 587 } 588 } 589 590 unsafe impl WasmTy for Rooted<ExternRef> { 591 #[inline] 592 fn valtype() -> ValType { 593 ValType::Ref(RefType::new(false, HeapType::Extern)) 594 } 595 596 #[inline] 597 fn compatible_with_store(&self, store: &StoreOpaque) -> bool { 598 self.comes_from_same_store(store) 599 } 600 601 #[inline] 602 fn dynamic_concrete_type_check(&self, _: &StoreOpaque, _: bool, _: &HeapType) -> Result<()> { 603 unreachable!() 604 } 605 606 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> { 607 self.wasm_ty_store(store, ptr, ValRaw::externref) 608 } 609 610 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self { 611 Self::wasm_ty_load(store, ptr.get_externref(), ExternRef::from_cloned_gc_ref) 612 } 613 } 614 615 unsafe impl WasmTy for Option<Rooted<ExternRef>> { 616 #[inline] 617 fn valtype() -> ValType { 618 ValType::EXTERNREF 619 } 620 621 #[inline] 622 fn compatible_with_store(&self, store: &StoreOpaque) -> bool { 623 self.map_or(true, |x| x.comes_from_same_store(store)) 624 } 625 626 #[inline] 627 fn dynamic_concrete_type_check(&self, _: &StoreOpaque, _: bool, _: &HeapType) -> Result<()> { 628 unreachable!() 629 } 630 631 #[inline] 632 fn is_vmgcref_and_points_to_object(&self) -> bool { 633 self.is_some() 634 } 635 636 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> { 637 <Rooted<ExternRef>>::wasm_ty_option_store(self, store, ptr, ValRaw::externref) 638 } 639 640 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self { 641 <Rooted<ExternRef>>::wasm_ty_option_load( 642 store, 643 ptr.get_externref(), 644 ExternRef::from_cloned_gc_ref, 645 ) 646 } 647 } 648 649 unsafe impl WasmTy for OwnedRooted<ExternRef> { 650 #[inline] 651 fn valtype() -> ValType { 652 ValType::Ref(RefType::new(false, HeapType::Extern)) 653 } 654 655 #[inline] 656 fn compatible_with_store(&self, store: &StoreOpaque) -> bool { 657 self.comes_from_same_store(store) 658 } 659 660 #[inline] 661 fn dynamic_concrete_type_check(&self, _: &StoreOpaque, _: bool, _: &HeapType) -> Result<()> { 662 unreachable!() 663 } 664 665 #[inline] 666 fn is_vmgcref_and_points_to_object(&self) -> bool { 667 true 668 } 669 670 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> { 671 self.wasm_ty_store(store, ptr, ValRaw::externref) 672 } 673 674 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self { 675 Self::wasm_ty_load(store, ptr.get_externref(), ExternRef::from_cloned_gc_ref) 676 } 677 } 678 679 unsafe impl WasmTy for Option<OwnedRooted<ExternRef>> { 680 #[inline] 681 fn valtype() -> ValType { 682 ValType::EXTERNREF 683 } 684 685 #[inline] 686 fn compatible_with_store(&self, store: &StoreOpaque) -> bool { 687 self.as_ref() 688 .map_or(true, |x| x.comes_from_same_store(store)) 689 } 690 691 #[inline] 692 fn dynamic_concrete_type_check(&self, _: &StoreOpaque, _: bool, _: &HeapType) -> Result<()> { 693 unreachable!() 694 } 695 696 #[inline] 697 fn is_vmgcref_and_points_to_object(&self) -> bool { 698 self.is_some() 699 } 700 701 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> { 702 <OwnedRooted<ExternRef>>::wasm_ty_option_store(self, store, ptr, ValRaw::externref) 703 } 704 705 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self { 706 <OwnedRooted<ExternRef>>::wasm_ty_option_load( 707 store, 708 ptr.get_externref(), 709 ExternRef::from_cloned_gc_ref, 710 ) 711 } 712 } 713