190ac295eSAlex Crichton use super::{truncate_i32_to_i8, truncate_i32_to_i16};
2f2e689cdSNick Fitzgerald use crate::{
3eaa4632eSChris Fallin AnyRef, ExnRef, ExternRef, Func, HeapType, RootedGcRefImpl, StorageType, Val, ValType,
4f2e689cdSNick Fitzgerald prelude::*,
5f2e689cdSNick Fitzgerald runtime::vm::{GcHeap, GcStore, VMGcRef},
6f2e689cdSNick Fitzgerald store::AutoAssertNoGc,
79529243aSNick Fitzgerald vm::{FuncRefTableId, SendSyncPtr},
8f2e689cdSNick Fitzgerald };
9c4be2d84SNick Fitzgerald use core::fmt;
109c23d884SNick Fitzgerald use wasmtime_environ::{GcStructLayout, VMGcKind};
11f2e689cdSNick Fitzgerald
12f2e689cdSNick Fitzgerald /// A `VMGcRef` that we know points to a `struct`.
13f2e689cdSNick Fitzgerald ///
14f2e689cdSNick Fitzgerald /// Create a `VMStructRef` via `VMGcRef::into_structref` and
15f2e689cdSNick Fitzgerald /// `VMGcRef::as_structref`, or their untyped equivalents
16f2e689cdSNick Fitzgerald /// `VMGcRef::into_structref_unchecked` and `VMGcRef::as_structref_unchecked`.
17f2e689cdSNick Fitzgerald ///
18f2e689cdSNick Fitzgerald /// Note: This is not a `TypedGcRef<_>` because each collector can have a
19f2e689cdSNick Fitzgerald /// different concrete representation of `structref` that they allocate inside
20f2e689cdSNick Fitzgerald /// their heaps.
21f2e689cdSNick Fitzgerald #[derive(Debug, PartialEq, Eq, Hash)]
22f2e689cdSNick Fitzgerald #[repr(transparent)]
23f2e689cdSNick Fitzgerald pub struct VMStructRef(VMGcRef);
24f2e689cdSNick Fitzgerald
25f2e689cdSNick Fitzgerald impl fmt::Pointer for VMStructRef {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result26f2e689cdSNick Fitzgerald fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27f2e689cdSNick Fitzgerald fmt::Pointer::fmt(&self.0, f)
28f2e689cdSNick Fitzgerald }
29f2e689cdSNick Fitzgerald }
30f2e689cdSNick Fitzgerald
31f2e689cdSNick Fitzgerald impl From<VMStructRef> for VMGcRef {
32f2e689cdSNick Fitzgerald #[inline]
from(x: VMStructRef) -> Self33f2e689cdSNick Fitzgerald fn from(x: VMStructRef) -> Self {
34f2e689cdSNick Fitzgerald x.0
35f2e689cdSNick Fitzgerald }
36f2e689cdSNick Fitzgerald }
37f2e689cdSNick Fitzgerald
38f2e689cdSNick Fitzgerald impl VMGcRef {
39f2e689cdSNick Fitzgerald /// Is this `VMGcRef` pointing to a `struct`?
is_structref(&self, gc_heap: &(impl GcHeap + ?Sized)) -> bool40f2e689cdSNick Fitzgerald pub fn is_structref(&self, gc_heap: &(impl GcHeap + ?Sized)) -> bool {
41f2e689cdSNick Fitzgerald if self.is_i31() {
42f2e689cdSNick Fitzgerald return false;
43f2e689cdSNick Fitzgerald }
44f2e689cdSNick Fitzgerald
45f2e689cdSNick Fitzgerald let header = gc_heap.header(&self);
46f2e689cdSNick Fitzgerald header.kind().matches(VMGcKind::StructRef)
47f2e689cdSNick Fitzgerald }
48f2e689cdSNick Fitzgerald
49f2e689cdSNick Fitzgerald /// Create a new `VMStructRef` from the given `gc_ref`.
50f2e689cdSNick Fitzgerald ///
51f2e689cdSNick Fitzgerald /// If this is not a GC reference to an `structref`, `Err(self)` is
52f2e689cdSNick Fitzgerald /// returned.
into_structref(self, gc_heap: &impl GcHeap) -> Result<VMStructRef, VMGcRef>53f2e689cdSNick Fitzgerald pub fn into_structref(self, gc_heap: &impl GcHeap) -> Result<VMStructRef, VMGcRef> {
54f2e689cdSNick Fitzgerald if self.is_structref(gc_heap) {
55f2e689cdSNick Fitzgerald Ok(self.into_structref_unchecked())
56f2e689cdSNick Fitzgerald } else {
57f2e689cdSNick Fitzgerald Err(self)
58f2e689cdSNick Fitzgerald }
59f2e689cdSNick Fitzgerald }
60f2e689cdSNick Fitzgerald
61f2e689cdSNick Fitzgerald /// Create a new `VMStructRef` from `self` without actually checking that
62f2e689cdSNick Fitzgerald /// `self` is an `structref`.
63f2e689cdSNick Fitzgerald ///
64f2e689cdSNick Fitzgerald /// This method does not check that `self` is actually an `structref`, but
65f2e689cdSNick Fitzgerald /// it should be. Failure to uphold this invariant is memory safe but will
66f2e689cdSNick Fitzgerald /// result in general incorrectness down the line such as panics or wrong
67f2e689cdSNick Fitzgerald /// results.
68f2e689cdSNick Fitzgerald #[inline]
into_structref_unchecked(self) -> VMStructRef69f2e689cdSNick Fitzgerald pub fn into_structref_unchecked(self) -> VMStructRef {
70f2e689cdSNick Fitzgerald debug_assert!(!self.is_i31());
71f2e689cdSNick Fitzgerald VMStructRef(self)
72f2e689cdSNick Fitzgerald }
73f2e689cdSNick Fitzgerald
74f2e689cdSNick Fitzgerald /// Get this GC reference as an `structref` reference, if it actually is an
75f2e689cdSNick Fitzgerald /// `structref` reference.
as_structref(&self, gc_heap: &(impl GcHeap + ?Sized)) -> Option<&VMStructRef>76f2e689cdSNick Fitzgerald pub fn as_structref(&self, gc_heap: &(impl GcHeap + ?Sized)) -> Option<&VMStructRef> {
77f2e689cdSNick Fitzgerald if self.is_structref(gc_heap) {
78f2e689cdSNick Fitzgerald Some(self.as_structref_unchecked())
79f2e689cdSNick Fitzgerald } else {
80f2e689cdSNick Fitzgerald None
81f2e689cdSNick Fitzgerald }
82f2e689cdSNick Fitzgerald }
83f2e689cdSNick Fitzgerald
84f2e689cdSNick Fitzgerald /// Get this GC reference as an `structref` reference without checking if it
85f2e689cdSNick Fitzgerald /// actually is an `structref` reference.
86f2e689cdSNick Fitzgerald ///
87f2e689cdSNick Fitzgerald /// Calling this method on a non-`structref` reference is memory safe, but
88f2e689cdSNick Fitzgerald /// will lead to general incorrectness like panics and wrong results.
as_structref_unchecked(&self) -> &VMStructRef89f2e689cdSNick Fitzgerald pub fn as_structref_unchecked(&self) -> &VMStructRef {
90f2e689cdSNick Fitzgerald debug_assert!(!self.is_i31());
91f2e689cdSNick Fitzgerald let ptr = self as *const VMGcRef;
92f2e689cdSNick Fitzgerald let ret = unsafe { &*ptr.cast() };
93f2e689cdSNick Fitzgerald assert!(matches!(ret, VMStructRef(VMGcRef { .. })));
94f2e689cdSNick Fitzgerald ret
95f2e689cdSNick Fitzgerald }
96f2e689cdSNick Fitzgerald }
97f2e689cdSNick Fitzgerald
98f2e689cdSNick Fitzgerald impl VMStructRef {
99f2e689cdSNick Fitzgerald /// Get the underlying `VMGcRef`.
as_gc_ref(&self) -> &VMGcRef100f2e689cdSNick Fitzgerald pub fn as_gc_ref(&self) -> &VMGcRef {
101f2e689cdSNick Fitzgerald &self.0
102f2e689cdSNick Fitzgerald }
103f2e689cdSNick Fitzgerald
104f2e689cdSNick Fitzgerald /// Clone this `VMStructRef`, running any GC barriers as necessary.
clone(&self, gc_store: &mut GcStore) -> Self105f2e689cdSNick Fitzgerald pub fn clone(&self, gc_store: &mut GcStore) -> Self {
106f2e689cdSNick Fitzgerald Self(gc_store.clone_gc_ref(&self.0))
107f2e689cdSNick Fitzgerald }
108f2e689cdSNick Fitzgerald
109f2e689cdSNick Fitzgerald /// Explicitly drop this `structref`, running GC drop barriers as necessary.
drop(self, gc_store: &mut GcStore)110f2e689cdSNick Fitzgerald pub fn drop(self, gc_store: &mut GcStore) {
111f2e689cdSNick Fitzgerald gc_store.drop_gc_ref(self.0);
112f2e689cdSNick Fitzgerald }
113f2e689cdSNick Fitzgerald
114f2e689cdSNick Fitzgerald /// Copy this `VMStructRef` without running the GC's clone barriers.
115f2e689cdSNick Fitzgerald ///
116f2e689cdSNick Fitzgerald /// Prefer calling `clone(&mut GcStore)` instead! This is mostly an internal
117f2e689cdSNick Fitzgerald /// escape hatch for collector implementations.
118f2e689cdSNick Fitzgerald ///
119f2e689cdSNick Fitzgerald /// Failure to run GC barriers when they would otherwise be necessary can
120f2e689cdSNick Fitzgerald /// lead to leaks, panics, and wrong results. It cannot lead to memory
121f2e689cdSNick Fitzgerald /// unsafety, however.
unchecked_copy(&self) -> Self122f2e689cdSNick Fitzgerald pub fn unchecked_copy(&self) -> Self {
123f2e689cdSNick Fitzgerald Self(self.0.unchecked_copy())
124f2e689cdSNick Fitzgerald }
125f2e689cdSNick Fitzgerald
126f2e689cdSNick Fitzgerald /// Read a field of the given `StorageType` into a `Val`.
127f2e689cdSNick Fitzgerald ///
128f2e689cdSNick Fitzgerald /// `i8` and `i16` fields are zero-extended into `Val::I32(_)`s.
129f2e689cdSNick Fitzgerald ///
130f2e689cdSNick Fitzgerald /// Does not check that the field is actually of type `ty`. That is the
131f2e689cdSNick Fitzgerald /// caller's responsibility. Failure to do so is memory safe, but will lead
132f2e689cdSNick Fitzgerald /// to general incorrectness such as panics and wrong results.
133f2e689cdSNick Fitzgerald ///
134f2e689cdSNick Fitzgerald /// Panics on out-of-bounds accesses.
read_field( &self, store: &mut AutoAssertNoGc, layout: &GcStructLayout, ty: &StorageType, field: usize, ) -> Val135f2e689cdSNick Fitzgerald pub fn read_field(
136f2e689cdSNick Fitzgerald &self,
137f2e689cdSNick Fitzgerald store: &mut AutoAssertNoGc,
138f2e689cdSNick Fitzgerald layout: &GcStructLayout,
139f2e689cdSNick Fitzgerald ty: &StorageType,
140f2e689cdSNick Fitzgerald field: usize,
141f2e689cdSNick Fitzgerald ) -> Val {
1420a29578fSNick Fitzgerald let offset = layout.fields[field].offset;
143eaa4632eSChris Fallin read_field_impl(self.as_gc_ref(), store, ty, offset)
144f2e689cdSNick Fitzgerald }
145f2e689cdSNick Fitzgerald
146f2e689cdSNick Fitzgerald /// Write the given value into this struct at the given offset.
147f2e689cdSNick Fitzgerald ///
148f2e689cdSNick Fitzgerald /// Returns an error if `val` is a GC reference that has since been
149f2e689cdSNick Fitzgerald /// unrooted.
150f2e689cdSNick Fitzgerald ///
151f2e689cdSNick Fitzgerald /// Does not check that `val` matches `ty`, nor that the field is actually
152f2e689cdSNick Fitzgerald /// of type `ty`. Checking those things is the caller's responsibility.
153f2e689cdSNick Fitzgerald /// Failure to do so is memory safe, but will lead to general incorrectness
154f2e689cdSNick Fitzgerald /// such as panics and wrong results.
155f2e689cdSNick Fitzgerald ///
156f2e689cdSNick Fitzgerald /// Panics on out-of-bounds accesses.
write_field( &self, store: &mut AutoAssertNoGc, layout: &GcStructLayout, ty: &StorageType, field: usize, val: Val, ) -> Result<()>157f2e689cdSNick Fitzgerald pub fn write_field(
158f2e689cdSNick Fitzgerald &self,
159f2e689cdSNick Fitzgerald store: &mut AutoAssertNoGc,
160f2e689cdSNick Fitzgerald layout: &GcStructLayout,
161f2e689cdSNick Fitzgerald ty: &StorageType,
162f2e689cdSNick Fitzgerald field: usize,
163f2e689cdSNick Fitzgerald val: Val,
164f2e689cdSNick Fitzgerald ) -> Result<()> {
165f2e689cdSNick Fitzgerald debug_assert!(val._matches_ty(&store, &ty.unpack())?);
166f2e689cdSNick Fitzgerald
1670a29578fSNick Fitzgerald let offset = layout.fields[field].offset;
168c6dddeafSAlex Crichton let gcstore = store.require_gc_store_mut()?;
169c6dddeafSAlex Crichton let data = gcstore.gc_object_data(self.as_gc_ref());
170f2e689cdSNick Fitzgerald match val {
1710bce0968SAlex Crichton Val::I32(i) if ty.is_i8() => data.write_i8(offset, truncate_i32_to_i8(i)),
1720bce0968SAlex Crichton Val::I32(i) if ty.is_i16() => data.write_i16(offset, truncate_i32_to_i16(i)),
173f2e689cdSNick Fitzgerald Val::I32(i) => data.write_i32(offset, i),
174f2e689cdSNick Fitzgerald Val::I64(i) => data.write_i64(offset, i),
175f2e689cdSNick Fitzgerald Val::F32(f) => data.write_u32(offset, f),
176f2e689cdSNick Fitzgerald Val::F64(f) => data.write_u64(offset, f),
177f2e689cdSNick Fitzgerald Val::V128(v) => data.write_v128(offset, v),
178f2e689cdSNick Fitzgerald
179f2e689cdSNick Fitzgerald // For GC-managed references, we need to take care to run the
180f2e689cdSNick Fitzgerald // appropriate barriers, even when we are writing null references
181f2e689cdSNick Fitzgerald // into the struct.
182f2e689cdSNick Fitzgerald //
183f2e689cdSNick Fitzgerald // POD-read the old value into a local copy, run the GC write
184f2e689cdSNick Fitzgerald // barrier on that local copy, and then POD-write the updated
185f2e689cdSNick Fitzgerald // value back into the struct. This avoids transmuting the inner
186f2e689cdSNick Fitzgerald // data, which would probably be fine, but this approach is
187f2e689cdSNick Fitzgerald // Obviously Correct and should get us by for now. If LLVM isn't
188f2e689cdSNick Fitzgerald // able to elide some of these unnecessary copies, and this
189f2e689cdSNick Fitzgerald // method is ever hot enough, we can always come back and clean
190f2e689cdSNick Fitzgerald // it up in the future.
191f2e689cdSNick Fitzgerald Val::ExternRef(e) => {
192f2e689cdSNick Fitzgerald let raw = data.read_u32(offset);
193f2e689cdSNick Fitzgerald let mut gc_ref = VMGcRef::from_raw_u32(raw);
194f2e689cdSNick Fitzgerald let e = match e {
195f2e689cdSNick Fitzgerald Some(e) => Some(e.try_gc_ref(store)?.unchecked_copy()),
196f2e689cdSNick Fitzgerald None => None,
197f2e689cdSNick Fitzgerald };
198c6dddeafSAlex Crichton let store = store.require_gc_store_mut()?;
199c6dddeafSAlex Crichton store.write_gc_ref(&mut gc_ref, e.as_ref());
200c6dddeafSAlex Crichton let data = store.gc_object_data(self.as_gc_ref());
201f2e689cdSNick Fitzgerald data.write_u32(offset, gc_ref.map_or(0, |r| r.as_raw_u32()));
202f2e689cdSNick Fitzgerald }
203f2e689cdSNick Fitzgerald Val::AnyRef(a) => {
204f2e689cdSNick Fitzgerald let raw = data.read_u32(offset);
205f2e689cdSNick Fitzgerald let mut gc_ref = VMGcRef::from_raw_u32(raw);
206f2e689cdSNick Fitzgerald let a = match a {
207f2e689cdSNick Fitzgerald Some(a) => Some(a.try_gc_ref(store)?.unchecked_copy()),
208f2e689cdSNick Fitzgerald None => None,
209f2e689cdSNick Fitzgerald };
210c6dddeafSAlex Crichton let store = store.require_gc_store_mut()?;
211c6dddeafSAlex Crichton store.write_gc_ref(&mut gc_ref, a.as_ref());
212c6dddeafSAlex Crichton let data = store.gc_object_data(self.as_gc_ref());
213f2e689cdSNick Fitzgerald data.write_u32(offset, gc_ref.map_or(0, |r| r.as_raw_u32()));
214f2e689cdSNick Fitzgerald }
215eaa4632eSChris Fallin Val::ExnRef(e) => {
216eaa4632eSChris Fallin let raw = data.read_u32(offset);
217eaa4632eSChris Fallin let mut gc_ref = VMGcRef::from_raw_u32(raw);
218eaa4632eSChris Fallin let e = match e {
219eaa4632eSChris Fallin Some(e) => Some(e.try_gc_ref(store)?.unchecked_copy()),
220eaa4632eSChris Fallin None => None,
221eaa4632eSChris Fallin };
222c6dddeafSAlex Crichton let store = store.require_gc_store_mut()?;
223c6dddeafSAlex Crichton store.write_gc_ref(&mut gc_ref, e.as_ref());
224c6dddeafSAlex Crichton let data = store.gc_object_data(self.as_gc_ref());
225eaa4632eSChris Fallin data.write_u32(offset, gc_ref.map_or(0, |r| r.as_raw_u32()));
226eaa4632eSChris Fallin }
227f2e689cdSNick Fitzgerald
2289529243aSNick Fitzgerald Val::FuncRef(f) => {
2299529243aSNick Fitzgerald let f = f.map(|f| SendSyncPtr::new(f.vm_func_ref(store)));
230c6dddeafSAlex Crichton let gcstore = store.require_gc_store_mut()?;
231c6dddeafSAlex Crichton let id = unsafe { gcstore.func_ref_table.intern(f) };
232c6dddeafSAlex Crichton gcstore
2339529243aSNick Fitzgerald .gc_object_data(self.as_gc_ref())
2349529243aSNick Fitzgerald .write_u32(offset, id.into_raw());
2359529243aSNick Fitzgerald }
236a631d20aSPaul Osborne Val::ContRef(_) => {
237a631d20aSPaul Osborne // TODO(#10248): Implement struct continuation reference field handling
238*96e19700SNick Fitzgerald return Err(crate::format_err!(
239a631d20aSPaul Osborne "setting continuation references in struct fields not yet supported"
240a631d20aSPaul Osborne ));
241a631d20aSPaul Osborne }
242f2e689cdSNick Fitzgerald }
243f2e689cdSNick Fitzgerald Ok(())
244f2e689cdSNick Fitzgerald }
245f2e689cdSNick Fitzgerald
246f2e689cdSNick Fitzgerald /// Initialize a field in this structref that is currently uninitialized.
247f2e689cdSNick Fitzgerald ///
248f2e689cdSNick Fitzgerald /// The difference between this method and `write_field` is that GC barriers
249f2e689cdSNick Fitzgerald /// are handled differently. When overwriting an initialized field (aka
250f2e689cdSNick Fitzgerald /// `write_field`) we need to call the full write GC write barrier, which
251f2e689cdSNick Fitzgerald /// logically drops the old GC reference and clones the new GC
252f2e689cdSNick Fitzgerald /// reference. When we are initializing a field for the first time, there is
253f2e689cdSNick Fitzgerald /// no old GC reference that is being overwritten and which we need to drop,
254f2e689cdSNick Fitzgerald /// so we only need to clone the new GC reference.
255f2e689cdSNick Fitzgerald ///
256f2e689cdSNick Fitzgerald /// Calling this method on a structref that has already had the associated
257f2e689cdSNick Fitzgerald /// field initialized will result in GC bugs. These are memory safe but will
258f2e689cdSNick Fitzgerald /// lead to generally incorrect behavior such as panics, leaks, and
259f2e689cdSNick Fitzgerald /// incorrect results.
260f2e689cdSNick Fitzgerald ///
261f2e689cdSNick Fitzgerald /// Does not check that `val` matches `ty`, nor that the field is actually
262f2e689cdSNick Fitzgerald /// of type `ty`. Checking those things is the caller's responsibility.
263f2e689cdSNick Fitzgerald /// Failure to do so is memory safe, but will lead to general incorrectness
264f2e689cdSNick Fitzgerald /// such as panics and wrong results.
265f2e689cdSNick Fitzgerald ///
266f2e689cdSNick Fitzgerald /// Returns an error if `val` is a GC reference that has since been
267f2e689cdSNick Fitzgerald /// unrooted.
268f2e689cdSNick Fitzgerald ///
269f2e689cdSNick Fitzgerald /// Panics on out-of-bounds accesses.
initialize_field( &self, store: &mut AutoAssertNoGc, layout: &GcStructLayout, ty: &StorageType, field: usize, val: Val, ) -> Result<()>270f2e689cdSNick Fitzgerald pub fn initialize_field(
271f2e689cdSNick Fitzgerald &self,
272f2e689cdSNick Fitzgerald store: &mut AutoAssertNoGc,
273f2e689cdSNick Fitzgerald layout: &GcStructLayout,
274f2e689cdSNick Fitzgerald ty: &StorageType,
275f2e689cdSNick Fitzgerald field: usize,
276f2e689cdSNick Fitzgerald val: Val,
277f2e689cdSNick Fitzgerald ) -> Result<()> {
278f2e689cdSNick Fitzgerald debug_assert!(val._matches_ty(&store, &ty.unpack())?);
2790a29578fSNick Fitzgerald let offset = layout.fields[field].offset;
280eaa4632eSChris Fallin initialize_field_impl(self.as_gc_ref(), store, ty, offset, val)
281eaa4632eSChris Fallin }
282eaa4632eSChris Fallin }
283eaa4632eSChris Fallin
284eaa4632eSChris Fallin /// Read a field from a GC object at a given offset.
285eaa4632eSChris Fallin ///
286eaa4632eSChris Fallin /// This factored-out function allows a shared implementation for both
287eaa4632eSChris Fallin /// structs (this module) and exception objects.
read_field_impl( gc_ref: &VMGcRef, store: &mut AutoAssertNoGc, ty: &StorageType, offset: u32, ) -> Val288eaa4632eSChris Fallin pub(crate) fn read_field_impl(
289eaa4632eSChris Fallin gc_ref: &VMGcRef,
290eaa4632eSChris Fallin store: &mut AutoAssertNoGc,
291eaa4632eSChris Fallin ty: &StorageType,
292eaa4632eSChris Fallin offset: u32,
293eaa4632eSChris Fallin ) -> Val {
294eaa4632eSChris Fallin let data = store.unwrap_gc_store_mut().gc_object_data(gc_ref);
295eaa4632eSChris Fallin match ty {
296eaa4632eSChris Fallin StorageType::I8 => Val::I32(data.read_u8(offset).into()),
297eaa4632eSChris Fallin StorageType::I16 => Val::I32(data.read_u16(offset).into()),
298eaa4632eSChris Fallin StorageType::ValType(ValType::I32) => Val::I32(data.read_i32(offset)),
299eaa4632eSChris Fallin StorageType::ValType(ValType::I64) => Val::I64(data.read_i64(offset)),
300eaa4632eSChris Fallin StorageType::ValType(ValType::F32) => Val::F32(data.read_u32(offset)),
301eaa4632eSChris Fallin StorageType::ValType(ValType::F64) => Val::F64(data.read_u64(offset)),
302eaa4632eSChris Fallin StorageType::ValType(ValType::V128) => Val::V128(data.read_v128(offset)),
303eaa4632eSChris Fallin StorageType::ValType(ValType::Ref(r)) => match r.heap_type().top() {
304eaa4632eSChris Fallin HeapType::Extern => {
305eaa4632eSChris Fallin let raw = data.read_u32(offset);
306eaa4632eSChris Fallin Val::ExternRef(ExternRef::_from_raw(store, raw))
307eaa4632eSChris Fallin }
308eaa4632eSChris Fallin HeapType::Any => {
309eaa4632eSChris Fallin let raw = data.read_u32(offset);
310eaa4632eSChris Fallin Val::AnyRef(AnyRef::_from_raw(store, raw))
311eaa4632eSChris Fallin }
312eaa4632eSChris Fallin HeapType::Exn => {
313eaa4632eSChris Fallin let raw = data.read_u32(offset);
314eaa4632eSChris Fallin Val::ExnRef(ExnRef::_from_raw(store, raw))
315eaa4632eSChris Fallin }
316eaa4632eSChris Fallin HeapType::Func => {
317eaa4632eSChris Fallin let func_ref_id = data.read_u32(offset);
318eaa4632eSChris Fallin let func_ref_id = FuncRefTableId::from_raw(func_ref_id);
319eaa4632eSChris Fallin let func_ref = store
320eaa4632eSChris Fallin .unwrap_gc_store()
321eaa4632eSChris Fallin .func_ref_table
322eaa4632eSChris Fallin .get_untyped(func_ref_id);
323eaa4632eSChris Fallin Val::FuncRef(unsafe {
324eaa4632eSChris Fallin func_ref.map(|p| Func::from_vm_func_ref(store.id(), p.as_non_null()))
325eaa4632eSChris Fallin })
326eaa4632eSChris Fallin }
327eaa4632eSChris Fallin otherwise => unreachable!("not a top type: {otherwise:?}"),
328eaa4632eSChris Fallin },
329eaa4632eSChris Fallin }
330eaa4632eSChris Fallin }
331eaa4632eSChris Fallin
initialize_field_impl( gc_ref: &VMGcRef, store: &mut AutoAssertNoGc, ty: &StorageType, offset: u32, val: Val, ) -> Result<()>332eaa4632eSChris Fallin pub(crate) fn initialize_field_impl(
333eaa4632eSChris Fallin gc_ref: &VMGcRef,
334eaa4632eSChris Fallin store: &mut AutoAssertNoGc,
335eaa4632eSChris Fallin ty: &StorageType,
336eaa4632eSChris Fallin offset: u32,
337eaa4632eSChris Fallin val: Val,
338eaa4632eSChris Fallin ) -> Result<()> {
339c6dddeafSAlex Crichton let gcstore = store.require_gc_store_mut()?;
340f2e689cdSNick Fitzgerald match val {
341c6dddeafSAlex Crichton Val::I32(i) if ty.is_i8() => gcstore
342eaa4632eSChris Fallin .gc_object_data(gc_ref)
3430bce0968SAlex Crichton .write_i8(offset, truncate_i32_to_i8(i)),
344c6dddeafSAlex Crichton Val::I32(i) if ty.is_i16() => gcstore
345eaa4632eSChris Fallin .gc_object_data(gc_ref)
3460bce0968SAlex Crichton .write_i16(offset, truncate_i32_to_i16(i)),
347c6dddeafSAlex Crichton Val::I32(i) => gcstore.gc_object_data(gc_ref).write_i32(offset, i),
348c6dddeafSAlex Crichton Val::I64(i) => gcstore.gc_object_data(gc_ref).write_i64(offset, i),
349c6dddeafSAlex Crichton Val::F32(f) => gcstore.gc_object_data(gc_ref).write_u32(offset, f),
350c6dddeafSAlex Crichton Val::F64(f) => gcstore.gc_object_data(gc_ref).write_u64(offset, f),
351c6dddeafSAlex Crichton Val::V128(v) => gcstore.gc_object_data(gc_ref).write_v128(offset, v),
352f2e689cdSNick Fitzgerald
353f2e689cdSNick Fitzgerald // NB: We don't need to do a write barrier when initializing a
354f2e689cdSNick Fitzgerald // field, because there is nothing being overwritten. Therefore, we
355f2e689cdSNick Fitzgerald // just the clone barrier.
356f2e689cdSNick Fitzgerald Val::ExternRef(x) => {
357f2e689cdSNick Fitzgerald let x = match x {
358f2e689cdSNick Fitzgerald None => 0,
359f2e689cdSNick Fitzgerald Some(x) => x.try_clone_gc_ref(store)?.as_raw_u32(),
360f2e689cdSNick Fitzgerald };
361f2e689cdSNick Fitzgerald store
362c6dddeafSAlex Crichton .require_gc_store_mut()?
363eaa4632eSChris Fallin .gc_object_data(gc_ref)
364f2e689cdSNick Fitzgerald .write_u32(offset, x);
365f2e689cdSNick Fitzgerald }
366f2e689cdSNick Fitzgerald Val::AnyRef(x) => {
367f2e689cdSNick Fitzgerald let x = match x {
368f2e689cdSNick Fitzgerald None => 0,
369f2e689cdSNick Fitzgerald Some(x) => x.try_clone_gc_ref(store)?.as_raw_u32(),
370f2e689cdSNick Fitzgerald };
371f2e689cdSNick Fitzgerald store
372c6dddeafSAlex Crichton .require_gc_store_mut()?
373eaa4632eSChris Fallin .gc_object_data(gc_ref)
374eaa4632eSChris Fallin .write_u32(offset, x);
375eaa4632eSChris Fallin }
376eaa4632eSChris Fallin Val::ExnRef(x) => {
377eaa4632eSChris Fallin let x = match x {
378eaa4632eSChris Fallin None => 0,
379eaa4632eSChris Fallin Some(x) => x.try_clone_gc_ref(store)?.as_raw_u32(),
380eaa4632eSChris Fallin };
381eaa4632eSChris Fallin store
382c6dddeafSAlex Crichton .require_gc_store_mut()?
383eaa4632eSChris Fallin .gc_object_data(gc_ref)
384f2e689cdSNick Fitzgerald .write_u32(offset, x);
385f2e689cdSNick Fitzgerald }
386f2e689cdSNick Fitzgerald
3879529243aSNick Fitzgerald Val::FuncRef(f) => {
3889529243aSNick Fitzgerald let f = f.map(|f| SendSyncPtr::new(f.vm_func_ref(store)));
389c6dddeafSAlex Crichton let gcstore = store.require_gc_store_mut()?;
390c6dddeafSAlex Crichton let id = unsafe { gcstore.func_ref_table.intern(f) };
391c6dddeafSAlex Crichton gcstore
392eaa4632eSChris Fallin .gc_object_data(gc_ref)
3939529243aSNick Fitzgerald .write_u32(offset, id.into_raw());
394f2e689cdSNick Fitzgerald }
395a631d20aSPaul Osborne Val::ContRef(_) => {
396a631d20aSPaul Osborne // TODO(#10248): Implement struct continuation reference field init handling
397*96e19700SNick Fitzgerald return Err(crate::format_err!(
398a631d20aSPaul Osborne "initializing continuation references in struct fields not yet supported"
399a631d20aSPaul Osborne ));
400a631d20aSPaul Osborne }
401f2e689cdSNick Fitzgerald }
402f2e689cdSNick Fitzgerald Ok(())
403f2e689cdSNick Fitzgerald }
404