1c4be2d84SNick Fitzgerald //! Working with GC `array` objects. 2c4be2d84SNick Fitzgerald 3*cc8d04f4SAlex Crichton use crate::runtime::vm::VMGcRef; 4*cc8d04f4SAlex Crichton use crate::store::{Asyncness, StoreId, StoreResourceLimiter}; 5*cc8d04f4SAlex Crichton #[cfg(feature = "async")] 6*cc8d04f4SAlex Crichton use crate::vm::VMStore; 74abb2133SAlex Crichton use crate::vm::{self, VMArrayRef, VMGcHeader}; 890ac295eSAlex Crichton use crate::{AnyRef, FieldType}; 9c4be2d84SNick Fitzgerald use crate::{ 10c16414fbSNick Fitzgerald ArrayType, AsContext, AsContextMut, EqRef, GcHeapOutOfMemory, GcRefImpl, GcRootIndex, HeapType, 119826719aSChris Fallin OwnedRooted, RefType, Rooted, Val, ValRaw, ValType, WasmTy, 1290ac295eSAlex Crichton prelude::*, 1390ac295eSAlex Crichton store::{AutoAssertNoGc, StoreContextMut, StoreOpaque}, 14c4be2d84SNick Fitzgerald }; 15c4be2d84SNick Fitzgerald use core::mem::{self, MaybeUninit}; 169c23d884SNick Fitzgerald use wasmtime_environ::{GcArrayLayout, GcLayout, VMGcKind, VMSharedTypeIndex}; 17c4be2d84SNick Fitzgerald 18c4be2d84SNick Fitzgerald /// An allocator for a particular Wasm GC array type. 19c4be2d84SNick Fitzgerald /// 20c4be2d84SNick Fitzgerald /// Every `ArrayRefPre` is associated with a particular [`Store`][crate::Store] 21c4be2d84SNick Fitzgerald /// and a particular [`ArrayType`][crate::ArrayType]. 22c4be2d84SNick Fitzgerald /// 23c4be2d84SNick Fitzgerald /// Reusing an allocator across many allocations amortizes some per-type runtime 24c4be2d84SNick Fitzgerald /// overheads inside Wasmtime. An `ArrayRefPre` is to `ArrayRef`s as an 25c4be2d84SNick Fitzgerald /// `InstancePre` is to `Instance`s. 26c4be2d84SNick Fitzgerald /// 27c4be2d84SNick Fitzgerald /// # Example 28c4be2d84SNick Fitzgerald /// 29c4be2d84SNick Fitzgerald /// ``` 30c4be2d84SNick Fitzgerald /// use wasmtime::*; 31c4be2d84SNick Fitzgerald /// 32c4be2d84SNick Fitzgerald /// # fn foo() -> Result<()> { 33c4be2d84SNick Fitzgerald /// let mut config = Config::new(); 34c4be2d84SNick Fitzgerald /// config.wasm_function_references(true); 35c4be2d84SNick Fitzgerald /// config.wasm_gc(true); 36c4be2d84SNick Fitzgerald /// 37c4be2d84SNick Fitzgerald /// let engine = Engine::new(&config)?; 38c4be2d84SNick Fitzgerald /// let mut store = Store::new(&engine, ()); 39c4be2d84SNick Fitzgerald /// 40c4be2d84SNick Fitzgerald /// // Define an array type. 41c4be2d84SNick Fitzgerald /// let array_ty = ArrayType::new( 42c4be2d84SNick Fitzgerald /// store.engine(), 43c4be2d84SNick Fitzgerald /// FieldType::new(Mutability::Var, ValType::I32.into()), 44c4be2d84SNick Fitzgerald /// ); 45c4be2d84SNick Fitzgerald /// 46c4be2d84SNick Fitzgerald /// // Create an allocator for the array type. 47c4be2d84SNick Fitzgerald /// let allocator = ArrayRefPre::new(&mut store, array_ty); 48c4be2d84SNick Fitzgerald /// 49c4be2d84SNick Fitzgerald /// { 50c4be2d84SNick Fitzgerald /// let mut scope = RootScope::new(&mut store); 51c4be2d84SNick Fitzgerald /// 52c4be2d84SNick Fitzgerald /// // Allocate a bunch of instances of our array type using the same 53c4be2d84SNick Fitzgerald /// // allocator! This is faster than creating a new allocator for each 54c4be2d84SNick Fitzgerald /// // instance we want to allocate. 55c4be2d84SNick Fitzgerald /// for i in 0..10 { 56c4be2d84SNick Fitzgerald /// let len = 42; 57c4be2d84SNick Fitzgerald /// let elem = Val::I32(36); 58c4be2d84SNick Fitzgerald /// ArrayRef::new(&mut scope, &allocator, &elem, len)?; 59c4be2d84SNick Fitzgerald /// } 60c4be2d84SNick Fitzgerald /// } 61c4be2d84SNick Fitzgerald /// # Ok(()) 62c4be2d84SNick Fitzgerald /// # } 63c22b3cb9SNick Fitzgerald /// # let _ = foo(); 64c4be2d84SNick Fitzgerald /// ``` 65c4be2d84SNick Fitzgerald pub struct ArrayRefPre { 66c4be2d84SNick Fitzgerald store_id: StoreId, 67c4be2d84SNick Fitzgerald ty: ArrayType, 68c4be2d84SNick Fitzgerald } 69c4be2d84SNick Fitzgerald 70c4be2d84SNick Fitzgerald impl ArrayRefPre { 71c4be2d84SNick Fitzgerald /// Create a new `ArrayRefPre` that is associated with the given store 72c4be2d84SNick Fitzgerald /// and type. new(mut store: impl AsContextMut, ty: ArrayType) -> Self73c4be2d84SNick Fitzgerald pub fn new(mut store: impl AsContextMut, ty: ArrayType) -> Self { 74c4be2d84SNick Fitzgerald Self::_new(store.as_context_mut().0, ty) 75c4be2d84SNick Fitzgerald } 76c4be2d84SNick Fitzgerald _new(store: &mut StoreOpaque, ty: ArrayType) -> Self77c4be2d84SNick Fitzgerald pub(crate) fn _new(store: &mut StoreOpaque, ty: ArrayType) -> Self { 78c4be2d84SNick Fitzgerald store.insert_gc_host_alloc_type(ty.registered_type().clone()); 79c4be2d84SNick Fitzgerald let store_id = store.id(); 80c4be2d84SNick Fitzgerald ArrayRefPre { store_id, ty } 81c4be2d84SNick Fitzgerald } 82c4be2d84SNick Fitzgerald layout(&self) -> &GcArrayLayout83c4be2d84SNick Fitzgerald pub(crate) fn layout(&self) -> &GcArrayLayout { 84c4be2d84SNick Fitzgerald self.ty 85c4be2d84SNick Fitzgerald .registered_type() 86c4be2d84SNick Fitzgerald .layout() 87c4be2d84SNick Fitzgerald .expect("array types have a layout") 88c4be2d84SNick Fitzgerald .unwrap_array() 89c4be2d84SNick Fitzgerald } 90c4be2d84SNick Fitzgerald type_index(&self) -> VMSharedTypeIndex91c4be2d84SNick Fitzgerald pub(crate) fn type_index(&self) -> VMSharedTypeIndex { 92c4be2d84SNick Fitzgerald self.ty.registered_type().index() 93c4be2d84SNick Fitzgerald } 94c4be2d84SNick Fitzgerald } 95c4be2d84SNick Fitzgerald 96c4be2d84SNick Fitzgerald /// A reference to a GC-managed `array` instance. 97c4be2d84SNick Fitzgerald /// 98c4be2d84SNick Fitzgerald /// WebAssembly `array`s are a sequence of elements of some homogeneous 99c4be2d84SNick Fitzgerald /// type. The elements length is determined at allocation time — two instances 100c4be2d84SNick Fitzgerald /// of the same array type may have different lengths — but, once allocated, an 101c4be2d84SNick Fitzgerald /// array's length can never be resized. An array's elements are mutable or 102c4be2d84SNick Fitzgerald /// constant, depending on the array's type. This determines whether any array 103c4be2d84SNick Fitzgerald /// element can be assigned a new value or not. Each element is either an 104c4be2d84SNick Fitzgerald /// unpacked [`Val`][crate::Val] or a packed 8-/16-bit integer. Array elements 105c4be2d84SNick Fitzgerald /// are dynamically accessed via indexing; out-of-bounds accesses result in 106c4be2d84SNick Fitzgerald /// traps. 107c4be2d84SNick Fitzgerald /// 108c4be2d84SNick Fitzgerald /// Like all WebAssembly references, these are opaque and unforgeable to Wasm: 109c4be2d84SNick Fitzgerald /// they cannot be faked and Wasm cannot, for example, cast the integer 110c4be2d84SNick Fitzgerald /// `0x12345678` into a reference, pretend it is a valid `arrayref`, and trick 111c4be2d84SNick Fitzgerald /// the host into dereferencing it and segfaulting or worse. 112c4be2d84SNick Fitzgerald /// 1139826719aSChris Fallin /// Note that you can also use `Rooted<ArrayRef>` and `OwnedRooted<ArrayRef>` 114c4be2d84SNick Fitzgerald /// as a type parameter with [`Func::typed`][crate::Func::typed]- and 115c4be2d84SNick Fitzgerald /// [`Func::wrap`][crate::Func::wrap]-style APIs. 116c4be2d84SNick Fitzgerald /// 117c4be2d84SNick Fitzgerald /// # Example 118c4be2d84SNick Fitzgerald /// 119c4be2d84SNick Fitzgerald /// ``` 120c4be2d84SNick Fitzgerald /// use wasmtime::*; 121c4be2d84SNick Fitzgerald /// 122c4be2d84SNick Fitzgerald /// # fn foo() -> Result<()> { 123c4be2d84SNick Fitzgerald /// let mut config = Config::new(); 124c4be2d84SNick Fitzgerald /// config.wasm_function_references(true); 125c4be2d84SNick Fitzgerald /// config.wasm_gc(true); 126c4be2d84SNick Fitzgerald /// 127c4be2d84SNick Fitzgerald /// let engine = Engine::new(&config)?; 128c4be2d84SNick Fitzgerald /// let mut store = Store::new(&engine, ()); 129c4be2d84SNick Fitzgerald /// 130c4be2d84SNick Fitzgerald /// // Define the type for an array of `i32`s. 131c4be2d84SNick Fitzgerald /// let array_ty = ArrayType::new( 132c4be2d84SNick Fitzgerald /// store.engine(), 133c4be2d84SNick Fitzgerald /// FieldType::new(Mutability::Var, ValType::I32.into()), 134c4be2d84SNick Fitzgerald /// ); 135c4be2d84SNick Fitzgerald /// 136c4be2d84SNick Fitzgerald /// // Create an allocator for the array type. 137c4be2d84SNick Fitzgerald /// let allocator = ArrayRefPre::new(&mut store, array_ty); 138c4be2d84SNick Fitzgerald /// 139c4be2d84SNick Fitzgerald /// { 140c4be2d84SNick Fitzgerald /// let mut scope = RootScope::new(&mut store); 141c4be2d84SNick Fitzgerald /// 142c4be2d84SNick Fitzgerald /// // Allocate an instance of the array type. 143c4be2d84SNick Fitzgerald /// let len = 36; 144c4be2d84SNick Fitzgerald /// let elem = Val::I32(42); 145c4be2d84SNick Fitzgerald /// let my_array = match ArrayRef::new(&mut scope, &allocator, &elem, len) { 146c4be2d84SNick Fitzgerald /// Ok(s) => s, 147c22b3cb9SNick Fitzgerald /// Err(e) => match e.downcast::<GcHeapOutOfMemory<()>>() { 148c22b3cb9SNick Fitzgerald /// // If the heap is out of memory, then do a GC to free up some 149c22b3cb9SNick Fitzgerald /// // space and try again. 150c22b3cb9SNick Fitzgerald /// Ok(oom) => { 151c4be2d84SNick Fitzgerald /// // Do a GC! Note: in an async context, you'd want to do 152c4be2d84SNick Fitzgerald /// // `scope.as_context_mut().gc_async().await`. 153*cc8d04f4SAlex Crichton /// scope.as_context_mut().gc(Some(&oom))?; 154c4be2d84SNick Fitzgerald /// 155c4be2d84SNick Fitzgerald /// // Try again. If the GC heap is still out of memory, then we 156c4be2d84SNick Fitzgerald /// // weren't able to free up resources for this allocation, so 157c4be2d84SNick Fitzgerald /// // propagate the error. 158c4be2d84SNick Fitzgerald /// ArrayRef::new(&mut scope, &allocator, &elem, len)? 159c4be2d84SNick Fitzgerald /// } 160c4be2d84SNick Fitzgerald /// // Propagate any other kind of error. 161c4be2d84SNick Fitzgerald /// Err(e) => return Err(e), 162c22b3cb9SNick Fitzgerald /// } 163c4be2d84SNick Fitzgerald /// }; 164c4be2d84SNick Fitzgerald /// 165c4be2d84SNick Fitzgerald /// // That instance's elements should have the initial value. 166c4be2d84SNick Fitzgerald /// for i in 0..len { 167c4be2d84SNick Fitzgerald /// let val = my_array.get(&mut scope, i)?.unwrap_i32(); 168c4be2d84SNick Fitzgerald /// assert_eq!(val, 42); 169c4be2d84SNick Fitzgerald /// } 170c4be2d84SNick Fitzgerald /// 171c4be2d84SNick Fitzgerald /// // We can set an element to a new value because the type was defined with 172c4be2d84SNick Fitzgerald /// // mutable elements (as opposed to const). 173c4be2d84SNick Fitzgerald /// my_array.set(&mut scope, 3, Val::I32(1234))?; 174c4be2d84SNick Fitzgerald /// let new_val = my_array.get(&mut scope, 3)?.unwrap_i32(); 175c4be2d84SNick Fitzgerald /// assert_eq!(new_val, 1234); 176c4be2d84SNick Fitzgerald /// } 177c4be2d84SNick Fitzgerald /// # Ok(()) 178c4be2d84SNick Fitzgerald /// # } 179c4be2d84SNick Fitzgerald /// # foo().unwrap(); 180c4be2d84SNick Fitzgerald /// ``` 181c4be2d84SNick Fitzgerald #[derive(Debug)] 182c4be2d84SNick Fitzgerald #[repr(transparent)] 183c4be2d84SNick Fitzgerald pub struct ArrayRef { 184c4be2d84SNick Fitzgerald pub(super) inner: GcRootIndex, 185c4be2d84SNick Fitzgerald } 186c4be2d84SNick Fitzgerald 187c4be2d84SNick Fitzgerald unsafe impl GcRefImpl for ArrayRef { transmute_ref(index: &GcRootIndex) -> &Self188c4be2d84SNick Fitzgerald fn transmute_ref(index: &GcRootIndex) -> &Self { 189c4be2d84SNick Fitzgerald // Safety: `ArrayRef` is a newtype of a `GcRootIndex`. 190c4be2d84SNick Fitzgerald let me: &Self = unsafe { mem::transmute(index) }; 191c4be2d84SNick Fitzgerald 192c4be2d84SNick Fitzgerald // Assert we really are just a newtype of a `GcRootIndex`. 193c4be2d84SNick Fitzgerald assert!(matches!( 194c4be2d84SNick Fitzgerald me, 195c4be2d84SNick Fitzgerald Self { 196c4be2d84SNick Fitzgerald inner: GcRootIndex { .. }, 197c4be2d84SNick Fitzgerald } 198c4be2d84SNick Fitzgerald )); 199c4be2d84SNick Fitzgerald 200c4be2d84SNick Fitzgerald me 201c4be2d84SNick Fitzgerald } 202c4be2d84SNick Fitzgerald } 203c4be2d84SNick Fitzgerald 204c4be2d84SNick Fitzgerald impl Rooted<ArrayRef> { 205c4be2d84SNick Fitzgerald /// Upcast this `arrayref` into an `anyref`. 206c4be2d84SNick Fitzgerald #[inline] to_anyref(self) -> Rooted<AnyRef>207c4be2d84SNick Fitzgerald pub fn to_anyref(self) -> Rooted<AnyRef> { 208c4be2d84SNick Fitzgerald self.unchecked_cast() 209c4be2d84SNick Fitzgerald } 210c16414fbSNick Fitzgerald 211c16414fbSNick Fitzgerald /// Upcast this `arrayref` into an `eqref`. 212c16414fbSNick Fitzgerald #[inline] to_eqref(self) -> Rooted<EqRef>213c16414fbSNick Fitzgerald pub fn to_eqref(self) -> Rooted<EqRef> { 214c16414fbSNick Fitzgerald self.unchecked_cast() 215c16414fbSNick Fitzgerald } 216c4be2d84SNick Fitzgerald } 217c4be2d84SNick Fitzgerald 2189826719aSChris Fallin impl OwnedRooted<ArrayRef> { 219c4be2d84SNick Fitzgerald /// Upcast this `arrayref` into an `anyref`. 220c4be2d84SNick Fitzgerald #[inline] to_anyref(self) -> OwnedRooted<AnyRef>2219826719aSChris Fallin pub fn to_anyref(self) -> OwnedRooted<AnyRef> { 222c4be2d84SNick Fitzgerald self.unchecked_cast() 223c4be2d84SNick Fitzgerald } 224c16414fbSNick Fitzgerald 225c16414fbSNick Fitzgerald /// Upcast this `arrayref` into an `eqref`. 226c16414fbSNick Fitzgerald #[inline] to_eqref(self) -> OwnedRooted<EqRef>2279826719aSChris Fallin pub fn to_eqref(self) -> OwnedRooted<EqRef> { 228c16414fbSNick Fitzgerald self.unchecked_cast() 229c16414fbSNick Fitzgerald } 230c4be2d84SNick Fitzgerald } 231c4be2d84SNick Fitzgerald 23207c71ab5SNick Fitzgerald /// An iterator for elements in `ArrayRef::new[_async]. 233c4be2d84SNick Fitzgerald /// 23407c71ab5SNick Fitzgerald /// NB: We can't use `iter::repeat(elem).take(len)` because that doesn't 23507c71ab5SNick Fitzgerald /// implement `ExactSizeIterator`. 23607c71ab5SNick Fitzgerald #[derive(Clone)] 237c4be2d84SNick Fitzgerald struct RepeatN<'a>(&'a Val, u32); 238c4be2d84SNick Fitzgerald 239c4be2d84SNick Fitzgerald impl<'a> Iterator for RepeatN<'a> { 240c4be2d84SNick Fitzgerald type Item = &'a Val; 241c4be2d84SNick Fitzgerald next(&mut self) -> Option<Self::Item>242c4be2d84SNick Fitzgerald fn next(&mut self) -> Option<Self::Item> { 243c4be2d84SNick Fitzgerald if self.1 == 0 { 244c4be2d84SNick Fitzgerald None 245c4be2d84SNick Fitzgerald } else { 246c4be2d84SNick Fitzgerald self.1 -= 1; 247c4be2d84SNick Fitzgerald Some(self.0) 248c4be2d84SNick Fitzgerald } 249c4be2d84SNick Fitzgerald } 250c4be2d84SNick Fitzgerald size_hint(&self) -> (usize, Option<usize>)251c4be2d84SNick Fitzgerald fn size_hint(&self) -> (usize, Option<usize>) { 252c4be2d84SNick Fitzgerald let len = self.len(); 253c4be2d84SNick Fitzgerald (len, Some(len)) 254c4be2d84SNick Fitzgerald } 255c4be2d84SNick Fitzgerald } 256c4be2d84SNick Fitzgerald 257c4be2d84SNick Fitzgerald impl ExactSizeIterator for RepeatN<'_> { len(&self) -> usize258c4be2d84SNick Fitzgerald fn len(&self) -> usize { 259c4be2d84SNick Fitzgerald usize::try_from(self.1).unwrap() 260c4be2d84SNick Fitzgerald } 261c4be2d84SNick Fitzgerald } 26207c71ab5SNick Fitzgerald 26307c71ab5SNick Fitzgerald impl ArrayRef { 26407c71ab5SNick Fitzgerald /// Allocate a new `array` of the given length, with every element 26507c71ab5SNick Fitzgerald /// initialized to `elem`. 26607c71ab5SNick Fitzgerald /// 26707c71ab5SNick Fitzgerald /// For example, `ArrayRef::new(ctx, pre, &Val::I64(9), 3)` allocates the 26807c71ab5SNick Fitzgerald /// array `[9, 9, 9]`. 26907c71ab5SNick Fitzgerald /// 27007c71ab5SNick Fitzgerald /// This is similar to the `array.new` instruction. 27107c71ab5SNick Fitzgerald /// 27207c71ab5SNick Fitzgerald /// # Automatic Garbage Collection 27307c71ab5SNick Fitzgerald /// 27407c71ab5SNick Fitzgerald /// If the GC heap is at capacity, and there isn't room for allocating this 27507c71ab5SNick Fitzgerald /// new array, then this method will automatically trigger a synchronous 27607c71ab5SNick Fitzgerald /// collection in an attempt to free up space in the GC heap. 27707c71ab5SNick Fitzgerald /// 27807c71ab5SNick Fitzgerald /// # Errors 27907c71ab5SNick Fitzgerald /// 28007c71ab5SNick Fitzgerald /// If the given `elem` value's type does not match the `allocator`'s array 28107c71ab5SNick Fitzgerald /// type's element type, an error is returned. 28207c71ab5SNick Fitzgerald /// 28307c71ab5SNick Fitzgerald /// If the allocation cannot be satisfied because the GC heap is currently 28407c71ab5SNick Fitzgerald /// out of memory, then a [`GcHeapOutOfMemory<()>`][crate::GcHeapOutOfMemory] 28507c71ab5SNick Fitzgerald /// error is returned. The allocation might succeed on a second attempt if 28607c71ab5SNick Fitzgerald /// you drop some rooted GC references and try again. 28707c71ab5SNick Fitzgerald /// 288*cc8d04f4SAlex Crichton /// If `store` is configured with a 289*cc8d04f4SAlex Crichton /// [`ResourceLimiterAsync`](crate::ResourceLimiterAsync) then an error will 290*cc8d04f4SAlex Crichton /// be returned because [`ArrayRef::new_async`] should be used instead. 29107c71ab5SNick Fitzgerald /// 292*cc8d04f4SAlex Crichton /// # Panics 29307c71ab5SNick Fitzgerald /// 29407c71ab5SNick Fitzgerald /// Panics if either the allocator or the `elem` value is not associated 29507c71ab5SNick Fitzgerald /// with the given store. new( mut store: impl AsContextMut, allocator: &ArrayRefPre, elem: &Val, len: u32, ) -> Result<Rooted<ArrayRef>>29607c71ab5SNick Fitzgerald pub fn new( 29707c71ab5SNick Fitzgerald mut store: impl AsContextMut, 29807c71ab5SNick Fitzgerald allocator: &ArrayRefPre, 29907c71ab5SNick Fitzgerald elem: &Val, 30007c71ab5SNick Fitzgerald len: u32, 30107c71ab5SNick Fitzgerald ) -> Result<Rooted<ArrayRef>> { 302*cc8d04f4SAlex Crichton let (mut limiter, store) = store 303*cc8d04f4SAlex Crichton .as_context_mut() 304*cc8d04f4SAlex Crichton .0 305*cc8d04f4SAlex Crichton .validate_sync_resource_limiter_and_store_opaque()?; 306155ea7fcSAlex Crichton vm::assert_ready(Self::_new_async( 307155ea7fcSAlex Crichton store, 308155ea7fcSAlex Crichton limiter.as_mut(), 309155ea7fcSAlex Crichton allocator, 310155ea7fcSAlex Crichton elem, 311155ea7fcSAlex Crichton len, 312*cc8d04f4SAlex Crichton Asyncness::No, 313155ea7fcSAlex Crichton )) 31407c71ab5SNick Fitzgerald } 31507c71ab5SNick Fitzgerald 31607c71ab5SNick Fitzgerald /// Asynchronously allocate a new `array` of the given length, with every 31707c71ab5SNick Fitzgerald /// element initialized to `elem`. 31807c71ab5SNick Fitzgerald /// 31907c71ab5SNick Fitzgerald /// For example, `ArrayRef::new(ctx, pre, &Val::I64(9), 3)` allocates the 32007c71ab5SNick Fitzgerald /// array `[9, 9, 9]`. 32107c71ab5SNick Fitzgerald /// 32207c71ab5SNick Fitzgerald /// This is similar to the `array.new` instruction. 32307c71ab5SNick Fitzgerald /// 32407c71ab5SNick Fitzgerald /// # Automatic Garbage Collection 32507c71ab5SNick Fitzgerald /// 32607c71ab5SNick Fitzgerald /// If the GC heap is at capacity, and there isn't room for allocating this 32707c71ab5SNick Fitzgerald /// new array, then this method will automatically trigger a asynchronous 32807c71ab5SNick Fitzgerald /// collection in an attempt to free up space in the GC heap. 32907c71ab5SNick Fitzgerald /// 33007c71ab5SNick Fitzgerald /// # Errors 33107c71ab5SNick Fitzgerald /// 33207c71ab5SNick Fitzgerald /// If the given `elem` value's type does not match the `allocator`'s array 33307c71ab5SNick Fitzgerald /// type's element type, an error is returned. 33407c71ab5SNick Fitzgerald /// 33507c71ab5SNick Fitzgerald /// If the allocation cannot be satisfied because the GC heap is currently 33607c71ab5SNick Fitzgerald /// out of memory, then a [`GcHeapOutOfMemory<()>`][crate::GcHeapOutOfMemory] 33707c71ab5SNick Fitzgerald /// error is returned. The allocation might succeed on a second attempt if 33807c71ab5SNick Fitzgerald /// you drop some rooted GC references and try again. 33907c71ab5SNick Fitzgerald /// 34007c71ab5SNick Fitzgerald /// # Panics 34107c71ab5SNick Fitzgerald /// 34207c71ab5SNick Fitzgerald /// Panics if your engine is not configured for async; use 34307c71ab5SNick Fitzgerald /// [`ArrayRef::new_async`][crate::ArrayRef::new_async] to perform 34407c71ab5SNick Fitzgerald /// synchronous allocation instead. 34507c71ab5SNick Fitzgerald /// 34607c71ab5SNick Fitzgerald /// Panics if either the allocator or the `elem` value is not associated 34707c71ab5SNick Fitzgerald /// with the given store. 34807c71ab5SNick Fitzgerald #[cfg(feature = "async")] new_async( mut store: impl AsContextMut, allocator: &ArrayRefPre, elem: &Val, len: u32, ) -> Result<Rooted<ArrayRef>>34907c71ab5SNick Fitzgerald pub async fn new_async( 35007c71ab5SNick Fitzgerald mut store: impl AsContextMut, 35107c71ab5SNick Fitzgerald allocator: &ArrayRefPre, 35207c71ab5SNick Fitzgerald elem: &Val, 35307c71ab5SNick Fitzgerald len: u32, 35407c71ab5SNick Fitzgerald ) -> Result<Rooted<ArrayRef>> { 355155ea7fcSAlex Crichton let (mut limiter, store) = store.as_context_mut().0.resource_limiter_and_store_opaque(); 356*cc8d04f4SAlex Crichton Self::_new_async( 357*cc8d04f4SAlex Crichton store, 358*cc8d04f4SAlex Crichton limiter.as_mut(), 359*cc8d04f4SAlex Crichton allocator, 360*cc8d04f4SAlex Crichton elem, 361*cc8d04f4SAlex Crichton len, 362*cc8d04f4SAlex Crichton Asyncness::Yes, 363*cc8d04f4SAlex Crichton ) 364*cc8d04f4SAlex Crichton .await 36507c71ab5SNick Fitzgerald } 36607c71ab5SNick Fitzgerald _new_async( store: &mut StoreOpaque, limiter: Option<&mut StoreResourceLimiter<'_>>, allocator: &ArrayRefPre, elem: &Val, len: u32, asyncness: Asyncness, ) -> Result<Rooted<ArrayRef>>36707c71ab5SNick Fitzgerald pub(crate) async fn _new_async( 36807c71ab5SNick Fitzgerald store: &mut StoreOpaque, 369155ea7fcSAlex Crichton limiter: Option<&mut StoreResourceLimiter<'_>>, 37007c71ab5SNick Fitzgerald allocator: &ArrayRefPre, 37107c71ab5SNick Fitzgerald elem: &Val, 37207c71ab5SNick Fitzgerald len: u32, 373*cc8d04f4SAlex Crichton asyncness: Asyncness, 37407c71ab5SNick Fitzgerald ) -> Result<Rooted<ArrayRef>> { 37507c71ab5SNick Fitzgerald store 376*cc8d04f4SAlex Crichton .retry_after_gc_async(limiter, (), asyncness, |store, ()| { 37707c71ab5SNick Fitzgerald Self::new_from_iter(store, allocator, RepeatN(elem, len)) 37807c71ab5SNick Fitzgerald }) 37907c71ab5SNick Fitzgerald .await 38007c71ab5SNick Fitzgerald } 38107c71ab5SNick Fitzgerald 38207c71ab5SNick Fitzgerald /// Allocate a new array of the given elements. 38307c71ab5SNick Fitzgerald /// 38407c71ab5SNick Fitzgerald /// Does not attempt a GC on OOM; leaves that to callers. new_from_iter<'a>( store: &mut StoreOpaque, allocator: &ArrayRefPre, elems: impl Clone + ExactSizeIterator<Item = &'a Val>, ) -> Result<Rooted<ArrayRef>>38507c71ab5SNick Fitzgerald fn new_from_iter<'a>( 38607c71ab5SNick Fitzgerald store: &mut StoreOpaque, 38707c71ab5SNick Fitzgerald allocator: &ArrayRefPre, 38807c71ab5SNick Fitzgerald elems: impl Clone + ExactSizeIterator<Item = &'a Val>, 38907c71ab5SNick Fitzgerald ) -> Result<Rooted<ArrayRef>> { 39007c71ab5SNick Fitzgerald assert_eq!( 39107c71ab5SNick Fitzgerald store.id(), 39207c71ab5SNick Fitzgerald allocator.store_id, 39307c71ab5SNick Fitzgerald "attempted to use a `ArrayRefPre` with the wrong store" 39407c71ab5SNick Fitzgerald ); 39507c71ab5SNick Fitzgerald 39607c71ab5SNick Fitzgerald // Type check the elements against the element type. 39707c71ab5SNick Fitzgerald for elem in elems.clone() { 39807c71ab5SNick Fitzgerald elem.ensure_matches_ty(store, allocator.ty.element_type().unpack()) 39907c71ab5SNick Fitzgerald .context("element type mismatch")?; 40007c71ab5SNick Fitzgerald } 40107c71ab5SNick Fitzgerald 402c4be2d84SNick Fitzgerald let len = u32::try_from(elems.len()).unwrap(); 403c4be2d84SNick Fitzgerald 404c4be2d84SNick Fitzgerald // Allocate the array and write each field value into the appropriate 405c4be2d84SNick Fitzgerald // offset. 406c4be2d84SNick Fitzgerald let arrayref = store 407c6dddeafSAlex Crichton .require_gc_store_mut()? 408c4be2d84SNick Fitzgerald .alloc_uninit_array(allocator.type_index(), len, allocator.layout()) 409c4be2d84SNick Fitzgerald .context("unrecoverable error when allocating new `arrayref`")? 410c22b3cb9SNick Fitzgerald .map_err(|n| GcHeapOutOfMemory::new((), n))?; 411c4be2d84SNick Fitzgerald 412c4be2d84SNick Fitzgerald // From this point on, if we get any errors, then the array is not 413c4be2d84SNick Fitzgerald // fully initialized, so we need to eagerly deallocate it before the 414c4be2d84SNick Fitzgerald // next GC where the collector might try to interpret one of the 415c4be2d84SNick Fitzgerald // uninitialized fields as a GC reference. 416c4be2d84SNick Fitzgerald let mut store = AutoAssertNoGc::new(store); 417c4be2d84SNick Fitzgerald match (|| { 418c4be2d84SNick Fitzgerald let elem_ty = allocator.ty.element_type(); 419c4be2d84SNick Fitzgerald for (i, elem) in elems.enumerate() { 420c4be2d84SNick Fitzgerald let i = u32::try_from(i).unwrap(); 421c4be2d84SNick Fitzgerald debug_assert!(i < len); 422c4be2d84SNick Fitzgerald arrayref.initialize_elem(&mut store, allocator.layout(), &elem_ty, i, *elem)?; 423c4be2d84SNick Fitzgerald } 424c4be2d84SNick Fitzgerald Ok(()) 425c4be2d84SNick Fitzgerald })() { 426c4be2d84SNick Fitzgerald Ok(()) => Ok(Rooted::new(&mut store, arrayref.into())), 427c4be2d84SNick Fitzgerald Err(e) => { 428c6dddeafSAlex Crichton store.require_gc_store_mut()?.dealloc_uninit_array(arrayref); 429c4be2d84SNick Fitzgerald Err(e) 430c4be2d84SNick Fitzgerald } 431c4be2d84SNick Fitzgerald } 432c4be2d84SNick Fitzgerald } 433c4be2d84SNick Fitzgerald 43407c71ab5SNick Fitzgerald /// Synchronously allocate a new `array` containing the given elements. 435c4be2d84SNick Fitzgerald /// 436c4be2d84SNick Fitzgerald /// For example, `ArrayRef::new_fixed(ctx, pre, &[Val::I64(4), Val::I64(5), 437c4be2d84SNick Fitzgerald /// Val::I64(6)])` allocates the array `[4, 5, 6]`. 438c4be2d84SNick Fitzgerald /// 439c4be2d84SNick Fitzgerald /// This is similar to the `array.new_fixed` instruction. 440c4be2d84SNick Fitzgerald /// 44107c71ab5SNick Fitzgerald /// # Automatic Garbage Collection 44207c71ab5SNick Fitzgerald /// 44307c71ab5SNick Fitzgerald /// If the GC heap is at capacity, and there isn't room for allocating this 44407c71ab5SNick Fitzgerald /// new array, then this method will automatically trigger a synchronous 44507c71ab5SNick Fitzgerald /// collection in an attempt to free up space in the GC heap. 44607c71ab5SNick Fitzgerald /// 447c4be2d84SNick Fitzgerald /// # Errors 448c4be2d84SNick Fitzgerald /// 449c4be2d84SNick Fitzgerald /// If any of the `elems` values' type does not match the `allocator`'s 450c4be2d84SNick Fitzgerald /// array type's element type, an error is returned. 451c4be2d84SNick Fitzgerald /// 452c4be2d84SNick Fitzgerald /// If the allocation cannot be satisfied because the GC heap is currently 45307c71ab5SNick Fitzgerald /// out of memory, then a [`GcHeapOutOfMemory<()>`][crate::GcHeapOutOfMemory] 45407c71ab5SNick Fitzgerald /// error is returned. The allocation might succeed on a second attempt if 45507c71ab5SNick Fitzgerald /// you drop some rooted GC references and try again. 456c4be2d84SNick Fitzgerald /// 457*cc8d04f4SAlex Crichton /// If `store` is configured with a 458*cc8d04f4SAlex Crichton /// [`ResourceLimiterAsync`](crate::ResourceLimiterAsync) then an error 459*cc8d04f4SAlex Crichton /// will be returned because [`ArrayRef::new_fixed_async`] should be used 460*cc8d04f4SAlex Crichton /// instead. 461c4be2d84SNick Fitzgerald /// 462*cc8d04f4SAlex Crichton /// # Panics 46307c71ab5SNick Fitzgerald /// 464c4be2d84SNick Fitzgerald /// Panics if the allocator or any of the `elems` values are not associated 465c4be2d84SNick Fitzgerald /// with the given store. new_fixed( mut store: impl AsContextMut, allocator: &ArrayRefPre, elems: &[Val], ) -> Result<Rooted<ArrayRef>>466c4be2d84SNick Fitzgerald pub fn new_fixed( 467c4be2d84SNick Fitzgerald mut store: impl AsContextMut, 468c4be2d84SNick Fitzgerald allocator: &ArrayRefPre, 469c4be2d84SNick Fitzgerald elems: &[Val], 470c4be2d84SNick Fitzgerald ) -> Result<Rooted<ArrayRef>> { 471*cc8d04f4SAlex Crichton let (mut limiter, store) = store 472*cc8d04f4SAlex Crichton .as_context_mut() 473*cc8d04f4SAlex Crichton .0 474*cc8d04f4SAlex Crichton .validate_sync_resource_limiter_and_store_opaque()?; 475155ea7fcSAlex Crichton vm::assert_ready(Self::_new_fixed_async( 476155ea7fcSAlex Crichton store, 477155ea7fcSAlex Crichton limiter.as_mut(), 478155ea7fcSAlex Crichton allocator, 479155ea7fcSAlex Crichton elems, 480*cc8d04f4SAlex Crichton Asyncness::No, 481155ea7fcSAlex Crichton )) 482c4be2d84SNick Fitzgerald } 483c4be2d84SNick Fitzgerald 48407c71ab5SNick Fitzgerald /// Asynchronously allocate a new `array` containing the given elements. 48507c71ab5SNick Fitzgerald /// 48607c71ab5SNick Fitzgerald /// For example, `ArrayRef::new_fixed_async(ctx, pre, &[Val::I64(4), 48707c71ab5SNick Fitzgerald /// Val::I64(5), Val::I64(6)])` allocates the array `[4, 5, 6]`. 48807c71ab5SNick Fitzgerald /// 48907c71ab5SNick Fitzgerald /// This is similar to the `array.new_fixed` instruction. 49007c71ab5SNick Fitzgerald /// 49107c71ab5SNick Fitzgerald /// If your engine is not configured for async, use 49207c71ab5SNick Fitzgerald /// [`ArrayRef::new_fixed`][crate::ArrayRef::new_fixed] to perform 49307c71ab5SNick Fitzgerald /// synchronous allocation. 49407c71ab5SNick Fitzgerald /// 49507c71ab5SNick Fitzgerald /// # Automatic Garbage Collection 49607c71ab5SNick Fitzgerald /// 49707c71ab5SNick Fitzgerald /// If the GC heap is at capacity, and there isn't room for allocating this 49807c71ab5SNick Fitzgerald /// new array, then this method will automatically trigger a synchronous 49907c71ab5SNick Fitzgerald /// collection in an attempt to free up space in the GC heap. 50007c71ab5SNick Fitzgerald /// 50107c71ab5SNick Fitzgerald /// # Errors 50207c71ab5SNick Fitzgerald /// 50307c71ab5SNick Fitzgerald /// If any of the `elems` values' type does not match the `allocator`'s 50407c71ab5SNick Fitzgerald /// array type's element type, an error is returned. 50507c71ab5SNick Fitzgerald /// 50607c71ab5SNick Fitzgerald /// If the allocation cannot be satisfied because the GC heap is currently 50707c71ab5SNick Fitzgerald /// out of memory, then a [`GcHeapOutOfMemory<()>`][crate::GcHeapOutOfMemory] 50807c71ab5SNick Fitzgerald /// error is returned. The allocation might succeed on a second attempt if 50907c71ab5SNick Fitzgerald /// you drop some rooted GC references and try again. 51007c71ab5SNick Fitzgerald /// 51107c71ab5SNick Fitzgerald /// # Panics 51207c71ab5SNick Fitzgerald /// 51307c71ab5SNick Fitzgerald /// Panics if the `store` is not configured for async; use 51407c71ab5SNick Fitzgerald /// [`ArrayRef::new_fixed`][crate::ArrayRef::new_fixed] to perform 51507c71ab5SNick Fitzgerald /// synchronous allocation instead. 51607c71ab5SNick Fitzgerald /// 51707c71ab5SNick Fitzgerald /// Panics if the allocator or any of the `elems` values are not associated 51807c71ab5SNick Fitzgerald /// with the given store. 51907c71ab5SNick Fitzgerald #[cfg(feature = "async")] new_fixed_async( mut store: impl AsContextMut, allocator: &ArrayRefPre, elems: &[Val], ) -> Result<Rooted<ArrayRef>>52007c71ab5SNick Fitzgerald pub async fn new_fixed_async( 52107c71ab5SNick Fitzgerald mut store: impl AsContextMut, 52207c71ab5SNick Fitzgerald allocator: &ArrayRefPre, 52307c71ab5SNick Fitzgerald elems: &[Val], 52407c71ab5SNick Fitzgerald ) -> Result<Rooted<ArrayRef>> { 525155ea7fcSAlex Crichton let (mut limiter, store) = store.as_context_mut().0.resource_limiter_and_store_opaque(); 526*cc8d04f4SAlex Crichton Self::_new_fixed_async(store, limiter.as_mut(), allocator, elems, Asyncness::Yes).await 52707c71ab5SNick Fitzgerald } 52807c71ab5SNick Fitzgerald _new_fixed_async( store: &mut StoreOpaque, limiter: Option<&mut StoreResourceLimiter<'_>>, allocator: &ArrayRefPre, elems: &[Val], asyncness: Asyncness, ) -> Result<Rooted<ArrayRef>>52907c71ab5SNick Fitzgerald pub(crate) async fn _new_fixed_async( 53007c71ab5SNick Fitzgerald store: &mut StoreOpaque, 531155ea7fcSAlex Crichton limiter: Option<&mut StoreResourceLimiter<'_>>, 53207c71ab5SNick Fitzgerald allocator: &ArrayRefPre, 53307c71ab5SNick Fitzgerald elems: &[Val], 534*cc8d04f4SAlex Crichton asyncness: Asyncness, 53507c71ab5SNick Fitzgerald ) -> Result<Rooted<ArrayRef>> { 53607c71ab5SNick Fitzgerald store 537*cc8d04f4SAlex Crichton .retry_after_gc_async(limiter, (), asyncness, |store, ()| { 53807c71ab5SNick Fitzgerald Self::new_from_iter(store, allocator, elems.iter()) 53907c71ab5SNick Fitzgerald }) 54007c71ab5SNick Fitzgerald .await 54107c71ab5SNick Fitzgerald } 54207c71ab5SNick Fitzgerald 543c4be2d84SNick Fitzgerald #[inline] comes_from_same_store(&self, store: &StoreOpaque) -> bool544c4be2d84SNick Fitzgerald pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool { 545c4be2d84SNick Fitzgerald self.inner.comes_from_same_store(store) 546c4be2d84SNick Fitzgerald } 547c4be2d84SNick Fitzgerald 548c4be2d84SNick Fitzgerald /// Get this `arrayref`'s type. 549c4be2d84SNick Fitzgerald /// 550c4be2d84SNick Fitzgerald /// # Errors 551c4be2d84SNick Fitzgerald /// 552c4be2d84SNick Fitzgerald /// Return an error if this reference has been unrooted. 553c4be2d84SNick Fitzgerald /// 554c4be2d84SNick Fitzgerald /// # Panics 555c4be2d84SNick Fitzgerald /// 556c4be2d84SNick Fitzgerald /// Panics if this reference is associated with a different store. ty(&self, store: impl AsContext) -> Result<ArrayType>557c4be2d84SNick Fitzgerald pub fn ty(&self, store: impl AsContext) -> Result<ArrayType> { 558c4be2d84SNick Fitzgerald self._ty(store.as_context().0) 559c4be2d84SNick Fitzgerald } 560c4be2d84SNick Fitzgerald _ty(&self, store: &StoreOpaque) -> Result<ArrayType>561c4be2d84SNick Fitzgerald pub(crate) fn _ty(&self, store: &StoreOpaque) -> Result<ArrayType> { 562c4be2d84SNick Fitzgerald assert!(self.comes_from_same_store(store)); 563c4be2d84SNick Fitzgerald let index = self.type_index(store)?; 564c4be2d84SNick Fitzgerald Ok(ArrayType::from_shared_type_index(store.engine(), index)) 565c4be2d84SNick Fitzgerald } 566c4be2d84SNick Fitzgerald 567c4be2d84SNick Fitzgerald /// Does this `arrayref` match the given type? 568c4be2d84SNick Fitzgerald /// 569c4be2d84SNick Fitzgerald /// That is, is this array's type a subtype of the given type? 570c4be2d84SNick Fitzgerald /// 571c4be2d84SNick Fitzgerald /// # Errors 572c4be2d84SNick Fitzgerald /// 573c4be2d84SNick Fitzgerald /// Return an error if this reference has been unrooted. 574c4be2d84SNick Fitzgerald /// 575c4be2d84SNick Fitzgerald /// # Panics 576c4be2d84SNick Fitzgerald /// 577c4be2d84SNick Fitzgerald /// Panics if this reference is associated with a different store or if the 578c4be2d84SNick Fitzgerald /// type is not associated with the store's engine. matches_ty(&self, store: impl AsContext, ty: &ArrayType) -> Result<bool>579c4be2d84SNick Fitzgerald pub fn matches_ty(&self, store: impl AsContext, ty: &ArrayType) -> Result<bool> { 580c4be2d84SNick Fitzgerald self._matches_ty(store.as_context().0, ty) 581c4be2d84SNick Fitzgerald } 582c4be2d84SNick Fitzgerald _matches_ty(&self, store: &StoreOpaque, ty: &ArrayType) -> Result<bool>583c4be2d84SNick Fitzgerald pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &ArrayType) -> Result<bool> { 584c4be2d84SNick Fitzgerald assert!(self.comes_from_same_store(store)); 585c4be2d84SNick Fitzgerald Ok(self._ty(store)?.matches(ty)) 586c4be2d84SNick Fitzgerald } 587c4be2d84SNick Fitzgerald ensure_matches_ty(&self, store: &StoreOpaque, ty: &ArrayType) -> Result<()>588c4be2d84SNick Fitzgerald pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &ArrayType) -> Result<()> { 589c4be2d84SNick Fitzgerald if !self.comes_from_same_store(store) { 590c4be2d84SNick Fitzgerald bail!("function used with wrong store"); 591c4be2d84SNick Fitzgerald } 592c4be2d84SNick Fitzgerald if self._matches_ty(store, ty)? { 593c4be2d84SNick Fitzgerald Ok(()) 594c4be2d84SNick Fitzgerald } else { 595c4be2d84SNick Fitzgerald let actual_ty = self._ty(store)?; 596c4be2d84SNick Fitzgerald bail!("type mismatch: expected `(ref {ty})`, found `(ref {actual_ty})`") 597c4be2d84SNick Fitzgerald } 598c4be2d84SNick Fitzgerald } 599c4be2d84SNick Fitzgerald 600c4be2d84SNick Fitzgerald /// Get the length of this array. 601c4be2d84SNick Fitzgerald /// 602c4be2d84SNick Fitzgerald /// # Errors 603c4be2d84SNick Fitzgerald /// 604c4be2d84SNick Fitzgerald /// Return an error if this reference has been unrooted. 605c4be2d84SNick Fitzgerald /// 606c4be2d84SNick Fitzgerald /// # Panics 607c4be2d84SNick Fitzgerald /// 608c4be2d84SNick Fitzgerald /// Panics if this reference is associated with a different store. len(&self, store: impl AsContext) -> Result<u32>609c4be2d84SNick Fitzgerald pub fn len(&self, store: impl AsContext) -> Result<u32> { 610c4be2d84SNick Fitzgerald self._len(store.as_context().0) 611c4be2d84SNick Fitzgerald } 612c4be2d84SNick Fitzgerald _len(&self, store: &StoreOpaque) -> Result<u32>613c4be2d84SNick Fitzgerald pub(crate) fn _len(&self, store: &StoreOpaque) -> Result<u32> { 614c4be2d84SNick Fitzgerald assert!(self.comes_from_same_store(store)); 615c4be2d84SNick Fitzgerald let gc_ref = self.inner.try_gc_ref(store)?; 616c4be2d84SNick Fitzgerald debug_assert!({ 617c6dddeafSAlex Crichton let header = store.require_gc_store()?.header(gc_ref); 618c4be2d84SNick Fitzgerald header.kind().matches(VMGcKind::ArrayRef) 619c4be2d84SNick Fitzgerald }); 620c4be2d84SNick Fitzgerald let arrayref = gc_ref.as_arrayref_unchecked(); 621c4be2d84SNick Fitzgerald Ok(arrayref.len(store)) 622c4be2d84SNick Fitzgerald } 623c4be2d84SNick Fitzgerald 624c4be2d84SNick Fitzgerald /// Get the values of this array's elements. 625c4be2d84SNick Fitzgerald /// 62607c71ab5SNick Fitzgerald /// Note that `i8` and `i16` element values are zero-extended into 627c4be2d84SNick Fitzgerald /// `Val::I32(_)`s. 628c4be2d84SNick Fitzgerald /// 629c4be2d84SNick Fitzgerald /// # Errors 630c4be2d84SNick Fitzgerald /// 631c4be2d84SNick Fitzgerald /// Return an error if this reference has been unrooted. 632c4be2d84SNick Fitzgerald /// 633c4be2d84SNick Fitzgerald /// # Panics 634c4be2d84SNick Fitzgerald /// 635c4be2d84SNick Fitzgerald /// Panics if this reference is associated with a different store. elems<'a, T: 'static>( &'a self, store: impl Into<StoreContextMut<'a, T>>, ) -> Result<impl ExactSizeIterator<Item = Val> + 'a>636f81c0dc0SAlex Crichton pub fn elems<'a, T: 'static>( 637c4be2d84SNick Fitzgerald &'a self, 638c4be2d84SNick Fitzgerald store: impl Into<StoreContextMut<'a, T>>, 639c4be2d84SNick Fitzgerald ) -> Result<impl ExactSizeIterator<Item = Val> + 'a> { 640c4be2d84SNick Fitzgerald self._elems(store.into().0) 641c4be2d84SNick Fitzgerald } 642c4be2d84SNick Fitzgerald _elems<'a>( &'a self, store: &'a mut StoreOpaque, ) -> Result<impl ExactSizeIterator<Item = Val> + 'a>643c4be2d84SNick Fitzgerald pub(crate) fn _elems<'a>( 644c4be2d84SNick Fitzgerald &'a self, 645c4be2d84SNick Fitzgerald store: &'a mut StoreOpaque, 646c4be2d84SNick Fitzgerald ) -> Result<impl ExactSizeIterator<Item = Val> + 'a> { 647c4be2d84SNick Fitzgerald assert!(self.comes_from_same_store(store)); 648c4be2d84SNick Fitzgerald let store = AutoAssertNoGc::new(store); 649c4be2d84SNick Fitzgerald 650c4be2d84SNick Fitzgerald let gc_ref = self.inner.try_gc_ref(&store)?; 651c6dddeafSAlex Crichton let header = store.require_gc_store()?.header(gc_ref); 652c4be2d84SNick Fitzgerald debug_assert!(header.kind().matches(VMGcKind::ArrayRef)); 653c4be2d84SNick Fitzgerald 654c4be2d84SNick Fitzgerald let len = self._len(&store)?; 655c4be2d84SNick Fitzgerald 656c4be2d84SNick Fitzgerald return Ok(Elems { 657c4be2d84SNick Fitzgerald arrayref: self, 658c4be2d84SNick Fitzgerald store, 659c4be2d84SNick Fitzgerald index: 0, 660c4be2d84SNick Fitzgerald len, 661c4be2d84SNick Fitzgerald }); 662c4be2d84SNick Fitzgerald 663c4be2d84SNick Fitzgerald struct Elems<'a, 'b> { 664c4be2d84SNick Fitzgerald arrayref: &'a ArrayRef, 665c4be2d84SNick Fitzgerald store: AutoAssertNoGc<'b>, 666c4be2d84SNick Fitzgerald index: u32, 667c4be2d84SNick Fitzgerald len: u32, 668c4be2d84SNick Fitzgerald } 669c4be2d84SNick Fitzgerald 670c4be2d84SNick Fitzgerald impl Iterator for Elems<'_, '_> { 671c4be2d84SNick Fitzgerald type Item = Val; 672c4be2d84SNick Fitzgerald 673c4be2d84SNick Fitzgerald #[inline] 674c4be2d84SNick Fitzgerald fn next(&mut self) -> Option<Self::Item> { 675c4be2d84SNick Fitzgerald let i = self.index; 676c4be2d84SNick Fitzgerald debug_assert!(i <= self.len); 677c4be2d84SNick Fitzgerald if i >= self.len { 678c4be2d84SNick Fitzgerald return None; 679c4be2d84SNick Fitzgerald } 680c4be2d84SNick Fitzgerald self.index += 1; 681c4be2d84SNick Fitzgerald Some(self.arrayref._get(&mut self.store, i).unwrap()) 682c4be2d84SNick Fitzgerald } 683c4be2d84SNick Fitzgerald 684c4be2d84SNick Fitzgerald #[inline] 685c4be2d84SNick Fitzgerald fn size_hint(&self) -> (usize, Option<usize>) { 686c4be2d84SNick Fitzgerald let len = self.len - self.index; 687c4be2d84SNick Fitzgerald let len = usize::try_from(len).unwrap(); 688c4be2d84SNick Fitzgerald (len, Some(len)) 689c4be2d84SNick Fitzgerald } 690c4be2d84SNick Fitzgerald } 691c4be2d84SNick Fitzgerald 692c4be2d84SNick Fitzgerald impl ExactSizeIterator for Elems<'_, '_> { 693c4be2d84SNick Fitzgerald #[inline] 694c4be2d84SNick Fitzgerald fn len(&self) -> usize { 695c4be2d84SNick Fitzgerald let len = self.len - self.index; 696c4be2d84SNick Fitzgerald usize::try_from(len).unwrap() 697c4be2d84SNick Fitzgerald } 698c4be2d84SNick Fitzgerald } 699c4be2d84SNick Fitzgerald } 700c4be2d84SNick Fitzgerald header<'a>(&self, store: &'a AutoAssertNoGc<'_>) -> Result<&'a VMGcHeader>701c4be2d84SNick Fitzgerald fn header<'a>(&self, store: &'a AutoAssertNoGc<'_>) -> Result<&'a VMGcHeader> { 702c4be2d84SNick Fitzgerald assert!(self.comes_from_same_store(&store)); 703c4be2d84SNick Fitzgerald let gc_ref = self.inner.try_gc_ref(store)?; 704c6dddeafSAlex Crichton Ok(store.require_gc_store()?.header(gc_ref)) 705c4be2d84SNick Fitzgerald } 706c4be2d84SNick Fitzgerald arrayref<'a>(&self, store: &'a AutoAssertNoGc<'_>) -> Result<&'a VMArrayRef>707c4be2d84SNick Fitzgerald fn arrayref<'a>(&self, store: &'a AutoAssertNoGc<'_>) -> Result<&'a VMArrayRef> { 708c4be2d84SNick Fitzgerald assert!(self.comes_from_same_store(&store)); 709c4be2d84SNick Fitzgerald let gc_ref = self.inner.try_gc_ref(store)?; 710c4be2d84SNick Fitzgerald debug_assert!(self.header(store)?.kind().matches(VMGcKind::ArrayRef)); 711c4be2d84SNick Fitzgerald Ok(gc_ref.as_arrayref_unchecked()) 712c4be2d84SNick Fitzgerald } 713c4be2d84SNick Fitzgerald layout(&self, store: &AutoAssertNoGc<'_>) -> Result<GcArrayLayout>714818966f3SNick Fitzgerald pub(crate) fn layout(&self, store: &AutoAssertNoGc<'_>) -> Result<GcArrayLayout> { 715c4be2d84SNick Fitzgerald assert!(self.comes_from_same_store(&store)); 716c4be2d84SNick Fitzgerald let type_index = self.type_index(store)?; 717c4be2d84SNick Fitzgerald let layout = store 718c4be2d84SNick Fitzgerald .engine() 719c4be2d84SNick Fitzgerald .signatures() 720c4be2d84SNick Fitzgerald .layout(type_index) 721c4be2d84SNick Fitzgerald .expect("array types should have GC layouts"); 722c4be2d84SNick Fitzgerald match layout { 723c4be2d84SNick Fitzgerald GcLayout::Array(a) => Ok(a), 724c4be2d84SNick Fitzgerald GcLayout::Struct(_) => unreachable!(), 725c4be2d84SNick Fitzgerald } 726c4be2d84SNick Fitzgerald } 727c4be2d84SNick Fitzgerald field_ty(&self, store: &StoreOpaque) -> Result<FieldType>728c4be2d84SNick Fitzgerald fn field_ty(&self, store: &StoreOpaque) -> Result<FieldType> { 729c4be2d84SNick Fitzgerald let ty = self._ty(store)?; 730c4be2d84SNick Fitzgerald Ok(ty.field_type()) 731c4be2d84SNick Fitzgerald } 732c4be2d84SNick Fitzgerald 733c4be2d84SNick Fitzgerald /// Get this array's `index`th element. 734c4be2d84SNick Fitzgerald /// 735c4be2d84SNick Fitzgerald /// Note that `i8` and `i16` field values are zero-extended into 736c4be2d84SNick Fitzgerald /// `Val::I32(_)`s. 737c4be2d84SNick Fitzgerald /// 738c4be2d84SNick Fitzgerald /// # Errors 739c4be2d84SNick Fitzgerald /// 740c4be2d84SNick Fitzgerald /// Returns an `Err(_)` if the index is out of bounds or this reference has 741c4be2d84SNick Fitzgerald /// been unrooted. 742c4be2d84SNick Fitzgerald /// 743c4be2d84SNick Fitzgerald /// # Panics 744c4be2d84SNick Fitzgerald /// 745c4be2d84SNick Fitzgerald /// Panics if this reference is associated with a different store. get(&self, mut store: impl AsContextMut, index: u32) -> Result<Val>746c4be2d84SNick Fitzgerald pub fn get(&self, mut store: impl AsContextMut, index: u32) -> Result<Val> { 747c4be2d84SNick Fitzgerald let mut store = AutoAssertNoGc::new(store.as_context_mut().0); 748c4be2d84SNick Fitzgerald self._get(&mut store, index) 749c4be2d84SNick Fitzgerald } 750c4be2d84SNick Fitzgerald _get(&self, store: &mut AutoAssertNoGc<'_>, index: u32) -> Result<Val>751c4be2d84SNick Fitzgerald pub(crate) fn _get(&self, store: &mut AutoAssertNoGc<'_>, index: u32) -> Result<Val> { 752c4be2d84SNick Fitzgerald assert!( 753c4be2d84SNick Fitzgerald self.comes_from_same_store(store), 754c4be2d84SNick Fitzgerald "attempted to use an array with the wrong store", 755c4be2d84SNick Fitzgerald ); 756c4be2d84SNick Fitzgerald let arrayref = self.arrayref(store)?.unchecked_copy(); 757c4be2d84SNick Fitzgerald let field_ty = self.field_ty(store)?; 758c4be2d84SNick Fitzgerald let layout = self.layout(store)?; 759c4be2d84SNick Fitzgerald let len = arrayref.len(store); 760c4be2d84SNick Fitzgerald ensure!( 761c4be2d84SNick Fitzgerald index < len, 762c4be2d84SNick Fitzgerald "index out of bounds: the length is {len} but the index is {index}" 763c4be2d84SNick Fitzgerald ); 764c4be2d84SNick Fitzgerald Ok(arrayref.read_elem(store, &layout, field_ty.element_type(), index)) 765c4be2d84SNick Fitzgerald } 766c4be2d84SNick Fitzgerald 767c4be2d84SNick Fitzgerald /// Set this array's `index`th element. 768c4be2d84SNick Fitzgerald /// 769c4be2d84SNick Fitzgerald /// # Errors 770c4be2d84SNick Fitzgerald /// 771c4be2d84SNick Fitzgerald /// Returns an error in the following scenarios: 772c4be2d84SNick Fitzgerald /// 773c4be2d84SNick Fitzgerald /// * When given a value of the wrong type, such as trying to write an `f32` 774c4be2d84SNick Fitzgerald /// value into an array of `i64` elements. 775c4be2d84SNick Fitzgerald /// 776c4be2d84SNick Fitzgerald /// * When the array elements are not mutable. 777c4be2d84SNick Fitzgerald /// 778c4be2d84SNick Fitzgerald /// * When `index` is not within the range `0..self.len(ctx)`. 779c4be2d84SNick Fitzgerald /// 780c4be2d84SNick Fitzgerald /// * When `value` is a GC reference that has since been unrooted. 781c4be2d84SNick Fitzgerald /// 782c4be2d84SNick Fitzgerald /// # Panics 783c4be2d84SNick Fitzgerald /// 784c4be2d84SNick Fitzgerald /// Panics if either this reference or the given `value` is associated with 785c4be2d84SNick Fitzgerald /// a different store. set(&self, mut store: impl AsContextMut, index: u32, value: Val) -> Result<()>786c4be2d84SNick Fitzgerald pub fn set(&self, mut store: impl AsContextMut, index: u32, value: Val) -> Result<()> { 787c4be2d84SNick Fitzgerald self._set(store.as_context_mut().0, index, value) 788c4be2d84SNick Fitzgerald } 789c4be2d84SNick Fitzgerald _set(&self, store: &mut StoreOpaque, index: u32, value: Val) -> Result<()>790c4be2d84SNick Fitzgerald pub(crate) fn _set(&self, store: &mut StoreOpaque, index: u32, value: Val) -> Result<()> { 791c4be2d84SNick Fitzgerald assert!( 792c4be2d84SNick Fitzgerald self.comes_from_same_store(store), 793c4be2d84SNick Fitzgerald "attempted to use an array with the wrong store", 794c4be2d84SNick Fitzgerald ); 795c4be2d84SNick Fitzgerald assert!( 796c4be2d84SNick Fitzgerald value.comes_from_same_store(store), 797c4be2d84SNick Fitzgerald "attempted to use a value with the wrong store", 798c4be2d84SNick Fitzgerald ); 799c4be2d84SNick Fitzgerald 800c4be2d84SNick Fitzgerald let mut store = AutoAssertNoGc::new(store); 801c4be2d84SNick Fitzgerald 802c4be2d84SNick Fitzgerald let field_ty = self.field_ty(&store)?; 803c4be2d84SNick Fitzgerald ensure!( 804c4be2d84SNick Fitzgerald field_ty.mutability().is_var(), 805c4be2d84SNick Fitzgerald "cannot set element {index}: array elements are not mutable" 806c4be2d84SNick Fitzgerald ); 807c4be2d84SNick Fitzgerald 808c4be2d84SNick Fitzgerald value 809c4be2d84SNick Fitzgerald .ensure_matches_ty(&store, &field_ty.element_type().unpack()) 810c4be2d84SNick Fitzgerald .with_context(|| format!("cannot set element {index}: type mismatch"))?; 811c4be2d84SNick Fitzgerald 812c4be2d84SNick Fitzgerald let layout = self.layout(&store)?; 813c4be2d84SNick Fitzgerald let arrayref = self.arrayref(&store)?.unchecked_copy(); 814c4be2d84SNick Fitzgerald 815c4be2d84SNick Fitzgerald let len = arrayref.len(&store); 816c4be2d84SNick Fitzgerald ensure!( 817c4be2d84SNick Fitzgerald index < len, 818c4be2d84SNick Fitzgerald "index out of bounds: the length is {len} but the index is {index}" 819c4be2d84SNick Fitzgerald ); 820c4be2d84SNick Fitzgerald 821c4be2d84SNick Fitzgerald arrayref.write_elem(&mut store, &layout, field_ty.element_type(), index, value) 822c4be2d84SNick Fitzgerald } 823c4be2d84SNick Fitzgerald type_index(&self, store: &StoreOpaque) -> Result<VMSharedTypeIndex>824c4be2d84SNick Fitzgerald pub(crate) fn type_index(&self, store: &StoreOpaque) -> Result<VMSharedTypeIndex> { 825c4be2d84SNick Fitzgerald let gc_ref = self.inner.try_gc_ref(store)?; 826c6dddeafSAlex Crichton let header = store.require_gc_store()?.header(gc_ref); 827c4be2d84SNick Fitzgerald debug_assert!(header.kind().matches(VMGcKind::ArrayRef)); 828c4be2d84SNick Fitzgerald Ok(header.ty().expect("arrayrefs should have concrete types")) 829c4be2d84SNick Fitzgerald } 830c4be2d84SNick Fitzgerald 831c4be2d84SNick Fitzgerald /// Create a new `Rooted<ArrayRef>` from the given GC reference. 832c4be2d84SNick Fitzgerald /// 833c4be2d84SNick Fitzgerald /// `gc_ref` should point to a valid `arrayref` and should belong to the 834c4be2d84SNick Fitzgerald /// store's GC heap. Failure to uphold these invariants is memory safe but 835c4be2d84SNick Fitzgerald /// will lead to general incorrectness such as panics or wrong results. from_cloned_gc_ref( store: &mut AutoAssertNoGc<'_>, gc_ref: VMGcRef, ) -> Rooted<Self>836c4be2d84SNick Fitzgerald pub(crate) fn from_cloned_gc_ref( 837c4be2d84SNick Fitzgerald store: &mut AutoAssertNoGc<'_>, 838c4be2d84SNick Fitzgerald gc_ref: VMGcRef, 839c4be2d84SNick Fitzgerald ) -> Rooted<Self> { 840d2e3f7a5SNick Fitzgerald debug_assert!(gc_ref.is_arrayref(&*store.unwrap_gc_store().gc_heap)); 841c4be2d84SNick Fitzgerald Rooted::new(store, gc_ref) 842c4be2d84SNick Fitzgerald } 843c4be2d84SNick Fitzgerald } 844c4be2d84SNick Fitzgerald 845c4be2d84SNick Fitzgerald unsafe impl WasmTy for Rooted<ArrayRef> { 846c4be2d84SNick Fitzgerald #[inline] valtype() -> ValType847c4be2d84SNick Fitzgerald fn valtype() -> ValType { 848c4be2d84SNick Fitzgerald ValType::Ref(RefType::new(false, HeapType::Array)) 849c4be2d84SNick Fitzgerald } 850c4be2d84SNick Fitzgerald 851c4be2d84SNick Fitzgerald #[inline] compatible_with_store(&self, store: &StoreOpaque) -> bool852c4be2d84SNick Fitzgerald fn compatible_with_store(&self, store: &StoreOpaque) -> bool { 853c4be2d84SNick Fitzgerald self.comes_from_same_store(store) 854c4be2d84SNick Fitzgerald } 855c4be2d84SNick Fitzgerald 856c4be2d84SNick Fitzgerald #[inline] dynamic_concrete_type_check( &self, store: &StoreOpaque, _nullable: bool, ty: &HeapType, ) -> Result<()>857c4be2d84SNick Fitzgerald fn dynamic_concrete_type_check( 858c4be2d84SNick Fitzgerald &self, 859c4be2d84SNick Fitzgerald store: &StoreOpaque, 860c4be2d84SNick Fitzgerald _nullable: bool, 861c4be2d84SNick Fitzgerald ty: &HeapType, 862c4be2d84SNick Fitzgerald ) -> Result<()> { 863c4be2d84SNick Fitzgerald match ty { 864c4be2d84SNick Fitzgerald HeapType::Any | HeapType::Eq | HeapType::Array => Ok(()), 865c4be2d84SNick Fitzgerald HeapType::ConcreteArray(ty) => self.ensure_matches_ty(store, ty), 866c4be2d84SNick Fitzgerald 867c4be2d84SNick Fitzgerald HeapType::Extern 868c4be2d84SNick Fitzgerald | HeapType::NoExtern 869c4be2d84SNick Fitzgerald | HeapType::Func 870c4be2d84SNick Fitzgerald | HeapType::ConcreteFunc(_) 871c4be2d84SNick Fitzgerald | HeapType::NoFunc 872c4be2d84SNick Fitzgerald | HeapType::I31 873c4be2d84SNick Fitzgerald | HeapType::Struct 874c4be2d84SNick Fitzgerald | HeapType::ConcreteStruct(_) 87563d482c8SFrank Emrich | HeapType::Cont 87663d482c8SFrank Emrich | HeapType::NoCont 87763d482c8SFrank Emrich | HeapType::ConcreteCont(_) 878eaa4632eSChris Fallin | HeapType::Exn 879eaa4632eSChris Fallin | HeapType::NoExn 880eaa4632eSChris Fallin | HeapType::ConcreteExn(_) 881c4be2d84SNick Fitzgerald | HeapType::None => bail!( 882c4be2d84SNick Fitzgerald "type mismatch: expected `(ref {ty})`, got `(ref {})`", 883c4be2d84SNick Fitzgerald self._ty(store)?, 884c4be2d84SNick Fitzgerald ), 885c4be2d84SNick Fitzgerald } 886c4be2d84SNick Fitzgerald } 887c4be2d84SNick Fitzgerald store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()>888c4be2d84SNick Fitzgerald fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> { 889c4be2d84SNick Fitzgerald self.wasm_ty_store(store, ptr, ValRaw::anyref) 890c4be2d84SNick Fitzgerald } 891c4be2d84SNick Fitzgerald load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self892c4be2d84SNick Fitzgerald unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self { 893c4be2d84SNick Fitzgerald Self::wasm_ty_load(store, ptr.get_anyref(), ArrayRef::from_cloned_gc_ref) 894c4be2d84SNick Fitzgerald } 895c4be2d84SNick Fitzgerald } 896c4be2d84SNick Fitzgerald 897c4be2d84SNick Fitzgerald unsafe impl WasmTy for Option<Rooted<ArrayRef>> { 898c4be2d84SNick Fitzgerald #[inline] valtype() -> ValType899c4be2d84SNick Fitzgerald fn valtype() -> ValType { 900c4be2d84SNick Fitzgerald ValType::ARRAYREF 901c4be2d84SNick Fitzgerald } 902c4be2d84SNick Fitzgerald 903c4be2d84SNick Fitzgerald #[inline] compatible_with_store(&self, store: &StoreOpaque) -> bool904c4be2d84SNick Fitzgerald fn compatible_with_store(&self, store: &StoreOpaque) -> bool { 905c4be2d84SNick Fitzgerald self.map_or(true, |x| x.comes_from_same_store(store)) 906c4be2d84SNick Fitzgerald } 907c4be2d84SNick Fitzgerald 908c4be2d84SNick Fitzgerald #[inline] dynamic_concrete_type_check( &self, store: &StoreOpaque, nullable: bool, ty: &HeapType, ) -> Result<()>909c4be2d84SNick Fitzgerald fn dynamic_concrete_type_check( 910c4be2d84SNick Fitzgerald &self, 911c4be2d84SNick Fitzgerald store: &StoreOpaque, 912c4be2d84SNick Fitzgerald nullable: bool, 913c4be2d84SNick Fitzgerald ty: &HeapType, 914c4be2d84SNick Fitzgerald ) -> Result<()> { 915c4be2d84SNick Fitzgerald match self { 916c4be2d84SNick Fitzgerald Some(s) => Rooted::<ArrayRef>::dynamic_concrete_type_check(s, store, nullable, ty), 917c4be2d84SNick Fitzgerald None => { 918c4be2d84SNick Fitzgerald ensure!( 919c4be2d84SNick Fitzgerald nullable, 920c4be2d84SNick Fitzgerald "expected a non-null reference, but found a null reference" 921c4be2d84SNick Fitzgerald ); 922c4be2d84SNick Fitzgerald Ok(()) 923c4be2d84SNick Fitzgerald } 924c4be2d84SNick Fitzgerald } 925c4be2d84SNick Fitzgerald } 926c4be2d84SNick Fitzgerald 927c4be2d84SNick Fitzgerald #[inline] is_vmgcref_and_points_to_object(&self) -> bool928c4be2d84SNick Fitzgerald fn is_vmgcref_and_points_to_object(&self) -> bool { 929c4be2d84SNick Fitzgerald self.is_some() 930c4be2d84SNick Fitzgerald } 931c4be2d84SNick Fitzgerald store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()>932c4be2d84SNick Fitzgerald fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> { 933c4be2d84SNick Fitzgerald <Rooted<ArrayRef>>::wasm_ty_option_store(self, store, ptr, ValRaw::anyref) 934c4be2d84SNick Fitzgerald } 935c4be2d84SNick Fitzgerald load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self936c4be2d84SNick Fitzgerald unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self { 937c4be2d84SNick Fitzgerald <Rooted<ArrayRef>>::wasm_ty_option_load( 938c4be2d84SNick Fitzgerald store, 939c4be2d84SNick Fitzgerald ptr.get_anyref(), 940c4be2d84SNick Fitzgerald ArrayRef::from_cloned_gc_ref, 941c4be2d84SNick Fitzgerald ) 942c4be2d84SNick Fitzgerald } 943c4be2d84SNick Fitzgerald } 944c4be2d84SNick Fitzgerald 9459826719aSChris Fallin unsafe impl WasmTy for OwnedRooted<ArrayRef> { 946c4be2d84SNick Fitzgerald #[inline] valtype() -> ValType947c4be2d84SNick Fitzgerald fn valtype() -> ValType { 948c4be2d84SNick Fitzgerald ValType::Ref(RefType::new(false, HeapType::Array)) 949c4be2d84SNick Fitzgerald } 950c4be2d84SNick Fitzgerald 951c4be2d84SNick Fitzgerald #[inline] compatible_with_store(&self, store: &StoreOpaque) -> bool952c4be2d84SNick Fitzgerald fn compatible_with_store(&self, store: &StoreOpaque) -> bool { 953c4be2d84SNick Fitzgerald self.comes_from_same_store(store) 954c4be2d84SNick Fitzgerald } 955c4be2d84SNick Fitzgerald 956c4be2d84SNick Fitzgerald #[inline] dynamic_concrete_type_check( &self, store: &StoreOpaque, _: bool, ty: &HeapType, ) -> Result<()>957c4be2d84SNick Fitzgerald fn dynamic_concrete_type_check( 958c4be2d84SNick Fitzgerald &self, 959c4be2d84SNick Fitzgerald store: &StoreOpaque, 960c4be2d84SNick Fitzgerald _: bool, 961c4be2d84SNick Fitzgerald ty: &HeapType, 962c4be2d84SNick Fitzgerald ) -> Result<()> { 963c4be2d84SNick Fitzgerald match ty { 964c4be2d84SNick Fitzgerald HeapType::Any | HeapType::Eq | HeapType::Array => Ok(()), 965c4be2d84SNick Fitzgerald HeapType::ConcreteArray(ty) => self.ensure_matches_ty(store, ty), 966c4be2d84SNick Fitzgerald 967c4be2d84SNick Fitzgerald HeapType::Extern 968c4be2d84SNick Fitzgerald | HeapType::NoExtern 969c4be2d84SNick Fitzgerald | HeapType::Func 970c4be2d84SNick Fitzgerald | HeapType::ConcreteFunc(_) 971c4be2d84SNick Fitzgerald | HeapType::NoFunc 972c4be2d84SNick Fitzgerald | HeapType::I31 973c4be2d84SNick Fitzgerald | HeapType::Struct 974c4be2d84SNick Fitzgerald | HeapType::ConcreteStruct(_) 97563d482c8SFrank Emrich | HeapType::Cont 97663d482c8SFrank Emrich | HeapType::NoCont 97763d482c8SFrank Emrich | HeapType::ConcreteCont(_) 978eaa4632eSChris Fallin | HeapType::Exn 979eaa4632eSChris Fallin | HeapType::NoExn 980eaa4632eSChris Fallin | HeapType::ConcreteExn(_) 981c4be2d84SNick Fitzgerald | HeapType::None => bail!( 982c4be2d84SNick Fitzgerald "type mismatch: expected `(ref {ty})`, got `(ref {})`", 983c4be2d84SNick Fitzgerald self._ty(store)?, 984c4be2d84SNick Fitzgerald ), 985c4be2d84SNick Fitzgerald } 986c4be2d84SNick Fitzgerald } 987c4be2d84SNick Fitzgerald store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()>988c4be2d84SNick Fitzgerald fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> { 989c4be2d84SNick Fitzgerald self.wasm_ty_store(store, ptr, ValRaw::anyref) 990c4be2d84SNick Fitzgerald } 991c4be2d84SNick Fitzgerald load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self992c4be2d84SNick Fitzgerald unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self { 993c4be2d84SNick Fitzgerald Self::wasm_ty_load(store, ptr.get_anyref(), ArrayRef::from_cloned_gc_ref) 994c4be2d84SNick Fitzgerald } 995c4be2d84SNick Fitzgerald } 996c4be2d84SNick Fitzgerald 9979826719aSChris Fallin unsafe impl WasmTy for Option<OwnedRooted<ArrayRef>> { 998c4be2d84SNick Fitzgerald #[inline] valtype() -> ValType999c4be2d84SNick Fitzgerald fn valtype() -> ValType { 1000c4be2d84SNick Fitzgerald ValType::ARRAYREF 1001c4be2d84SNick Fitzgerald } 1002c4be2d84SNick Fitzgerald 1003c4be2d84SNick Fitzgerald #[inline] compatible_with_store(&self, store: &StoreOpaque) -> bool1004c4be2d84SNick Fitzgerald fn compatible_with_store(&self, store: &StoreOpaque) -> bool { 1005c4be2d84SNick Fitzgerald self.as_ref() 1006c4be2d84SNick Fitzgerald .map_or(true, |x| x.comes_from_same_store(store)) 1007c4be2d84SNick Fitzgerald } 1008c4be2d84SNick Fitzgerald 1009c4be2d84SNick Fitzgerald #[inline] dynamic_concrete_type_check( &self, store: &StoreOpaque, nullable: bool, ty: &HeapType, ) -> Result<()>1010c4be2d84SNick Fitzgerald fn dynamic_concrete_type_check( 1011c4be2d84SNick Fitzgerald &self, 1012c4be2d84SNick Fitzgerald store: &StoreOpaque, 1013c4be2d84SNick Fitzgerald nullable: bool, 1014c4be2d84SNick Fitzgerald ty: &HeapType, 1015c4be2d84SNick Fitzgerald ) -> Result<()> { 1016c4be2d84SNick Fitzgerald match self { 10179826719aSChris Fallin Some(s) => OwnedRooted::<ArrayRef>::dynamic_concrete_type_check(s, store, nullable, ty), 1018c4be2d84SNick Fitzgerald None => { 1019c4be2d84SNick Fitzgerald ensure!( 1020c4be2d84SNick Fitzgerald nullable, 1021c4be2d84SNick Fitzgerald "expected a non-null reference, but found a null reference" 1022c4be2d84SNick Fitzgerald ); 1023c4be2d84SNick Fitzgerald Ok(()) 1024c4be2d84SNick Fitzgerald } 1025c4be2d84SNick Fitzgerald } 1026c4be2d84SNick Fitzgerald } 1027c4be2d84SNick Fitzgerald 1028c4be2d84SNick Fitzgerald #[inline] is_vmgcref_and_points_to_object(&self) -> bool1029c4be2d84SNick Fitzgerald fn is_vmgcref_and_points_to_object(&self) -> bool { 1030c4be2d84SNick Fitzgerald self.is_some() 1031c4be2d84SNick Fitzgerald } 1032c4be2d84SNick Fitzgerald store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()>1033c4be2d84SNick Fitzgerald fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> { 10349826719aSChris Fallin <OwnedRooted<ArrayRef>>::wasm_ty_option_store(self, store, ptr, ValRaw::anyref) 1035c4be2d84SNick Fitzgerald } 1036c4be2d84SNick Fitzgerald load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self1037c4be2d84SNick Fitzgerald unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self { 10389826719aSChris Fallin <OwnedRooted<ArrayRef>>::wasm_ty_option_load( 1039c4be2d84SNick Fitzgerald store, 1040c4be2d84SNick Fitzgerald ptr.get_anyref(), 1041c4be2d84SNick Fitzgerald ArrayRef::from_cloned_gc_ref, 1042c4be2d84SNick Fitzgerald ) 1043c4be2d84SNick Fitzgerald } 1044c4be2d84SNick Fitzgerald } 1045