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