Skip to content

Commit 735bc9c

Browse files
authored
Implement TryClone for GcLayout (#12616)
And also make it so that cloning it doesn't actually require any allocations by wrapping the inner `GcStructLayout` in an `Arc`.
1 parent 40df277 commit 735bc9c

4 files changed

Lines changed: 47 additions & 16 deletions

File tree

crates/environ/src/gc.rs

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@ pub mod drc;
1616
pub mod null;
1717

1818
use crate::{
19-
WasmArrayType, WasmCompositeInnerType, WasmCompositeType, WasmStorageType, WasmStructType,
20-
WasmValType,
19+
WasmArrayType, WasmCompositeInnerType, WasmCompositeType, WasmExnType, WasmStorageType,
20+
WasmStructType, WasmValType,
21+
collections::{self, TryClone},
22+
error::OutOfMemory,
23+
prelude::*,
2124
};
22-
use crate::{WasmExnType, prelude::*};
25+
use alloc::sync::Arc;
2326
use core::alloc::Layout;
2427

2528
/// Discriminant to check whether GC reference is an `i31ref` or not.
@@ -122,7 +125,9 @@ fn common_struct_or_exn_layout(
122125
fields: &[crate::WasmFieldType],
123126
header_size: u32,
124127
header_align: u32,
125-
) -> (u32, u32, Vec<GcStructLayoutField>) {
128+
) -> (u32, u32, collections::Vec<GcStructLayoutField>) {
129+
use crate::PanicOnOom as _;
130+
126131
// Process each field, aligning it to its natural alignment.
127132
//
128133
// We don't try and do any fancy field reordering to minimize padding (yet?)
@@ -143,7 +148,8 @@ fn common_struct_or_exn_layout(
143148
let is_gc_ref = f.element_type.is_vmgcref_type_and_not_i31();
144149
GcStructLayoutField { offset, is_gc_ref }
145150
})
146-
.collect();
151+
.try_collect::<collections::Vec<_>, _>()
152+
.panic_on_oom();
147153

148154
// Ensure that the final size is a multiple of the alignment, for
149155
// simplicity.
@@ -228,12 +234,12 @@ pub trait GcTypeLayouts {
228234
assert!(!ty.shared);
229235
match &ty.inner {
230236
WasmCompositeInnerType::Array(ty) => Some(self.array_layout(ty).into()),
231-
WasmCompositeInnerType::Struct(ty) => Some(self.struct_layout(ty).into()),
237+
WasmCompositeInnerType::Struct(ty) => Some(Arc::new(self.struct_layout(ty)).into()),
232238
WasmCompositeInnerType::Func(_) => None,
233239
WasmCompositeInnerType::Cont(_) => {
234240
unimplemented!("Stack switching feature not compatible with GC, yet")
235241
}
236-
WasmCompositeInnerType::Exn(ty) => Some(self.exn_layout(ty).into()),
242+
WasmCompositeInnerType::Exn(ty) => Some(Arc::new(self.exn_layout(ty)).into()),
237243
}
238244
}
239245

@@ -254,7 +260,7 @@ pub enum GcLayout {
254260
Array(GcArrayLayout),
255261

256262
/// The layout of a GC-managed struct or exception object.
257-
Struct(GcStructLayout),
263+
Struct(Arc<GcStructLayout>),
258264
}
259265

260266
impl From<GcArrayLayout> for GcLayout {
@@ -263,16 +269,22 @@ impl From<GcArrayLayout> for GcLayout {
263269
}
264270
}
265271

266-
impl From<GcStructLayout> for GcLayout {
267-
fn from(layout: GcStructLayout) -> Self {
272+
impl From<Arc<GcStructLayout>> for GcLayout {
273+
fn from(layout: Arc<GcStructLayout>) -> Self {
268274
Self::Struct(layout)
269275
}
270276
}
271277

278+
impl TryClone for GcLayout {
279+
fn try_clone(&self) -> core::result::Result<Self, wasmtime_core::error::OutOfMemory> {
280+
Ok(self.clone())
281+
}
282+
}
283+
272284
impl GcLayout {
273285
/// Get the underlying `GcStructLayout`, or panic.
274286
#[track_caller]
275-
pub fn unwrap_struct(&self) -> &GcStructLayout {
287+
pub fn unwrap_struct(&self) -> &Arc<GcStructLayout> {
276288
match self {
277289
Self::Struct(s) => s,
278290
_ => panic!("GcLayout::unwrap_struct on non-struct GC layout"),
@@ -368,12 +380,23 @@ pub struct GcStructLayout {
368380

369381
/// The fields of this struct. The `i`th entry contains information about
370382
/// the `i`th struct field's layout.
371-
pub fields: Vec<GcStructLayoutField>,
383+
pub fields: collections::Vec<GcStructLayoutField>,
372384

373385
/// Whether this is an exception object layout.
374386
pub is_exception: bool,
375387
}
376388

389+
impl TryClone for GcStructLayout {
390+
fn try_clone(&self) -> Result<Self, OutOfMemory> {
391+
Ok(GcStructLayout {
392+
size: self.size,
393+
align: self.align,
394+
fields: self.fields.try_clone()?,
395+
is_exception: self.is_exception,
396+
})
397+
}
398+
}
399+
377400
impl GcStructLayout {
378401
/// Get a `core::alloc::Layout` for a struct of this type.
379402
pub fn layout(&self) -> Layout {
@@ -397,6 +420,12 @@ pub struct GcStructLayoutField {
397420
pub is_gc_ref: bool,
398421
}
399422

423+
impl TryClone for GcStructLayoutField {
424+
fn try_clone(&self) -> Result<Self, OutOfMemory> {
425+
Ok(*self)
426+
}
427+
}
428+
400429
/// The kind of an object in a GC heap.
401430
///
402431
/// Note that this type is accessed from Wasm JIT code.

crates/wasmtime/src/runtime/gc/enabled/exnref.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::{
1111
store::{AutoAssertNoGc, StoreOpaque},
1212
};
1313
use crate::{ExnType, FieldType, GcHeapOutOfMemory, StoreContextMut, Tag, prelude::*};
14+
use alloc::sync::Arc;
1415
use core::mem;
1516
use core::mem::MaybeUninit;
1617
use wasmtime_environ::{GcLayout, GcStructLayout, VMGcKind, VMSharedTypeIndex};
@@ -563,7 +564,7 @@ impl ExnRef {
563564
Ok(gc_ref.as_exnref_unchecked())
564565
}
565566

566-
fn layout(&self, store: &AutoAssertNoGc<'_>) -> Result<GcStructLayout> {
567+
fn layout(&self, store: &AutoAssertNoGc<'_>) -> Result<Arc<GcStructLayout>> {
567568
assert!(self.comes_from_same_store(&store));
568569
let type_index = self.type_index(store)?;
569570
let layout = store

crates/wasmtime/src/runtime/gc/enabled/structref.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::{
1212
prelude::*,
1313
store::{AutoAssertNoGc, StoreContextMut, StoreOpaque, StoreResourceLimiter},
1414
};
15+
use alloc::sync::Arc;
1516
use core::mem::{self, MaybeUninit};
1617
use wasmtime_environ::{GcLayout, GcStructLayout, VMGcKind, VMSharedTypeIndex};
1718

@@ -515,7 +516,7 @@ impl StructRef {
515516
Ok(gc_ref.as_structref_unchecked())
516517
}
517518

518-
fn layout(&self, store: &AutoAssertNoGc<'_>) -> Result<GcStructLayout> {
519+
fn layout(&self, store: &AutoAssertNoGc<'_>) -> Result<Arc<GcStructLayout>> {
519520
assert!(self.comes_from_same_store(&store));
520521
let type_index = self.type_index(store)?;
521522
let layout = store

crates/wasmtime/src/runtime/type_registry.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,10 +1107,10 @@ impl TypeRegistryInner {
11071107
gc_runtime.layouts().array_layout(a).into()
11081108
}
11091109
wasmtime_environ::WasmCompositeInnerType::Struct(s) => {
1110-
gc_runtime.layouts().struct_layout(s).into()
1110+
try_new::<Arc<_>>(gc_runtime.layouts().struct_layout(s))?.into()
11111111
}
11121112
wasmtime_environ::WasmCompositeInnerType::Exn(e) => {
1113-
gc_runtime.layouts().exn_layout(e).into()
1113+
try_new::<Arc<_>>(gc_runtime.layouts().exn_layout(e))?.into()
11141114
}
11151115
wasmtime_environ::WasmCompositeInnerType::Cont(_) => continue, // FIXME: #10248 stack switching support.
11161116
};

0 commit comments

Comments
 (0)