Skip to content

Commit

Permalink
threads: add WasmCompositeInnerType layer (#9520)
Browse files Browse the repository at this point in the history
* threads: add `WasmCompositeInnerType` layer

As in `wasm-tools`, push the type down a layer so that
`WasmCompositeType` can be marked shared. This leaves several holes to
be filled in by future commits (all marked with `TODO: handle shared`);
in effect, this change allows `WasmCompositeType` to be marked shared
but mostly does not wire up the sharedness during translation.

* review: remove TODOs

* review: remove more TODOs

* review: refactor to use `GcTypeLayouts::gc_layout`

* review: propagate sharedness

* review: fail if an unwrapped type is shared

* review: propagate sharedness more

* review: redefine accessors as unshared

* fix: add `DisabledLayouts` to satisfy `GcRuntime::layouts()`

* review: panic on shared

* review: remove unnecessary assert
  • Loading branch information
abrown authored Nov 2, 2024
1 parent 44da056 commit 38845a0
Show file tree
Hide file tree
Showing 8 changed files with 205 additions and 112 deletions.
6 changes: 3 additions & 3 deletions crates/cranelift/src/func_environ.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use wasmtime_environ::{
BuiltinFunctionIndex, DataIndex, ElemIndex, EngineOrModuleTypeIndex, FuncIndex, GlobalIndex,
IndexType, Memory, MemoryIndex, MemoryStyle, Module, ModuleInternedTypeIndex,
ModuleTranslation, ModuleTypesBuilder, PtrSize, Table, TableIndex, Tunables, TypeConvert,
TypeIndex, VMOffsets, WasmCompositeType, WasmFuncType, WasmHeapTopType, WasmHeapType,
TypeIndex, VMOffsets, WasmCompositeInnerType, WasmFuncType, WasmHeapTopType, WasmHeapType,
WasmRefType, WasmResult, WasmValType,
};
use wasmtime_environ::{FUNCREF_INIT_BIT, FUNCREF_MASK};
Expand Down Expand Up @@ -1911,8 +1911,8 @@ impl<'module_environment> crate::translate::FuncEnvironment

fn struct_fields_len(&mut self, struct_type_index: TypeIndex) -> WasmResult<usize> {
let ty = self.module.types[struct_type_index];
match &self.types[ty].composite_type {
WasmCompositeType::Struct(s) => Ok(s.fields.len()),
match &self.types[ty].composite_type.inner {
WasmCompositeInnerType::Struct(s) => Ok(s.fields.len()),
_ => unreachable!(),
}
}
Expand Down
64 changes: 21 additions & 43 deletions crates/cranelift/src/gc/enabled.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use cranelift_frontend::FunctionBuilder;
use smallvec::SmallVec;
use wasmtime_environ::{
wasm_unsupported, Collector, GcArrayLayout, GcLayout, GcStructLayout, ModuleInternedTypeIndex,
PtrSize, TypeIndex, VMGcKind, WasmCompositeType, WasmHeapTopType, WasmHeapType, WasmRefType,
WasmResult, WasmStorageType, WasmValType, I31_DISCRIMINANT, NON_NULL_NON_I31_MASK,
PtrSize, TypeIndex, VMGcKind, WasmHeapTopType, WasmHeapType, WasmRefType, WasmResult,
WasmStorageType, WasmValType, I31_DISCRIMINANT, NON_NULL_NON_I31_MASK,
};

#[cfg(feature = "gc-drc")]
Expand Down Expand Up @@ -285,10 +285,7 @@ pub fn translate_struct_new_default(
struct_type_index: TypeIndex,
) -> WasmResult<ir::Value> {
let interned_ty = func_env.module.types[struct_type_index];
let struct_ty = match &func_env.types[interned_ty].composite_type {
WasmCompositeType::Struct(s) => s,
_ => unreachable!(),
};
let struct_ty = func_env.types.unwrap_struct(interned_ty)?;
let fields = struct_ty
.fields
.iter()
Expand Down Expand Up @@ -317,12 +314,7 @@ pub fn translate_struct_get(
let struct_size_val = builder.ins().iconst(ir::types::I32, i64::from(struct_size));

let field_offset = struct_layout.fields[field_index];

let field_ty = match &func_env.types[interned_type_index].composite_type {
WasmCompositeType::Struct(s) => &s.fields[field_index],
_ => unreachable!(),
};

let field_ty = &func_env.types.unwrap_struct(interned_type_index)?.fields[field_index];
let field_size = wasmtime_environ::byte_size_of_wasm_ty_in_gc_heap(&field_ty.element_type);
assert!(field_offset + field_size <= struct_size);

Expand Down Expand Up @@ -355,12 +347,7 @@ fn translate_struct_get_and_extend(
let struct_size_val = builder.ins().iconst(ir::types::I32, i64::from(struct_size));

let field_offset = struct_layout.fields[field_index];

let field_ty = match &func_env.types[interned_type_index].composite_type {
WasmCompositeType::Struct(s) => &s.fields[field_index],
_ => unreachable!(),
};

let field_ty = &func_env.types.unwrap_struct(interned_type_index)?.fields[field_index];
let field_size = wasmtime_environ::byte_size_of_wasm_ty_in_gc_heap(&field_ty.element_type);
assert!(field_offset + field_size <= struct_size);

Expand Down Expand Up @@ -433,12 +420,7 @@ pub fn translate_struct_set(
let struct_size_val = builder.ins().iconst(ir::types::I32, i64::from(struct_size));

let field_offset = struct_layout.fields[field_index];

let field_ty = match &func_env.types[interned_type_index].composite_type {
WasmCompositeType::Struct(s) => &s.fields[field_index],
_ => unreachable!(),
};

let field_ty = &func_env.types.unwrap_struct(interned_type_index)?.fields[field_index];
let field_size = wasmtime_environ::byte_size_of_wasm_ty_in_gc_heap(&field_ty.element_type);
assert!(field_offset + field_size <= struct_size);

Expand Down Expand Up @@ -480,9 +462,7 @@ pub fn translate_array_new_default(
len: ir::Value,
) -> WasmResult<ir::Value> {
let interned_ty = func_env.module.types[array_type_index];
let WasmCompositeType::Array(array_ty) = &func_env.types[interned_ty].composite_type else {
unreachable!()
};
let array_ty = func_env.types.unwrap_array(interned_ty)?;
let elem = default_value(&mut builder.cursor(), func_env, &array_ty.0.element_type);
gc_compiler(func_env)?.alloc_array(
func_env,
Expand Down Expand Up @@ -532,8 +512,10 @@ impl ArrayInit<'_> {
ir::Value,
) -> WasmResult<()>,
) -> WasmResult<()> {
assert!(!func_env.types[interned_type_index].composite_type.shared);
let array_ty = func_env.types[interned_type_index]
.composite_type
.inner
.unwrap_array();
let elem_ty = array_ty.0.element_type;
let elem_size = wasmtime_environ::byte_size_of_wasm_ty_in_gc_heap(&elem_ty);
Expand Down Expand Up @@ -698,9 +680,9 @@ pub fn translate_array_fill(
one_elem_size,
fill_end,
|func_env, builder, elem_addr| {
let elem_ty = func_env.types[interned_type_index]
.composite_type
.unwrap_array()
let elem_ty = func_env
.types
.unwrap_array(interned_type_index)?
.0
.element_type;
write_field_at_addr(func_env, builder, elem_ty, elem_addr, value)
Expand Down Expand Up @@ -865,9 +847,7 @@ pub fn translate_array_get(
let array_type_index = func_env.module.types[array_type_index];
let elem_addr = array_elem_addr(func_env, builder, array_type_index, array_ref, index);

let array_ty = func_env.types[array_type_index]
.composite_type
.unwrap_array();
let array_ty = func_env.types.unwrap_array(array_type_index)?;
let elem_ty = array_ty.0.element_type;

read_field_at_addr(func_env, builder, elem_ty, elem_addr, None)
Expand All @@ -883,9 +863,7 @@ pub fn translate_array_get_s(
let array_type_index = func_env.module.types[array_type_index];
let elem_addr = array_elem_addr(func_env, builder, array_type_index, array_ref, index);

let array_ty = func_env.types[array_type_index]
.composite_type
.unwrap_array();
let array_ty = func_env.types.unwrap_array(array_type_index)?;
let elem_ty = array_ty.0.element_type;

read_field_at_addr(func_env, builder, elem_ty, elem_addr, Some(Extension::Sign))
Expand All @@ -901,9 +879,7 @@ pub fn translate_array_get_u(
let array_type_index = func_env.module.types[array_type_index];
let elem_addr = array_elem_addr(func_env, builder, array_type_index, array_ref, index);

let array_ty = func_env.types[array_type_index]
.composite_type
.unwrap_array();
let array_ty = func_env.types.unwrap_array(array_type_index)?;
let elem_ty = array_ty.0.element_type;

read_field_at_addr(func_env, builder, elem_ty, elem_addr, Some(Extension::Zero))
Expand All @@ -920,9 +896,7 @@ pub fn translate_array_set(
let array_type_index = func_env.module.types[array_type_index];
let elem_addr = array_elem_addr(func_env, builder, array_type_index, array_ref, index);

let array_ty = func_env.types[array_type_index]
.composite_type
.unwrap_array();
let array_ty = func_env.types.unwrap_array(array_type_index)?;
let elem_ty = array_ty.0.element_type;

write_field_at_addr(func_env, builder, elem_ty, elem_addr, value)
Expand Down Expand Up @@ -1263,7 +1237,11 @@ fn initialize_struct_fields(
let field_offsets: SmallVec<[_; 8]> = struct_layout.fields.iter().copied().collect();
assert_eq!(field_offsets.len(), field_values.len());

let struct_ty = func_env.types[struct_ty].composite_type.unwrap_struct();
assert!(!func_env.types[struct_ty].composite_type.shared);
let struct_ty = func_env.types[struct_ty]
.composite_type
.inner
.unwrap_struct();
let field_types: SmallVec<[_; 8]> = struct_ty.fields.iter().cloned().collect();
assert_eq!(field_types.len(), field_values.len());

Expand Down
73 changes: 60 additions & 13 deletions crates/environ/src/compile/module_types.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::{
EngineOrModuleTypeIndex, EntityRef, ModuleInternedRecGroupIndex, ModuleInternedTypeIndex,
ModuleTypes, TypeConvert, TypeIndex, WasmCompositeType, WasmFuncType, WasmHeapType, WasmResult,
WasmSubType,
wasm_unsupported, EngineOrModuleTypeIndex, EntityRef, ModuleInternedRecGroupIndex,
ModuleInternedTypeIndex, ModuleTypes, TypeConvert, TypeIndex, WasmArrayType,
WasmCompositeInnerType, WasmCompositeType, WasmFuncType, WasmHeapType, WasmResult,
WasmStructType, WasmSubType,
};
use std::{borrow::Cow, collections::HashMap, ops::Index};
use wasmparser::{UnpackedIndex, Validator, ValidatorId};
Expand Down Expand Up @@ -140,7 +141,8 @@ impl ModuleTypesBuilder {
&mut self,
for_func_ty: ModuleInternedTypeIndex,
) -> ModuleInternedTypeIndex {
let trampoline = self.types[for_func_ty].unwrap_func().trampoline_type();
let sub_ty = &self.types[for_func_ty];
let trampoline = sub_ty.unwrap_func().trampoline_type();

if let Some(idx) = self.trampoline_types.get(&trampoline) {
// We've already interned this trampoline type; reuse it.
Expand All @@ -163,7 +165,10 @@ impl ModuleTypesBuilder {
let idx = self.types.push(WasmSubType {
is_final: true,
supertype: None,
composite_type: WasmCompositeType::Func(f.clone()),
composite_type: WasmCompositeType {
inner: WasmCompositeInnerType::Func(f.clone()),
shared: sub_ty.composite_type.shared,
},
});

// The trampoline type is its own trampoline type.
Expand Down Expand Up @@ -325,6 +330,46 @@ impl ModuleTypesBuilder {
pub fn trampoline_type(&self, ty: ModuleInternedTypeIndex) -> ModuleInternedTypeIndex {
self.types.trampoline_type(ty)
}

/// Get and unwrap a [`WasmStructType`] for the given struct index.
///
/// # Panics
///
/// Panics if the unwrapped type is not a struct.
///
/// # Errors
///
/// For now, fails with an unsupported error if the type is shared.
pub fn unwrap_struct(&self, ty: ModuleInternedTypeIndex) -> WasmResult<&WasmStructType> {
let composite_type = &self.types[ty].composite_type;
if composite_type.shared {
return Err(wasm_unsupported!("shared structs are not yet implemented"));
}
match &composite_type.inner {
WasmCompositeInnerType::Struct(s) => Ok(s),
_ => unreachable!(),
}
}

/// Get and unwrap a [`WasmArrayType`] for the given array index.
///
/// # Panics
///
/// Panics if the unwrapped type is not an array.
///
/// # Errors
///
/// For now, fails with an unsupported error if the type is shared.
pub fn unwrap_array(&self, interned_ty: ModuleInternedTypeIndex) -> WasmResult<&WasmArrayType> {
let composite_type = &self.types[interned_ty].composite_type;
if composite_type.shared {
return Err(wasm_unsupported!("shared arrays are not yet implemented"));
}
match &composite_type.inner {
WasmCompositeInnerType::Array(a) => Ok(a),
_ => unreachable!(),
}
}
}

// Forward the indexing impl to the internal `ModuleTypes`
Expand Down Expand Up @@ -388,10 +433,11 @@ where
// array vs struct vs func reference. In this case, we can use
// the validator's type context.
if let Some(ty) = self.types.types.get(interned) {
match &ty.composite_type {
WasmCompositeType::Array(_) => WasmHeapType::ConcreteArray(index),
WasmCompositeType::Func(_) => WasmHeapType::ConcreteFunc(index),
WasmCompositeType::Struct(_) => WasmHeapType::ConcreteStruct(index),
assert!(!ty.composite_type.shared);
match &ty.composite_type.inner {
WasmCompositeInnerType::Array(_) => WasmHeapType::ConcreteArray(index),
WasmCompositeInnerType::Func(_) => WasmHeapType::ConcreteFunc(index),
WasmCompositeInnerType::Struct(_) => WasmHeapType::ConcreteStruct(index),
}
} else if let Some((wasmparser_types, _)) = self.rec_group_context.as_ref() {
let wasmparser_ty = &wasmparser_types[id].composite_type;
Expand Down Expand Up @@ -426,10 +472,11 @@ where
// indirectly get one by looking it up inside the current rec
// group.
if let Some(ty) = self.types.types.get(interned) {
match &ty.composite_type {
WasmCompositeType::Array(_) => WasmHeapType::ConcreteArray(index),
WasmCompositeType::Func(_) => WasmHeapType::ConcreteFunc(index),
WasmCompositeType::Struct(_) => WasmHeapType::ConcreteStruct(index),
assert!(!ty.composite_type.shared);
match &ty.composite_type.inner {
WasmCompositeInnerType::Array(_) => WasmHeapType::ConcreteArray(index),
WasmCompositeInnerType::Func(_) => WasmHeapType::ConcreteFunc(index),
WasmCompositeInnerType::Struct(_) => WasmHeapType::ConcreteStruct(index),
}
} else if let Some((parser_types, rec_group)) = self.rec_group_context.as_ref() {
let rec_group_index = interned.index() - self.types.types.len_types();
Expand Down
14 changes: 9 additions & 5 deletions crates/environ/src/gc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ pub mod drc;
pub mod null;

use crate::prelude::*;
use crate::{WasmArrayType, WasmCompositeType, WasmStorageType, WasmStructType, WasmValType};
use crate::{
WasmArrayType, WasmCompositeInnerType, WasmCompositeType, WasmStorageType, WasmStructType,
WasmValType,
};
use core::alloc::Layout;

/// Discriminant to check whether GC reference is an `i31ref` or not.
Expand Down Expand Up @@ -158,10 +161,11 @@ pub trait GcTypeLayouts {
/// Returns `None` if the type is a function type, as functions are not
/// managed by the GC.
fn gc_layout(&self, ty: &WasmCompositeType) -> Option<GcLayout> {
match ty {
WasmCompositeType::Array(ty) => Some(self.array_layout(ty).into()),
WasmCompositeType::Struct(ty) => Some(self.struct_layout(ty).into()),
WasmCompositeType::Func(_) => None,
assert!(!ty.shared);
match &ty.inner {
WasmCompositeInnerType::Array(ty) => Some(self.array_layout(ty).into()),
WasmCompositeInnerType::Struct(ty) => Some(self.struct_layout(ty).into()),
WasmCompositeInnerType::Func(_) => None,
}
}

Expand Down
Loading

0 comments on commit 38845a0

Please sign in to comment.