1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
//! Layout of Wasm GC objects in the deferred reference-counting collector.
use super::*;
/// The size of the `VMDrcHeader` header for GC objects.
pub const HEADER_SIZE: u32 = 16;
/// The align of the `VMDrcHeader` header for GC objects.
pub const HEADER_ALIGN: u32 = 8;
/// The offset of the length field in a `VMDrcArrayHeader`.
pub const ARRAY_LENGTH_OFFSET: u32 = HEADER_SIZE;
/// Align `offset` up to `bytes`, updating `max_align` if `align` is the
/// new maximum alignment, and returning the aligned offset.
fn align_up(offset: &mut u32, max_align: &mut u32, align: u32) -> u32 {
debug_assert!(max_align.is_power_of_two());
debug_assert!(align.is_power_of_two());
*offset = offset.checked_add(align - 1).unwrap() & !(align - 1);
*max_align = core::cmp::max(*max_align, align);
*offset
}
/// Define a new field of size and alignment `bytes`, updating the object's
/// total `size` and `align` as necessary. The offset of the new field is
/// returned.
fn field(size: &mut u32, align: &mut u32, bytes: u32) -> u32 {
let offset = align_up(size, align, bytes);
*size += bytes;
offset
}
/// The layout of Wasm GC objects in the deferred reference-counting collector.
#[derive(Default)]
pub struct DrcTypeLayouts;
impl GcTypeLayouts for DrcTypeLayouts {
fn array_length_field_offset(&self) -> u32 {
ARRAY_LENGTH_OFFSET
}
fn array_layout(&self, ty: &WasmArrayType) -> GcArrayLayout {
let mut size = HEADER_SIZE;
let mut align = HEADER_ALIGN;
let length_field_offset = field(&mut size, &mut align, 4);
debug_assert_eq!(length_field_offset, ARRAY_LENGTH_OFFSET);
let elem_size = byte_size_of_wasm_ty_in_gc_heap(&ty.0.element_type);
let elems_offset = align_up(&mut size, &mut align, elem_size);
debug_assert_eq!(elems_offset, size);
GcArrayLayout {
base_size: size,
align,
elem_size,
}
}
fn struct_layout(&self, ty: &WasmStructType) -> GcStructLayout {
// Process each field, aligning it to its natural alignment.
//
// We don't try and do any fancy field reordering to minimize padding
// (yet?) because (a) the toolchain probably already did that and (b)
// we're just doing the simple thing first. We can come back and improve
// things here if we find that (a) isn't actually holding true in
// practice.
let mut size = HEADER_SIZE;
let mut align = HEADER_ALIGN;
let fields = ty
.fields
.iter()
.map(|f| {
let field_size = byte_size_of_wasm_ty_in_gc_heap(&f.element_type);
field(&mut size, &mut align, field_size)
})
.collect();
// Ensure that the final size is a multiple of the alignment, for
// simplicity.
align_up(&mut size, &mut 16, align);
GcStructLayout {
size,
align,
fields,
}
}
}