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