1f2e689cdSNick Fitzgerald //! Working with GC `struct` objects. 2f2e689cdSNick Fitzgerald 3f2e689cdSNick Fitzgerald use crate::runtime::vm::VMGcRef; 4cc8d04f4SAlex Crichton use crate::store::{Asyncness, StoreId}; 5cc8d04f4SAlex Crichton #[cfg(feature = "async")] 6cc8d04f4SAlex Crichton use crate::vm::VMStore; 7cc8d04f4SAlex Crichton use crate::vm::{self, VMGcHeader, VMStructRef}; 890ac295eSAlex Crichton use crate::{AnyRef, FieldType}; 9f2e689cdSNick Fitzgerald use crate::{ 10c16414fbSNick Fitzgerald AsContext, AsContextMut, EqRef, GcHeapOutOfMemory, GcRefImpl, GcRootIndex, HeapType, 119826719aSChris Fallin OwnedRooted, RefType, Rooted, StructType, Val, ValRaw, ValType, WasmTy, 1290ac295eSAlex Crichton prelude::*, 13155ea7fcSAlex Crichton store::{AutoAssertNoGc, StoreContextMut, StoreOpaque, StoreResourceLimiter}, 14f2e689cdSNick Fitzgerald }; 15*735bc9c0SNick Fitzgerald use alloc::sync::Arc; 16f2e689cdSNick Fitzgerald use core::mem::{self, MaybeUninit}; 179c23d884SNick Fitzgerald use wasmtime_environ::{GcLayout, GcStructLayout, VMGcKind, VMSharedTypeIndex}; 18f2e689cdSNick Fitzgerald 19f2e689cdSNick Fitzgerald /// An allocator for a particular Wasm GC struct type. 20f2e689cdSNick Fitzgerald /// 21f2e689cdSNick Fitzgerald /// Every `StructRefPre` is associated with a particular 22f2e689cdSNick Fitzgerald /// [`Store`][crate::Store] and a particular [StructType][crate::StructType]. 23f2e689cdSNick Fitzgerald /// 24f2e689cdSNick Fitzgerald /// Reusing an allocator across many allocations amortizes some per-type runtime 25f2e689cdSNick Fitzgerald /// overheads inside Wasmtime. A `StructRefPre` is to `StructRef`s as an 26f2e689cdSNick Fitzgerald /// `InstancePre` is to `Instance`s. 27f2e689cdSNick Fitzgerald /// 28f2e689cdSNick Fitzgerald /// # Example 29f2e689cdSNick Fitzgerald /// 30f2e689cdSNick Fitzgerald /// ``` 31f2e689cdSNick Fitzgerald /// use wasmtime::*; 32f2e689cdSNick Fitzgerald /// 33f2e689cdSNick Fitzgerald /// # fn foo() -> Result<()> { 34f2e689cdSNick Fitzgerald /// let mut config = Config::new(); 35f2e689cdSNick Fitzgerald /// config.wasm_function_references(true); 36f2e689cdSNick Fitzgerald /// config.wasm_gc(true); 37f2e689cdSNick Fitzgerald /// 38f2e689cdSNick Fitzgerald /// let engine = Engine::new(&config)?; 39f2e689cdSNick Fitzgerald /// let mut store = Store::new(&engine, ()); 40f2e689cdSNick Fitzgerald /// 41f2e689cdSNick Fitzgerald /// // Define a struct type. 42f2e689cdSNick Fitzgerald /// let struct_ty = StructType::new( 43f2e689cdSNick Fitzgerald /// store.engine(), 44f2e689cdSNick Fitzgerald /// [FieldType::new(Mutability::Var, StorageType::I8)], 45f2e689cdSNick Fitzgerald /// )?; 46f2e689cdSNick Fitzgerald /// 47f2e689cdSNick Fitzgerald /// // Create an allocator for the struct type. 48f2e689cdSNick Fitzgerald /// let allocator = StructRefPre::new(&mut store, struct_ty); 49f2e689cdSNick Fitzgerald /// 50f2e689cdSNick Fitzgerald /// { 51f2e689cdSNick Fitzgerald /// let mut scope = RootScope::new(&mut store); 52f2e689cdSNick Fitzgerald /// 53f2e689cdSNick Fitzgerald /// // Allocate a bunch of instances of our struct type using the same 54f2e689cdSNick Fitzgerald /// // allocator! This is faster than creating a new allocator for each 55f2e689cdSNick Fitzgerald /// // instance we want to allocate. 56f2e689cdSNick Fitzgerald /// for i in 0..10 { 57f2e689cdSNick Fitzgerald /// StructRef::new(&mut scope, &allocator, &[Val::I32(i)])?; 58f2e689cdSNick Fitzgerald /// } 59f2e689cdSNick Fitzgerald /// } 60f2e689cdSNick Fitzgerald /// # Ok(()) 61f2e689cdSNick Fitzgerald /// # } 62f2e689cdSNick Fitzgerald /// # foo().unwrap(); 63f2e689cdSNick Fitzgerald /// ``` 64f2e689cdSNick Fitzgerald pub struct StructRefPre { 65f2e689cdSNick Fitzgerald store_id: StoreId, 66f2e689cdSNick Fitzgerald ty: StructType, 67f2e689cdSNick Fitzgerald } 68f2e689cdSNick Fitzgerald 69f2e689cdSNick Fitzgerald impl StructRefPre { 70f2e689cdSNick Fitzgerald /// Create a new `StructRefPre` that is associated with the given store 71f2e689cdSNick Fitzgerald /// and type. new(mut store: impl AsContextMut, ty: StructType) -> Self72f2e689cdSNick Fitzgerald pub fn new(mut store: impl AsContextMut, ty: StructType) -> Self { 73f2e689cdSNick Fitzgerald Self::_new(store.as_context_mut().0, ty) 74f2e689cdSNick Fitzgerald } 75f2e689cdSNick Fitzgerald _new(store: &mut StoreOpaque, ty: StructType) -> Self76f2e689cdSNick Fitzgerald pub(crate) fn _new(store: &mut StoreOpaque, ty: StructType) -> Self { 77f2e689cdSNick Fitzgerald store.insert_gc_host_alloc_type(ty.registered_type().clone()); 78f2e689cdSNick Fitzgerald let store_id = store.id(); 79f2e689cdSNick Fitzgerald 80f2e689cdSNick Fitzgerald StructRefPre { store_id, ty } 81f2e689cdSNick Fitzgerald } 82f2e689cdSNick Fitzgerald layout(&self) -> &GcStructLayout83f2e689cdSNick Fitzgerald pub(crate) fn layout(&self) -> &GcStructLayout { 84f2e689cdSNick Fitzgerald self.ty 85f2e689cdSNick Fitzgerald .registered_type() 86f2e689cdSNick Fitzgerald .layout() 87f2e689cdSNick Fitzgerald .expect("struct types have a layout") 88f2e689cdSNick Fitzgerald .unwrap_struct() 89f2e689cdSNick Fitzgerald } 90f2e689cdSNick Fitzgerald type_index(&self) -> VMSharedTypeIndex91f2e689cdSNick Fitzgerald pub(crate) fn type_index(&self) -> VMSharedTypeIndex { 92f2e689cdSNick Fitzgerald self.ty.registered_type().index() 93f2e689cdSNick Fitzgerald } 94f2e689cdSNick Fitzgerald } 95f2e689cdSNick Fitzgerald 96f2e689cdSNick Fitzgerald /// A reference to a GC-managed `struct` instance. 97f2e689cdSNick Fitzgerald /// 98f2e689cdSNick Fitzgerald /// WebAssembly `struct`s are static, fixed-length, ordered sequences of 99f2e689cdSNick Fitzgerald /// fields. Fields are named by index, not by identifier; in this way, they are 100f2e689cdSNick Fitzgerald /// similar to Rust's tuples. Each field is mutable or constant and stores 101f2e689cdSNick Fitzgerald /// unpacked [`Val`][crate::Val]s or packed 8-/16-bit integers. 102f2e689cdSNick Fitzgerald /// 103f2e689cdSNick Fitzgerald /// Like all WebAssembly references, these are opaque and unforgeable to Wasm: 104f2e689cdSNick Fitzgerald /// they cannot be faked and Wasm cannot, for example, cast the integer 105f2e689cdSNick Fitzgerald /// `0x12345678` into a reference, pretend it is a valid `structref`, and trick 106f2e689cdSNick Fitzgerald /// the host into dereferencing it and segfaulting or worse. 107f2e689cdSNick Fitzgerald /// 108f2e689cdSNick Fitzgerald /// Note that you can also use `Rooted<StructRef>` and 1099826719aSChris Fallin /// `OwnedRooted<StructRef>` as a type parameter with 110f2e689cdSNick Fitzgerald /// [`Func::typed`][crate::Func::typed]- and 111f2e689cdSNick Fitzgerald /// [`Func::wrap`][crate::Func::wrap]-style APIs. 112f2e689cdSNick Fitzgerald /// 113f2e689cdSNick Fitzgerald /// # Example 114f2e689cdSNick Fitzgerald /// 115f2e689cdSNick Fitzgerald /// ``` 116f2e689cdSNick Fitzgerald /// use wasmtime::*; 117f2e689cdSNick Fitzgerald /// 118f2e689cdSNick Fitzgerald /// # fn foo() -> Result<()> { 119f2e689cdSNick Fitzgerald /// let mut config = Config::new(); 120f2e689cdSNick Fitzgerald /// config.wasm_function_references(true); 121f2e689cdSNick Fitzgerald /// config.wasm_gc(true); 122f2e689cdSNick Fitzgerald /// 123f2e689cdSNick Fitzgerald /// let engine = Engine::new(&config)?; 124f2e689cdSNick Fitzgerald /// let mut store = Store::new(&engine, ()); 125f2e689cdSNick Fitzgerald /// 126f2e689cdSNick Fitzgerald /// // Define a struct type. 127f2e689cdSNick Fitzgerald /// let struct_ty = StructType::new( 128f2e689cdSNick Fitzgerald /// store.engine(), 129f2e689cdSNick Fitzgerald /// [FieldType::new(Mutability::Var, StorageType::I8)], 130f2e689cdSNick Fitzgerald /// )?; 131f2e689cdSNick Fitzgerald /// 132f2e689cdSNick Fitzgerald /// // Create an allocator for the struct type. 133f2e689cdSNick Fitzgerald /// let allocator = StructRefPre::new(&mut store, struct_ty); 134f2e689cdSNick Fitzgerald /// 135f2e689cdSNick Fitzgerald /// { 136f2e689cdSNick Fitzgerald /// let mut scope = RootScope::new(&mut store); 137f2e689cdSNick Fitzgerald /// 138f2e689cdSNick Fitzgerald /// // Allocate an instance of the struct type. 13907c71ab5SNick Fitzgerald /// let my_struct = StructRef::new(&mut scope, &allocator, &[Val::I32(42)])?; 140f2e689cdSNick Fitzgerald /// 141f2e689cdSNick Fitzgerald /// // That instance's field should have the expected value. 142f2e689cdSNick Fitzgerald /// let val = my_struct.field(&mut scope, 0)?.unwrap_i32(); 143f2e689cdSNick Fitzgerald /// assert_eq!(val, 42); 144f2e689cdSNick Fitzgerald /// 145f2e689cdSNick Fitzgerald /// // And we can update the field's value because it is a mutable field. 146f2e689cdSNick Fitzgerald /// my_struct.set_field(&mut scope, 0, Val::I32(36))?; 147f2e689cdSNick Fitzgerald /// let new_val = my_struct.field(&mut scope, 0)?.unwrap_i32(); 148f2e689cdSNick Fitzgerald /// assert_eq!(new_val, 36); 149f2e689cdSNick Fitzgerald /// } 150f2e689cdSNick Fitzgerald /// # Ok(()) 151f2e689cdSNick Fitzgerald /// # } 152f2e689cdSNick Fitzgerald /// # foo().unwrap(); 153f2e689cdSNick Fitzgerald /// ``` 154f2e689cdSNick Fitzgerald #[derive(Debug)] 155f2e689cdSNick Fitzgerald #[repr(transparent)] 156f2e689cdSNick Fitzgerald pub struct StructRef { 157f2e689cdSNick Fitzgerald pub(super) inner: GcRootIndex, 158f2e689cdSNick Fitzgerald } 159f2e689cdSNick Fitzgerald 160f2e689cdSNick Fitzgerald unsafe impl GcRefImpl for StructRef { transmute_ref(index: &GcRootIndex) -> &Self161f2e689cdSNick Fitzgerald fn transmute_ref(index: &GcRootIndex) -> &Self { 162f2e689cdSNick Fitzgerald // Safety: `StructRef` is a newtype of a `GcRootIndex`. 163f2e689cdSNick Fitzgerald let me: &Self = unsafe { mem::transmute(index) }; 164f2e689cdSNick Fitzgerald 165f2e689cdSNick Fitzgerald // Assert we really are just a newtype of a `GcRootIndex`. 166f2e689cdSNick Fitzgerald assert!(matches!( 167f2e689cdSNick Fitzgerald me, 168f2e689cdSNick Fitzgerald Self { 169f2e689cdSNick Fitzgerald inner: GcRootIndex { .. }, 170f2e689cdSNick Fitzgerald } 171f2e689cdSNick Fitzgerald )); 172f2e689cdSNick Fitzgerald 173f2e689cdSNick Fitzgerald me 174f2e689cdSNick Fitzgerald } 175f2e689cdSNick Fitzgerald } 176f2e689cdSNick Fitzgerald 177f2e689cdSNick Fitzgerald impl Rooted<StructRef> { 178f2e689cdSNick Fitzgerald /// Upcast this `structref` into an `anyref`. 179f2e689cdSNick Fitzgerald #[inline] to_anyref(self) -> Rooted<AnyRef>180f2e689cdSNick Fitzgerald pub fn to_anyref(self) -> Rooted<AnyRef> { 181f2e689cdSNick Fitzgerald self.unchecked_cast() 182f2e689cdSNick Fitzgerald } 183c16414fbSNick Fitzgerald 184c16414fbSNick Fitzgerald /// Upcast this `structref` into an `eqref`. 185c16414fbSNick Fitzgerald #[inline] to_eqref(self) -> Rooted<EqRef>186c16414fbSNick Fitzgerald pub fn to_eqref(self) -> Rooted<EqRef> { 187c16414fbSNick Fitzgerald self.unchecked_cast() 188c16414fbSNick Fitzgerald } 189f2e689cdSNick Fitzgerald } 190f2e689cdSNick Fitzgerald 1919826719aSChris Fallin impl OwnedRooted<StructRef> { 192f2e689cdSNick Fitzgerald /// Upcast this `structref` into an `anyref`. 193f2e689cdSNick Fitzgerald #[inline] to_anyref(self) -> OwnedRooted<AnyRef>1949826719aSChris Fallin pub fn to_anyref(self) -> OwnedRooted<AnyRef> { 195f2e689cdSNick Fitzgerald self.unchecked_cast() 196f2e689cdSNick Fitzgerald } 197c16414fbSNick Fitzgerald 198c16414fbSNick Fitzgerald /// Upcast this `structref` into an `eqref`. 199c16414fbSNick Fitzgerald #[inline] to_eqref(self) -> OwnedRooted<EqRef>2009826719aSChris Fallin pub fn to_eqref(self) -> OwnedRooted<EqRef> { 201c16414fbSNick Fitzgerald self.unchecked_cast() 202c16414fbSNick Fitzgerald } 203f2e689cdSNick Fitzgerald } 204f2e689cdSNick Fitzgerald 205f2e689cdSNick Fitzgerald impl StructRef { 20607c71ab5SNick Fitzgerald /// Synchronously allocate a new `struct` and get a reference to it. 20707c71ab5SNick Fitzgerald /// 20807c71ab5SNick Fitzgerald /// # Automatic Garbage Collection 20907c71ab5SNick Fitzgerald /// 21007c71ab5SNick Fitzgerald /// If the GC heap is at capacity, and there isn't room for allocating this 21107c71ab5SNick Fitzgerald /// new struct, then this method will automatically trigger a synchronous 21207c71ab5SNick Fitzgerald /// collection in an attempt to free up space in the GC heap. 213f2e689cdSNick Fitzgerald /// 214f2e689cdSNick Fitzgerald /// # Errors 215f2e689cdSNick Fitzgerald /// 216f2e689cdSNick Fitzgerald /// If the given `fields` values' types do not match the field types of the 217f2e689cdSNick Fitzgerald /// `allocator`'s struct type, an error is returned. 218f2e689cdSNick Fitzgerald /// 219f2e689cdSNick Fitzgerald /// If the allocation cannot be satisfied because the GC heap is currently 22007c71ab5SNick Fitzgerald /// out of memory, then a [`GcHeapOutOfMemory<()>`][crate::GcHeapOutOfMemory] 22107c71ab5SNick Fitzgerald /// error is returned. The allocation might succeed on a second attempt if 22207c71ab5SNick Fitzgerald /// you drop some rooted GC references and try again. 223f2e689cdSNick Fitzgerald /// 224cc8d04f4SAlex Crichton /// If `store` is configured with a 225cc8d04f4SAlex Crichton /// [`ResourceLimiterAsync`](crate::ResourceLimiterAsync) then an error 226cc8d04f4SAlex Crichton /// will be returned because [`StructRef::new_async`] should be used 227cc8d04f4SAlex Crichton /// instead. 228f2e689cdSNick Fitzgerald /// 229cc8d04f4SAlex Crichton /// # Panics 23007c71ab5SNick Fitzgerald /// 231f2e689cdSNick Fitzgerald /// Panics if the allocator, or any of the field values, is not associated 232f2e689cdSNick Fitzgerald /// with the given store. new( mut store: impl AsContextMut, allocator: &StructRefPre, fields: &[Val], ) -> Result<Rooted<StructRef>>233f2e689cdSNick Fitzgerald pub fn new( 234f2e689cdSNick Fitzgerald mut store: impl AsContextMut, 235f2e689cdSNick Fitzgerald allocator: &StructRefPre, 236f2e689cdSNick Fitzgerald fields: &[Val], 237f2e689cdSNick Fitzgerald ) -> Result<Rooted<StructRef>> { 238cc8d04f4SAlex Crichton let (mut limiter, store) = store 239cc8d04f4SAlex Crichton .as_context_mut() 240cc8d04f4SAlex Crichton .0 241cc8d04f4SAlex Crichton .validate_sync_resource_limiter_and_store_opaque()?; 242cc8d04f4SAlex Crichton vm::assert_ready(Self::_new_async( 243cc8d04f4SAlex Crichton store, 244cc8d04f4SAlex Crichton limiter.as_mut(), 245cc8d04f4SAlex Crichton allocator, 246cc8d04f4SAlex Crichton fields, 247cc8d04f4SAlex Crichton Asyncness::No, 248cc8d04f4SAlex Crichton )) 24907c71ab5SNick Fitzgerald } 250f2e689cdSNick Fitzgerald 25107c71ab5SNick Fitzgerald /// Asynchronously allocate a new `struct` and get a reference to it. 25207c71ab5SNick Fitzgerald /// 25307c71ab5SNick Fitzgerald /// # Automatic Garbage Collection 25407c71ab5SNick Fitzgerald /// 25507c71ab5SNick Fitzgerald /// If the GC heap is at capacity, and there isn't room for allocating this 25607c71ab5SNick Fitzgerald /// new struct, then this method will automatically trigger a synchronous 25707c71ab5SNick Fitzgerald /// collection in an attempt to free up space in the GC heap. 25807c71ab5SNick Fitzgerald /// 25907c71ab5SNick Fitzgerald /// # Errors 26007c71ab5SNick Fitzgerald /// 26107c71ab5SNick Fitzgerald /// If the given `fields` values' types do not match the field types of the 26207c71ab5SNick Fitzgerald /// `allocator`'s struct type, an error is returned. 26307c71ab5SNick Fitzgerald /// 26407c71ab5SNick Fitzgerald /// If the allocation cannot be satisfied because the GC heap is currently 26507c71ab5SNick Fitzgerald /// out of memory, then a [`GcHeapOutOfMemory<()>`][crate::GcHeapOutOfMemory] 26607c71ab5SNick Fitzgerald /// error is returned. The allocation might succeed on a second attempt if 26707c71ab5SNick Fitzgerald /// you drop some rooted GC references and try again. 26807c71ab5SNick Fitzgerald /// 26907c71ab5SNick Fitzgerald /// # Panics 27007c71ab5SNick Fitzgerald /// 27107c71ab5SNick Fitzgerald /// Panics if the allocator, or any of the field values, is not associated 27207c71ab5SNick Fitzgerald /// with the given store. 27307c71ab5SNick Fitzgerald #[cfg(feature = "async")] new_async( mut store: impl AsContextMut, allocator: &StructRefPre, fields: &[Val], ) -> Result<Rooted<StructRef>>27407c71ab5SNick Fitzgerald pub async fn new_async( 27507c71ab5SNick Fitzgerald mut store: impl AsContextMut, 27607c71ab5SNick Fitzgerald allocator: &StructRefPre, 27707c71ab5SNick Fitzgerald fields: &[Val], 27807c71ab5SNick Fitzgerald ) -> Result<Rooted<StructRef>> { 279155ea7fcSAlex Crichton let (mut limiter, store) = store.as_context_mut().0.resource_limiter_and_store_opaque(); 280cc8d04f4SAlex Crichton Self::_new_async(store, limiter.as_mut(), allocator, fields, Asyncness::Yes).await 28107c71ab5SNick Fitzgerald } 28207c71ab5SNick Fitzgerald _new_async( store: &mut StoreOpaque, limiter: Option<&mut StoreResourceLimiter<'_>>, allocator: &StructRefPre, fields: &[Val], asyncness: Asyncness, ) -> Result<Rooted<StructRef>>28307c71ab5SNick Fitzgerald pub(crate) async fn _new_async( 28407c71ab5SNick Fitzgerald store: &mut StoreOpaque, 285155ea7fcSAlex Crichton limiter: Option<&mut StoreResourceLimiter<'_>>, 28607c71ab5SNick Fitzgerald allocator: &StructRefPre, 28707c71ab5SNick Fitzgerald fields: &[Val], 288cc8d04f4SAlex Crichton asyncness: Asyncness, 28907c71ab5SNick Fitzgerald ) -> Result<Rooted<StructRef>> { 29007c71ab5SNick Fitzgerald Self::type_check_fields(store, allocator, fields)?; 29107c71ab5SNick Fitzgerald store 292cc8d04f4SAlex Crichton .retry_after_gc_async(limiter, (), asyncness, |store, ()| { 29307c71ab5SNick Fitzgerald Self::new_unchecked(store, allocator, fields) 29407c71ab5SNick Fitzgerald }) 29507c71ab5SNick Fitzgerald .await 29607c71ab5SNick Fitzgerald } 29707c71ab5SNick Fitzgerald 29807c71ab5SNick Fitzgerald /// Type check the field values before allocating a new struct. type_check_fields( store: &mut StoreOpaque, allocator: &StructRefPre, fields: &[Val], ) -> Result<(), Error>29907c71ab5SNick Fitzgerald fn type_check_fields( 30007c71ab5SNick Fitzgerald store: &mut StoreOpaque, 30107c71ab5SNick Fitzgerald allocator: &StructRefPre, 30207c71ab5SNick Fitzgerald fields: &[Val], 30307c71ab5SNick Fitzgerald ) -> Result<(), Error> { 304f2e689cdSNick Fitzgerald let expected_len = allocator.ty.fields().len(); 305f2e689cdSNick Fitzgerald let actual_len = fields.len(); 306f2e689cdSNick Fitzgerald ensure!( 307f2e689cdSNick Fitzgerald actual_len == expected_len, 308f2e689cdSNick Fitzgerald "expected {expected_len} fields, got {actual_len}" 309f2e689cdSNick Fitzgerald ); 310f2e689cdSNick Fitzgerald for (ty, val) in allocator.ty.fields().zip(fields) { 311f2e689cdSNick Fitzgerald assert!( 312f2e689cdSNick Fitzgerald val.comes_from_same_store(store), 313f2e689cdSNick Fitzgerald "field value comes from the wrong store", 314f2e689cdSNick Fitzgerald ); 315f2e689cdSNick Fitzgerald let ty = ty.element_type().unpack(); 316f2e689cdSNick Fitzgerald val.ensure_matches_ty(store, ty) 317f2e689cdSNick Fitzgerald .context("field type mismatch")?; 318f2e689cdSNick Fitzgerald } 31907c71ab5SNick Fitzgerald Ok(()) 32007c71ab5SNick Fitzgerald } 32107c71ab5SNick Fitzgerald 32207c71ab5SNick Fitzgerald /// Given that the field values have already been type checked, allocate a 32307c71ab5SNick Fitzgerald /// new struct. 32407c71ab5SNick Fitzgerald /// 32507c71ab5SNick Fitzgerald /// Does not attempt GC+retry on OOM, that is the caller's responsibility. new_unchecked( store: &mut StoreOpaque, allocator: &StructRefPre, fields: &[Val], ) -> Result<Rooted<StructRef>>32607c71ab5SNick Fitzgerald fn new_unchecked( 32707c71ab5SNick Fitzgerald store: &mut StoreOpaque, 32807c71ab5SNick Fitzgerald allocator: &StructRefPre, 32907c71ab5SNick Fitzgerald fields: &[Val], 33007c71ab5SNick Fitzgerald ) -> Result<Rooted<StructRef>> { 33107c71ab5SNick Fitzgerald assert_eq!( 33207c71ab5SNick Fitzgerald store.id(), 33307c71ab5SNick Fitzgerald allocator.store_id, 33407c71ab5SNick Fitzgerald "attempted to use a `StructRefPre` with the wrong store" 33507c71ab5SNick Fitzgerald ); 336f2e689cdSNick Fitzgerald 337f2e689cdSNick Fitzgerald // Allocate the struct and write each field value into the appropriate 338f2e689cdSNick Fitzgerald // offset. 339f2e689cdSNick Fitzgerald let structref = store 340c6dddeafSAlex Crichton .require_gc_store_mut()? 341f2e689cdSNick Fitzgerald .alloc_uninit_struct(allocator.type_index(), &allocator.layout()) 342f2e689cdSNick Fitzgerald .context("unrecoverable error when allocating new `structref`")? 343c22b3cb9SNick Fitzgerald .map_err(|n| GcHeapOutOfMemory::new((), n))?; 344f2e689cdSNick Fitzgerald 345f2e689cdSNick Fitzgerald // From this point on, if we get any errors, then the struct is not 346f2e689cdSNick Fitzgerald // fully initialized, so we need to eagerly deallocate it before the 347f2e689cdSNick Fitzgerald // next GC where the collector might try to interpret one of the 348f2e689cdSNick Fitzgerald // uninitialized fields as a GC reference. 349f2e689cdSNick Fitzgerald let mut store = AutoAssertNoGc::new(store); 350f2e689cdSNick Fitzgerald match (|| { 351f2e689cdSNick Fitzgerald for (index, (ty, val)) in allocator.ty.fields().zip(fields).enumerate() { 352f2e689cdSNick Fitzgerald structref.initialize_field( 353f2e689cdSNick Fitzgerald &mut store, 354f2e689cdSNick Fitzgerald allocator.layout(), 355f2e689cdSNick Fitzgerald ty.element_type(), 356f2e689cdSNick Fitzgerald index, 3570c0153c1SNick Fitzgerald *val, 358f2e689cdSNick Fitzgerald )?; 359f2e689cdSNick Fitzgerald } 360f2e689cdSNick Fitzgerald Ok(()) 361f2e689cdSNick Fitzgerald })() { 362f2e689cdSNick Fitzgerald Ok(()) => Ok(Rooted::new(&mut store, structref.into())), 363f2e689cdSNick Fitzgerald Err(e) => { 364c6dddeafSAlex Crichton store 365c6dddeafSAlex Crichton .require_gc_store_mut()? 366c6dddeafSAlex Crichton .dealloc_uninit_struct(structref); 367f2e689cdSNick Fitzgerald Err(e) 368f2e689cdSNick Fitzgerald } 369f2e689cdSNick Fitzgerald } 370f2e689cdSNick Fitzgerald } 371f2e689cdSNick Fitzgerald 372f2e689cdSNick Fitzgerald #[inline] comes_from_same_store(&self, store: &StoreOpaque) -> bool373f2e689cdSNick Fitzgerald pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool { 374f2e689cdSNick Fitzgerald self.inner.comes_from_same_store(store) 375f2e689cdSNick Fitzgerald } 376f2e689cdSNick Fitzgerald 377f2e689cdSNick Fitzgerald /// Get this `structref`'s type. 378f2e689cdSNick Fitzgerald /// 379f2e689cdSNick Fitzgerald /// # Errors 380f2e689cdSNick Fitzgerald /// 381f2e689cdSNick Fitzgerald /// Return an error if this reference has been unrooted. 382f2e689cdSNick Fitzgerald /// 383f2e689cdSNick Fitzgerald /// # Panics 384f2e689cdSNick Fitzgerald /// 385f2e689cdSNick Fitzgerald /// Panics if this reference is associated with a different store. ty(&self, store: impl AsContext) -> Result<StructType>386f2e689cdSNick Fitzgerald pub fn ty(&self, store: impl AsContext) -> Result<StructType> { 387f2e689cdSNick Fitzgerald self._ty(store.as_context().0) 388f2e689cdSNick Fitzgerald } 389f2e689cdSNick Fitzgerald _ty(&self, store: &StoreOpaque) -> Result<StructType>390f2e689cdSNick Fitzgerald pub(crate) fn _ty(&self, store: &StoreOpaque) -> Result<StructType> { 391f2e689cdSNick Fitzgerald assert!(self.comes_from_same_store(store)); 392f2e689cdSNick Fitzgerald let index = self.type_index(store)?; 393f2e689cdSNick Fitzgerald Ok(StructType::from_shared_type_index(store.engine(), index)) 394f2e689cdSNick Fitzgerald } 395f2e689cdSNick Fitzgerald 396f2e689cdSNick Fitzgerald /// Does this `structref` match the given type? 397f2e689cdSNick Fitzgerald /// 398f2e689cdSNick Fitzgerald /// That is, is this struct's type a subtype of the given type? 399f2e689cdSNick Fitzgerald /// 400f2e689cdSNick Fitzgerald /// # Errors 401f2e689cdSNick Fitzgerald /// 402f2e689cdSNick Fitzgerald /// Return an error if this reference has been unrooted. 403f2e689cdSNick Fitzgerald /// 404f2e689cdSNick Fitzgerald /// # Panics 405f2e689cdSNick Fitzgerald /// 406f2e689cdSNick Fitzgerald /// Panics if this reference is associated with a different store or if the 407f2e689cdSNick Fitzgerald /// type is not associated with the store's engine. matches_ty(&self, store: impl AsContext, ty: &StructType) -> Result<bool>408f2e689cdSNick Fitzgerald pub fn matches_ty(&self, store: impl AsContext, ty: &StructType) -> Result<bool> { 409f2e689cdSNick Fitzgerald self._matches_ty(store.as_context().0, ty) 410f2e689cdSNick Fitzgerald } 411f2e689cdSNick Fitzgerald _matches_ty(&self, store: &StoreOpaque, ty: &StructType) -> Result<bool>412f2e689cdSNick Fitzgerald pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &StructType) -> Result<bool> { 413f2e689cdSNick Fitzgerald assert!(self.comes_from_same_store(store)); 414f2e689cdSNick Fitzgerald Ok(self._ty(store)?.matches(ty)) 415f2e689cdSNick Fitzgerald } 416f2e689cdSNick Fitzgerald ensure_matches_ty(&self, store: &StoreOpaque, ty: &StructType) -> Result<()>417f2e689cdSNick Fitzgerald pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &StructType) -> Result<()> { 418f2e689cdSNick Fitzgerald if !self.comes_from_same_store(store) { 419f2e689cdSNick Fitzgerald bail!("function used with wrong store"); 420f2e689cdSNick Fitzgerald } 421f2e689cdSNick Fitzgerald if self._matches_ty(store, ty)? { 422f2e689cdSNick Fitzgerald Ok(()) 423f2e689cdSNick Fitzgerald } else { 424f2e689cdSNick Fitzgerald let actual_ty = self._ty(store)?; 425f2e689cdSNick Fitzgerald bail!("type mismatch: expected `(ref {ty})`, found `(ref {actual_ty})`") 426f2e689cdSNick Fitzgerald } 427f2e689cdSNick Fitzgerald } 428f2e689cdSNick Fitzgerald 429f2e689cdSNick Fitzgerald /// Get the values of this struct's fields. 430f2e689cdSNick Fitzgerald /// 431f2e689cdSNick Fitzgerald /// Note that `i8` and `i16` field values are zero-extended into 432f2e689cdSNick Fitzgerald /// `Val::I32(_)`s. 433f2e689cdSNick Fitzgerald /// 434f2e689cdSNick Fitzgerald /// # Errors 435f2e689cdSNick Fitzgerald /// 436f2e689cdSNick Fitzgerald /// Return an error if this reference has been unrooted. 437f2e689cdSNick Fitzgerald /// 438f2e689cdSNick Fitzgerald /// # Panics 439f2e689cdSNick Fitzgerald /// 440f2e689cdSNick Fitzgerald /// Panics if this reference is associated with a different store. fields<'a, T: 'static>( &'a self, store: impl Into<StoreContextMut<'a, T>>, ) -> Result<impl ExactSizeIterator<Item = Val> + 'a>441f81c0dc0SAlex Crichton pub fn fields<'a, T: 'static>( 442f2e689cdSNick Fitzgerald &'a self, 443f2e689cdSNick Fitzgerald store: impl Into<StoreContextMut<'a, T>>, 444f2e689cdSNick Fitzgerald ) -> Result<impl ExactSizeIterator<Item = Val> + 'a> { 445f2e689cdSNick Fitzgerald self._fields(store.into().0) 446f2e689cdSNick Fitzgerald } 447f2e689cdSNick Fitzgerald _fields<'a>( &'a self, store: &'a mut StoreOpaque, ) -> Result<impl ExactSizeIterator<Item = Val> + 'a>448f2e689cdSNick Fitzgerald pub(crate) fn _fields<'a>( 449f2e689cdSNick Fitzgerald &'a self, 450f2e689cdSNick Fitzgerald store: &'a mut StoreOpaque, 451f2e689cdSNick Fitzgerald ) -> Result<impl ExactSizeIterator<Item = Val> + 'a> { 452f2e689cdSNick Fitzgerald assert!(self.comes_from_same_store(store)); 453f2e689cdSNick Fitzgerald let store = AutoAssertNoGc::new(store); 454f2e689cdSNick Fitzgerald 455f2e689cdSNick Fitzgerald let gc_ref = self.inner.try_gc_ref(&store)?; 456c6dddeafSAlex Crichton let header = store.require_gc_store()?.header(gc_ref); 457f2e689cdSNick Fitzgerald debug_assert!(header.kind().matches(VMGcKind::StructRef)); 458f2e689cdSNick Fitzgerald 459f2e689cdSNick Fitzgerald let index = header.ty().expect("structrefs should have concrete types"); 460f2e689cdSNick Fitzgerald let ty = StructType::from_shared_type_index(store.engine(), index); 461f2e689cdSNick Fitzgerald let len = ty.fields().len(); 462f2e689cdSNick Fitzgerald 463f2e689cdSNick Fitzgerald return Ok(Fields { 464f2e689cdSNick Fitzgerald structref: self, 465f2e689cdSNick Fitzgerald store, 466f2e689cdSNick Fitzgerald index: 0, 467f2e689cdSNick Fitzgerald len, 468f2e689cdSNick Fitzgerald }); 469f2e689cdSNick Fitzgerald 470f2e689cdSNick Fitzgerald struct Fields<'a, 'b> { 471f2e689cdSNick Fitzgerald structref: &'a StructRef, 472f2e689cdSNick Fitzgerald store: AutoAssertNoGc<'b>, 473f2e689cdSNick Fitzgerald index: usize, 474f2e689cdSNick Fitzgerald len: usize, 475f2e689cdSNick Fitzgerald } 476f2e689cdSNick Fitzgerald 477f2e689cdSNick Fitzgerald impl Iterator for Fields<'_, '_> { 478f2e689cdSNick Fitzgerald type Item = Val; 479f2e689cdSNick Fitzgerald 480f2e689cdSNick Fitzgerald #[inline] 481f2e689cdSNick Fitzgerald fn next(&mut self) -> Option<Self::Item> { 482f2e689cdSNick Fitzgerald let i = self.index; 483f2e689cdSNick Fitzgerald debug_assert!(i <= self.len); 484f2e689cdSNick Fitzgerald if i >= self.len { 485f2e689cdSNick Fitzgerald return None; 486f2e689cdSNick Fitzgerald } 487f2e689cdSNick Fitzgerald self.index += 1; 488f2e689cdSNick Fitzgerald Some(self.structref._field(&mut self.store, i).unwrap()) 489f2e689cdSNick Fitzgerald } 490f2e689cdSNick Fitzgerald 491f2e689cdSNick Fitzgerald #[inline] 492f2e689cdSNick Fitzgerald fn size_hint(&self) -> (usize, Option<usize>) { 493f2e689cdSNick Fitzgerald let len = self.len - self.index; 494f2e689cdSNick Fitzgerald (len, Some(len)) 495f2e689cdSNick Fitzgerald } 496f2e689cdSNick Fitzgerald } 497f2e689cdSNick Fitzgerald 498f2e689cdSNick Fitzgerald impl ExactSizeIterator for Fields<'_, '_> { 499f2e689cdSNick Fitzgerald #[inline] 500f2e689cdSNick Fitzgerald fn len(&self) -> usize { 501f2e689cdSNick Fitzgerald self.len - self.index 502f2e689cdSNick Fitzgerald } 503f2e689cdSNick Fitzgerald } 504f2e689cdSNick Fitzgerald } 505f2e689cdSNick Fitzgerald header<'a>(&self, store: &'a AutoAssertNoGc<'_>) -> Result<&'a VMGcHeader>506f2e689cdSNick Fitzgerald fn header<'a>(&self, store: &'a AutoAssertNoGc<'_>) -> Result<&'a VMGcHeader> { 507f2e689cdSNick Fitzgerald assert!(self.comes_from_same_store(&store)); 508f2e689cdSNick Fitzgerald let gc_ref = self.inner.try_gc_ref(store)?; 509c6dddeafSAlex Crichton Ok(store.require_gc_store()?.header(gc_ref)) 510f2e689cdSNick Fitzgerald } 511f2e689cdSNick Fitzgerald structref<'a>(&self, store: &'a AutoAssertNoGc<'_>) -> Result<&'a VMStructRef>512f2e689cdSNick Fitzgerald fn structref<'a>(&self, store: &'a AutoAssertNoGc<'_>) -> Result<&'a VMStructRef> { 513f2e689cdSNick Fitzgerald assert!(self.comes_from_same_store(&store)); 514f2e689cdSNick Fitzgerald let gc_ref = self.inner.try_gc_ref(store)?; 515f2e689cdSNick Fitzgerald debug_assert!(self.header(store)?.kind().matches(VMGcKind::StructRef)); 516f2e689cdSNick Fitzgerald Ok(gc_ref.as_structref_unchecked()) 517f2e689cdSNick Fitzgerald } 518f2e689cdSNick Fitzgerald layout(&self, store: &AutoAssertNoGc<'_>) -> Result<Arc<GcStructLayout>>519*735bc9c0SNick Fitzgerald fn layout(&self, store: &AutoAssertNoGc<'_>) -> Result<Arc<GcStructLayout>> { 520f2e689cdSNick Fitzgerald assert!(self.comes_from_same_store(&store)); 521f2e689cdSNick Fitzgerald let type_index = self.type_index(store)?; 522f2e689cdSNick Fitzgerald let layout = store 523f2e689cdSNick Fitzgerald .engine() 524f2e689cdSNick Fitzgerald .signatures() 525f2e689cdSNick Fitzgerald .layout(type_index) 526f2e689cdSNick Fitzgerald .expect("struct types should have GC layouts"); 527f2e689cdSNick Fitzgerald match layout { 528f2e689cdSNick Fitzgerald GcLayout::Struct(s) => Ok(s), 529f2e689cdSNick Fitzgerald GcLayout::Array(_) => unreachable!(), 530f2e689cdSNick Fitzgerald } 531f2e689cdSNick Fitzgerald } 532f2e689cdSNick Fitzgerald field_ty(&self, store: &StoreOpaque, field: usize) -> Result<FieldType>533f2e689cdSNick Fitzgerald fn field_ty(&self, store: &StoreOpaque, field: usize) -> Result<FieldType> { 534f2e689cdSNick Fitzgerald let ty = self._ty(store)?; 535f2e689cdSNick Fitzgerald match ty.field(field) { 536f2e689cdSNick Fitzgerald Some(f) => Ok(f), 537f2e689cdSNick Fitzgerald None => { 538f2e689cdSNick Fitzgerald let len = ty.fields().len(); 539f2e689cdSNick Fitzgerald bail!("cannot access field {field}: struct only has {len} fields") 540f2e689cdSNick Fitzgerald } 541f2e689cdSNick Fitzgerald } 542f2e689cdSNick Fitzgerald } 543f2e689cdSNick Fitzgerald 544f2e689cdSNick Fitzgerald /// Get this struct's `index`th field. 545f2e689cdSNick Fitzgerald /// 546f2e689cdSNick Fitzgerald /// Note that `i8` and `i16` field values are zero-extended into 547f2e689cdSNick Fitzgerald /// `Val::I32(_)`s. 548f2e689cdSNick Fitzgerald /// 549f2e689cdSNick Fitzgerald /// # Errors 550f2e689cdSNick Fitzgerald /// 551f2e689cdSNick Fitzgerald /// Returns an `Err(_)` if the index is out of bounds or this reference has 552f2e689cdSNick Fitzgerald /// been unrooted. 553f2e689cdSNick Fitzgerald /// 554f2e689cdSNick Fitzgerald /// # Panics 555f2e689cdSNick Fitzgerald /// 556f2e689cdSNick Fitzgerald /// Panics if this reference is associated with a different store. field(&self, mut store: impl AsContextMut, index: usize) -> Result<Val>557f2e689cdSNick Fitzgerald pub fn field(&self, mut store: impl AsContextMut, index: usize) -> Result<Val> { 558f2e689cdSNick Fitzgerald let mut store = AutoAssertNoGc::new(store.as_context_mut().0); 559f2e689cdSNick Fitzgerald self._field(&mut store, index) 560f2e689cdSNick Fitzgerald } 561f2e689cdSNick Fitzgerald _field(&self, store: &mut AutoAssertNoGc<'_>, index: usize) -> Result<Val>562f2e689cdSNick Fitzgerald pub(crate) fn _field(&self, store: &mut AutoAssertNoGc<'_>, index: usize) -> Result<Val> { 563f2e689cdSNick Fitzgerald assert!(self.comes_from_same_store(store)); 564f2e689cdSNick Fitzgerald let structref = self.structref(store)?.unchecked_copy(); 565f2e689cdSNick Fitzgerald let field_ty = self.field_ty(store, index)?; 566f2e689cdSNick Fitzgerald let layout = self.layout(store)?; 567f2e689cdSNick Fitzgerald Ok(structref.read_field(store, &layout, field_ty.element_type(), index)) 568f2e689cdSNick Fitzgerald } 569f2e689cdSNick Fitzgerald 570f2e689cdSNick Fitzgerald /// Set this struct's `index`th field. 571f2e689cdSNick Fitzgerald /// 572f2e689cdSNick Fitzgerald /// # Errors 573f2e689cdSNick Fitzgerald /// 574f2e689cdSNick Fitzgerald /// Returns an error in the following scenarios: 575f2e689cdSNick Fitzgerald /// 576f2e689cdSNick Fitzgerald /// * When given a value of the wrong type, such as trying to set an `f32` 577f2e689cdSNick Fitzgerald /// field to an `i64` value. 578f2e689cdSNick Fitzgerald /// 579f2e689cdSNick Fitzgerald /// * When the field is not mutable. 580f2e689cdSNick Fitzgerald /// 581f2e689cdSNick Fitzgerald /// * When this struct does not have an `index`th field, i.e. `index` is out 582f2e689cdSNick Fitzgerald /// of bounds. 583f2e689cdSNick Fitzgerald /// 584f2e689cdSNick Fitzgerald /// * When `value` is a GC reference that has since been unrooted. 585f2e689cdSNick Fitzgerald /// 586f2e689cdSNick Fitzgerald /// # Panics 587f2e689cdSNick Fitzgerald /// 588f2e689cdSNick Fitzgerald /// Panics if this reference is associated with a different store. set_field(&self, mut store: impl AsContextMut, index: usize, value: Val) -> Result<()>589f2e689cdSNick Fitzgerald pub fn set_field(&self, mut store: impl AsContextMut, index: usize, value: Val) -> Result<()> { 590f2e689cdSNick Fitzgerald self._set_field(store.as_context_mut().0, index, value) 591f2e689cdSNick Fitzgerald } 592f2e689cdSNick Fitzgerald _set_field( &self, store: &mut StoreOpaque, index: usize, value: Val, ) -> Result<()>593f2e689cdSNick Fitzgerald pub(crate) fn _set_field( 594f2e689cdSNick Fitzgerald &self, 595f2e689cdSNick Fitzgerald store: &mut StoreOpaque, 596f2e689cdSNick Fitzgerald index: usize, 597f2e689cdSNick Fitzgerald value: Val, 598f2e689cdSNick Fitzgerald ) -> Result<()> { 599f2e689cdSNick Fitzgerald assert!(self.comes_from_same_store(store)); 600f2e689cdSNick Fitzgerald let mut store = AutoAssertNoGc::new(store); 601f2e689cdSNick Fitzgerald 602f2e689cdSNick Fitzgerald let field_ty = self.field_ty(&store, index)?; 603f2e689cdSNick Fitzgerald ensure!( 604f2e689cdSNick Fitzgerald field_ty.mutability().is_var(), 605f2e689cdSNick Fitzgerald "cannot set field {index}: field is not mutable" 606f2e689cdSNick Fitzgerald ); 607f2e689cdSNick Fitzgerald 608f2e689cdSNick Fitzgerald value 609f2e689cdSNick Fitzgerald .ensure_matches_ty(&store, &field_ty.element_type().unpack()) 610f2e689cdSNick Fitzgerald .with_context(|| format!("cannot set field {index}: type mismatch"))?; 611f2e689cdSNick Fitzgerald 612f2e689cdSNick Fitzgerald let layout = self.layout(&store)?; 613f2e689cdSNick Fitzgerald let structref = self.structref(&store)?.unchecked_copy(); 614f2e689cdSNick Fitzgerald 615f2e689cdSNick Fitzgerald structref.write_field(&mut store, &layout, field_ty.element_type(), index, value) 616f2e689cdSNick Fitzgerald } 617f2e689cdSNick Fitzgerald type_index(&self, store: &StoreOpaque) -> Result<VMSharedTypeIndex>618f2e689cdSNick Fitzgerald pub(crate) fn type_index(&self, store: &StoreOpaque) -> Result<VMSharedTypeIndex> { 61999b739fbSNick Fitzgerald let gc_ref = self.inner.try_gc_ref(store)?; 620c6dddeafSAlex Crichton let header = store.require_gc_store()?.header(gc_ref); 621f2e689cdSNick Fitzgerald debug_assert!(header.kind().matches(VMGcKind::StructRef)); 622f2e689cdSNick Fitzgerald Ok(header.ty().expect("structrefs should have concrete types")) 623f2e689cdSNick Fitzgerald } 624f2e689cdSNick Fitzgerald 625f2e689cdSNick Fitzgerald /// Create a new `Rooted<StructRef>` from the given GC reference. 626f2e689cdSNick Fitzgerald /// 627f2e689cdSNick Fitzgerald /// `gc_ref` should point to a valid `structref` and should belong to the 628f2e689cdSNick Fitzgerald /// store's GC heap. Failure to uphold these invariants is memory safe but 629f2e689cdSNick Fitzgerald /// will lead to general incorrectness such as panics or wrong results. from_cloned_gc_ref( store: &mut AutoAssertNoGc<'_>, gc_ref: VMGcRef, ) -> Rooted<Self>630f2e689cdSNick Fitzgerald pub(crate) fn from_cloned_gc_ref( 631f2e689cdSNick Fitzgerald store: &mut AutoAssertNoGc<'_>, 632f2e689cdSNick Fitzgerald gc_ref: VMGcRef, 633f2e689cdSNick Fitzgerald ) -> Rooted<Self> { 634d2e3f7a5SNick Fitzgerald debug_assert!(gc_ref.is_structref(&*store.unwrap_gc_store().gc_heap)); 635f2e689cdSNick Fitzgerald Rooted::new(store, gc_ref) 636f2e689cdSNick Fitzgerald } 637f2e689cdSNick Fitzgerald } 638f2e689cdSNick Fitzgerald 639f2e689cdSNick Fitzgerald unsafe impl WasmTy for Rooted<StructRef> { 640f2e689cdSNick Fitzgerald #[inline] valtype() -> ValType641f2e689cdSNick Fitzgerald fn valtype() -> ValType { 642f2e689cdSNick Fitzgerald ValType::Ref(RefType::new(false, HeapType::Struct)) 643f2e689cdSNick Fitzgerald } 644f2e689cdSNick Fitzgerald 645f2e689cdSNick Fitzgerald #[inline] compatible_with_store(&self, store: &StoreOpaque) -> bool646f2e689cdSNick Fitzgerald fn compatible_with_store(&self, store: &StoreOpaque) -> bool { 647f2e689cdSNick Fitzgerald self.comes_from_same_store(store) 648f2e689cdSNick Fitzgerald } 649f2e689cdSNick Fitzgerald 650f2e689cdSNick Fitzgerald #[inline] dynamic_concrete_type_check( &self, store: &StoreOpaque, _nullable: bool, ty: &HeapType, ) -> Result<()>651f2e689cdSNick Fitzgerald fn dynamic_concrete_type_check( 652f2e689cdSNick Fitzgerald &self, 653f2e689cdSNick Fitzgerald store: &StoreOpaque, 654f2e689cdSNick Fitzgerald _nullable: bool, 655f2e689cdSNick Fitzgerald ty: &HeapType, 656f2e689cdSNick Fitzgerald ) -> Result<()> { 657f2e689cdSNick Fitzgerald match ty { 658f2e689cdSNick Fitzgerald HeapType::Any | HeapType::Eq | HeapType::Struct => Ok(()), 659f2e689cdSNick Fitzgerald HeapType::ConcreteStruct(ty) => self.ensure_matches_ty(store, ty), 660f2e689cdSNick Fitzgerald 661f2e689cdSNick Fitzgerald HeapType::Extern 662f2e689cdSNick Fitzgerald | HeapType::NoExtern 663f2e689cdSNick Fitzgerald | HeapType::Func 664f2e689cdSNick Fitzgerald | HeapType::ConcreteFunc(_) 665f2e689cdSNick Fitzgerald | HeapType::NoFunc 666f2e689cdSNick Fitzgerald | HeapType::I31 667f2e689cdSNick Fitzgerald | HeapType::Array 668f2e689cdSNick Fitzgerald | HeapType::ConcreteArray(_) 66963d482c8SFrank Emrich | HeapType::None 67063d482c8SFrank Emrich | HeapType::NoCont 67163d482c8SFrank Emrich | HeapType::Cont 672eaa4632eSChris Fallin | HeapType::ConcreteCont(_) 673eaa4632eSChris Fallin | HeapType::NoExn 674eaa4632eSChris Fallin | HeapType::Exn 675eaa4632eSChris Fallin | HeapType::ConcreteExn(_) => bail!( 676f2e689cdSNick Fitzgerald "type mismatch: expected `(ref {ty})`, got `(ref {})`", 677f2e689cdSNick Fitzgerald self._ty(store)?, 678f2e689cdSNick Fitzgerald ), 679f2e689cdSNick Fitzgerald } 680f2e689cdSNick Fitzgerald } 681f2e689cdSNick Fitzgerald store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()>682f2e689cdSNick Fitzgerald fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> { 6839459cf5eSNick Fitzgerald self.wasm_ty_store(store, ptr, ValRaw::anyref) 684f2e689cdSNick Fitzgerald } 685f2e689cdSNick Fitzgerald load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self686f2e689cdSNick Fitzgerald unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self { 6879459cf5eSNick Fitzgerald Self::wasm_ty_load(store, ptr.get_anyref(), StructRef::from_cloned_gc_ref) 688f2e689cdSNick Fitzgerald } 689f2e689cdSNick Fitzgerald } 690f2e689cdSNick Fitzgerald 691f2e689cdSNick Fitzgerald unsafe impl WasmTy for Option<Rooted<StructRef>> { 692f2e689cdSNick Fitzgerald #[inline] valtype() -> ValType693f2e689cdSNick Fitzgerald fn valtype() -> ValType { 694f2e689cdSNick Fitzgerald ValType::STRUCTREF 695f2e689cdSNick Fitzgerald } 696f2e689cdSNick Fitzgerald 697f2e689cdSNick Fitzgerald #[inline] compatible_with_store(&self, store: &StoreOpaque) -> bool698f2e689cdSNick Fitzgerald fn compatible_with_store(&self, store: &StoreOpaque) -> bool { 699f2e689cdSNick Fitzgerald self.map_or(true, |x| x.comes_from_same_store(store)) 700f2e689cdSNick Fitzgerald } 701f2e689cdSNick Fitzgerald 702f2e689cdSNick Fitzgerald #[inline] dynamic_concrete_type_check( &self, store: &StoreOpaque, nullable: bool, ty: &HeapType, ) -> Result<()>703f2e689cdSNick Fitzgerald fn dynamic_concrete_type_check( 704f2e689cdSNick Fitzgerald &self, 705f2e689cdSNick Fitzgerald store: &StoreOpaque, 706f2e689cdSNick Fitzgerald nullable: bool, 707f2e689cdSNick Fitzgerald ty: &HeapType, 708f2e689cdSNick Fitzgerald ) -> Result<()> { 709f2e689cdSNick Fitzgerald match self { 710f2e689cdSNick Fitzgerald Some(s) => Rooted::<StructRef>::dynamic_concrete_type_check(s, store, nullable, ty), 711f2e689cdSNick Fitzgerald None => { 712f2e689cdSNick Fitzgerald ensure!( 713f2e689cdSNick Fitzgerald nullable, 714f2e689cdSNick Fitzgerald "expected a non-null reference, but found a null reference" 715f2e689cdSNick Fitzgerald ); 716f2e689cdSNick Fitzgerald Ok(()) 717f2e689cdSNick Fitzgerald } 718f2e689cdSNick Fitzgerald } 719f2e689cdSNick Fitzgerald } 720f2e689cdSNick Fitzgerald 721f2e689cdSNick Fitzgerald #[inline] is_vmgcref_and_points_to_object(&self) -> bool722f2e689cdSNick Fitzgerald fn is_vmgcref_and_points_to_object(&self) -> bool { 723f2e689cdSNick Fitzgerald self.is_some() 724f2e689cdSNick Fitzgerald } 725f2e689cdSNick Fitzgerald store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()>726f2e689cdSNick Fitzgerald fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> { 7279459cf5eSNick Fitzgerald <Rooted<StructRef>>::wasm_ty_option_store(self, store, ptr, ValRaw::anyref) 728f2e689cdSNick Fitzgerald } 729f2e689cdSNick Fitzgerald load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self730f2e689cdSNick Fitzgerald unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self { 7319459cf5eSNick Fitzgerald <Rooted<StructRef>>::wasm_ty_option_load( 7329459cf5eSNick Fitzgerald store, 7339459cf5eSNick Fitzgerald ptr.get_anyref(), 7349459cf5eSNick Fitzgerald StructRef::from_cloned_gc_ref, 7359459cf5eSNick Fitzgerald ) 736f2e689cdSNick Fitzgerald } 737f2e689cdSNick Fitzgerald } 738f2e689cdSNick Fitzgerald 7399826719aSChris Fallin unsafe impl WasmTy for OwnedRooted<StructRef> { 740f2e689cdSNick Fitzgerald #[inline] valtype() -> ValType741f2e689cdSNick Fitzgerald fn valtype() -> ValType { 742f2e689cdSNick Fitzgerald ValType::Ref(RefType::new(false, HeapType::Struct)) 743f2e689cdSNick Fitzgerald } 744f2e689cdSNick Fitzgerald 745f2e689cdSNick Fitzgerald #[inline] compatible_with_store(&self, store: &StoreOpaque) -> bool746f2e689cdSNick Fitzgerald fn compatible_with_store(&self, store: &StoreOpaque) -> bool { 747f2e689cdSNick Fitzgerald self.comes_from_same_store(store) 748f2e689cdSNick Fitzgerald } 749f2e689cdSNick Fitzgerald 750f2e689cdSNick Fitzgerald #[inline] dynamic_concrete_type_check( &self, store: &StoreOpaque, _: bool, ty: &HeapType, ) -> Result<()>751f2e689cdSNick Fitzgerald fn dynamic_concrete_type_check( 752f2e689cdSNick Fitzgerald &self, 753f2e689cdSNick Fitzgerald store: &StoreOpaque, 754f2e689cdSNick Fitzgerald _: bool, 755f2e689cdSNick Fitzgerald ty: &HeapType, 756f2e689cdSNick Fitzgerald ) -> Result<()> { 757f2e689cdSNick Fitzgerald match ty { 758f2e689cdSNick Fitzgerald HeapType::Any | HeapType::Eq | HeapType::Struct => Ok(()), 759f2e689cdSNick Fitzgerald HeapType::ConcreteStruct(ty) => self.ensure_matches_ty(store, ty), 760f2e689cdSNick Fitzgerald 761f2e689cdSNick Fitzgerald HeapType::Extern 762f2e689cdSNick Fitzgerald | HeapType::NoExtern 763f2e689cdSNick Fitzgerald | HeapType::Func 764f2e689cdSNick Fitzgerald | HeapType::ConcreteFunc(_) 765f2e689cdSNick Fitzgerald | HeapType::NoFunc 766f2e689cdSNick Fitzgerald | HeapType::I31 767f2e689cdSNick Fitzgerald | HeapType::Array 768f2e689cdSNick Fitzgerald | HeapType::ConcreteArray(_) 76963d482c8SFrank Emrich | HeapType::None 77063d482c8SFrank Emrich | HeapType::NoCont 77163d482c8SFrank Emrich | HeapType::Cont 772eaa4632eSChris Fallin | HeapType::ConcreteCont(_) 773eaa4632eSChris Fallin | HeapType::NoExn 774eaa4632eSChris Fallin | HeapType::Exn 775eaa4632eSChris Fallin | HeapType::ConcreteExn(_) => bail!( 776f2e689cdSNick Fitzgerald "type mismatch: expected `(ref {ty})`, got `(ref {})`", 777f2e689cdSNick Fitzgerald self._ty(store)?, 778f2e689cdSNick Fitzgerald ), 779f2e689cdSNick Fitzgerald } 780f2e689cdSNick Fitzgerald } 781f2e689cdSNick Fitzgerald store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()>782f2e689cdSNick Fitzgerald fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> { 7839459cf5eSNick Fitzgerald self.wasm_ty_store(store, ptr, ValRaw::anyref) 784f2e689cdSNick Fitzgerald } 785f2e689cdSNick Fitzgerald load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self786f2e689cdSNick Fitzgerald unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self { 7879459cf5eSNick Fitzgerald Self::wasm_ty_load(store, ptr.get_anyref(), StructRef::from_cloned_gc_ref) 788f2e689cdSNick Fitzgerald } 789f2e689cdSNick Fitzgerald } 790f2e689cdSNick Fitzgerald 7919826719aSChris Fallin unsafe impl WasmTy for Option<OwnedRooted<StructRef>> { 792f2e689cdSNick Fitzgerald #[inline] valtype() -> ValType793f2e689cdSNick Fitzgerald fn valtype() -> ValType { 794f2e689cdSNick Fitzgerald ValType::STRUCTREF 795f2e689cdSNick Fitzgerald } 796f2e689cdSNick Fitzgerald 797f2e689cdSNick Fitzgerald #[inline] compatible_with_store(&self, store: &StoreOpaque) -> bool798f2e689cdSNick Fitzgerald fn compatible_with_store(&self, store: &StoreOpaque) -> bool { 799f2e689cdSNick Fitzgerald self.as_ref() 800f2e689cdSNick Fitzgerald .map_or(true, |x| x.comes_from_same_store(store)) 801f2e689cdSNick Fitzgerald } 802f2e689cdSNick Fitzgerald 803f2e689cdSNick Fitzgerald #[inline] dynamic_concrete_type_check( &self, store: &StoreOpaque, nullable: bool, ty: &HeapType, ) -> Result<()>804f2e689cdSNick Fitzgerald fn dynamic_concrete_type_check( 805f2e689cdSNick Fitzgerald &self, 806f2e689cdSNick Fitzgerald store: &StoreOpaque, 807f2e689cdSNick Fitzgerald nullable: bool, 808f2e689cdSNick Fitzgerald ty: &HeapType, 809f2e689cdSNick Fitzgerald ) -> Result<()> { 810f2e689cdSNick Fitzgerald match self { 811f2e689cdSNick Fitzgerald Some(s) => { 8129826719aSChris Fallin OwnedRooted::<StructRef>::dynamic_concrete_type_check(s, store, nullable, ty) 813f2e689cdSNick Fitzgerald } 814f2e689cdSNick Fitzgerald None => { 815f2e689cdSNick Fitzgerald ensure!( 816f2e689cdSNick Fitzgerald nullable, 817f2e689cdSNick Fitzgerald "expected a non-null reference, but found a null reference" 818f2e689cdSNick Fitzgerald ); 819f2e689cdSNick Fitzgerald Ok(()) 820f2e689cdSNick Fitzgerald } 821f2e689cdSNick Fitzgerald } 822f2e689cdSNick Fitzgerald } 823f2e689cdSNick Fitzgerald 824f2e689cdSNick Fitzgerald #[inline] is_vmgcref_and_points_to_object(&self) -> bool825f2e689cdSNick Fitzgerald fn is_vmgcref_and_points_to_object(&self) -> bool { 826f2e689cdSNick Fitzgerald self.is_some() 827f2e689cdSNick Fitzgerald } 828f2e689cdSNick Fitzgerald store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()>829f2e689cdSNick Fitzgerald fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> { 8309826719aSChris Fallin <OwnedRooted<StructRef>>::wasm_ty_option_store(self, store, ptr, ValRaw::anyref) 831f2e689cdSNick Fitzgerald } 832f2e689cdSNick Fitzgerald load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self833f2e689cdSNick Fitzgerald unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self { 8349826719aSChris Fallin <OwnedRooted<StructRef>>::wasm_ty_option_load( 8359459cf5eSNick Fitzgerald store, 8369459cf5eSNick Fitzgerald ptr.get_anyref(), 8379459cf5eSNick Fitzgerald StructRef::from_cloned_gc_ref, 838f2e689cdSNick Fitzgerald ) 839f2e689cdSNick Fitzgerald } 840f2e689cdSNick Fitzgerald } 841