Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wasmtime: Add a gc cargo feature #7975

Merged
merged 12 commits into from
Feb 23, 2024
4 changes: 4 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,10 @@ jobs:
- run: cargo check -p wasmtime --no-default-features --features wmemcheck
- run: cargo check -p wasmtime --no-default-features --features demangle
- run: cargo check -p wasmtime --no-default-features --features addr2line
- run: cargo check -p wasmtime --no-default-features --features gc
- run: cargo check -p wasmtime --no-default-features --features runtime,gc
- run: cargo check -p wasmtime --no-default-features --features cranelift,gc
- run: cargo check -p wasmtime --no-default-features --features runtime
- run: cargo check --features component-model
- run: cargo check -p wasmtime --features incremental-cache

Expand Down
2 changes: 1 addition & 1 deletion crates/c-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ doctest = false
env_logger = { workspace = true, optional = true }
anyhow = { workspace = true }
once_cell = { workspace = true }
wasmtime = { workspace = true, features = ['cranelift', 'runtime'] }
wasmtime = { workspace = true, features = ['cranelift', 'runtime', 'gc'] }
wasmtime-c-api-macros = { workspace = true }
log = { workspace = true }
tracing = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion crates/cli-flags/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ clap = { workspace = true }
file-per-thread-logger = { workspace = true, optional = true }
tracing-subscriber = { workspace = true, optional = true }
rayon = { version = "1.5.0", optional = true }
wasmtime = { workspace = true }
wasmtime = { workspace = true, features = ["gc"] }
humantime = { workspace = true }

[features]
Expand Down
1 change: 1 addition & 0 deletions crates/cranelift/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@ host-arch = ["cranelift-codegen/host-arch"]
component-model = ["wasmtime-environ/component-model"]
incremental-cache = ["cranelift-codegen/incremental-cache"]
wmemcheck = []
gc = ["wasmtime-environ/gc"]
91 changes: 89 additions & 2 deletions crates/cranelift/src/func_environ.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,26 +34,41 @@ macro_rules! declare_function_signatures {
) => {
/// A struct with an `Option<ir::SigRef>` member for every builtin
/// function, to de-duplicate constructing/getting its signature.
#[allow(unused_doc_comments)]
struct BuiltinFunctionSignatures {
pointer_type: ir::Type,

#[cfg(feature = "gc")]
reference_type: ir::Type,

call_conv: isa::CallConv,

$(
$( #[$attr] )*
$name: Option<ir::SigRef>,
)*
}

#[allow(unused_doc_comments)]
impl BuiltinFunctionSignatures {
fn new(
pointer_type: ir::Type,
reference_type: ir::Type,
call_conv: isa::CallConv,
) -> Self {
#[cfg(not(feature = "gc"))]
let _ = reference_type;

Self {
pointer_type,

#[cfg(feature = "gc")]
reference_type,

call_conv,

$(
$( #[$attr] )*
$name: None,
)*
}
Expand All @@ -63,6 +78,7 @@ macro_rules! declare_function_signatures {
AbiParam::special(self.pointer_type, ArgumentPurpose::VMContext)
}

#[cfg(feature = "gc")]
fn reference(&self) -> AbiParam {
AbiParam::new(self.reference_type)
}
Expand All @@ -89,6 +105,7 @@ macro_rules! declare_function_signatures {
}

$(
$( #[$attr] )*
fn $name(&mut self, func: &mut Function) -> ir::SigRef {
let sig = self.$name.unwrap_or_else(|| {
func.import_signature(Signature {
Expand Down Expand Up @@ -336,6 +353,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
/// reference count.
///
/// The new reference count is returned.
#[cfg(feature = "gc")]
fn mutate_externref_ref_count(
&mut self,
builder: &mut FunctionBuilder,
Expand Down Expand Up @@ -1324,11 +1342,19 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
self.builtin_function_signatures
.table_grow_func_ref(&mut pos.func),
),
#[cfg(feature = "gc")]
WasmHeapType::Extern => (
BuiltinFunctionIndex::table_grow_externref(),
self.builtin_function_signatures
.table_grow_externref(&mut pos.func),
),
#[cfg(not(feature = "gc"))]
WasmHeapType::Extern => {
return Err(cranelift_wasm::wasm_unsupported!(
"support for `externref` disabled at compile time because \
the `gc` cargo feature was not enabled",
))
}
};

let (vmctx, func_addr) = self.translate_load_builtin_function_address(&mut pos, func_idx);
Expand All @@ -1350,8 +1376,6 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
table: ir::Table,
index: ir::Value,
) -> WasmResult<ir::Value> {
let pointer_type = self.pointer_type();

let plan = &self.module.table_plans[table_index];
match plan.table.wasm_ty.heap_type {
WasmHeapType::Func | WasmHeapType::Concrete(_) | WasmHeapType::NoFunc => match plan
Expand All @@ -1361,6 +1385,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
Ok(self.get_or_init_func_ref_table_elem(builder, table_index, table, index))
}
},
#[cfg(feature = "gc")]
WasmHeapType::Extern => {
// Our read barrier for `externref` tables is roughly equivalent
// to the following pseudocode:
Expand All @@ -1382,6 +1407,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
// onto the stack are safely held alive by the
// `VMExternRefActivationsTable`.

let pointer_type = self.pointer_type();
let reference_type = self.reference_type(WasmHeapType::Extern);

builder.ensure_inserted_block();
Expand Down Expand Up @@ -1477,6 +1503,13 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m

Ok(elem)
}
#[cfg(not(feature = "gc"))]
WasmHeapType::Extern => {
return Err(cranelift_wasm::wasm_unsupported!(
"support for `externref` disabled at compile time because the \
`gc` cargo feature was not enabled",
))
}
}
}

Expand Down Expand Up @@ -1510,6 +1543,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
}
},

#[cfg(feature = "gc")]
WasmHeapType::Extern => {
// Our write barrier for `externref`s being copied out of the
// stack and into a table is roughly equivalent to the following
Expand Down Expand Up @@ -1640,6 +1674,14 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m

Ok(())
}

#[cfg(not(feature = "gc"))]
WasmHeapType::Extern => {
return Err(cranelift_wasm::wasm_unsupported!(
"support for `externref` disabled at compile time because the \
`gc` cargo feature was not enabled",
))
}
}
}

Expand All @@ -1658,11 +1700,19 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
self.builtin_function_signatures
.table_fill_func_ref(&mut pos.func),
),
#[cfg(feature = "gc")]
WasmHeapType::Extern => (
BuiltinFunctionIndex::table_fill_externref(),
self.builtin_function_signatures
.table_fill_externref(&mut pos.func),
),
#[cfg(not(feature = "gc"))]
WasmHeapType::Extern => {
return Err(cranelift_wasm::wasm_unsupported!(
"support for `externref` disabled at compile time because the \
`gc` cargo feature was not enabled",
));
}
};

let (vmctx, builtin_addr) =
Expand Down Expand Up @@ -1727,6 +1777,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
Ok(pos.func.dfg.first_result(call_inst))
}

#[cfg(feature = "gc")]
fn translate_custom_global_get(
&mut self,
mut pos: cranelift_codegen::cursor::FuncCursor<'_>,
Expand Down Expand Up @@ -1754,6 +1805,24 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
Ok(pos.func.dfg.first_result(call_inst))
}

#[cfg(not(feature = "gc"))]
fn translate_custom_global_get(
&mut self,
_pos: FuncCursor,
index: GlobalIndex,
) -> WasmResult<ir::Value> {
debug_assert_eq!(
self.module.globals[index].wasm_ty,
WasmValType::Ref(WasmRefType::EXTERNREF),
"We only use GlobalVariable::Custom for externref"
);
Err(cranelift_wasm::wasm_unsupported!(
"support for `externref` disabled at compile time because the \
`gc` cargo feature was not enabled",
))
}

#[cfg(feature = "gc")]
fn translate_custom_global_set(
&mut self,
mut pos: cranelift_codegen::cursor::FuncCursor<'_>,
Expand Down Expand Up @@ -1781,6 +1850,24 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
Ok(())
}

#[cfg(not(feature = "gc"))]
fn translate_custom_global_set(
&mut self,
_pos: FuncCursor,
index: GlobalIndex,
_value: ir::Value,
) -> WasmResult<()> {
debug_assert_eq!(
self.module.globals[index].wasm_ty,
WasmValType::Ref(WasmRefType::EXTERNREF),
"We only use GlobalVariable::Custom for externref"
);
Err(cranelift_wasm::wasm_unsupported!(
"support for `externref` disabled at compile time because the \
`gc` cargo feature was not enabled",
))
}

fn make_heap(&mut self, func: &mut ir::Function, index: MemoryIndex) -> WasmResult<Heap> {
let pointer_type = self.pointer_type();
let is_shared = self.module.memory_plans[index].memory.shared;
Expand Down
1 change: 1 addition & 0 deletions crates/environ/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,4 @@ component-model = [
"dep:wasmtime-component-util",
]
demangle = ['dep:rustc-demangle', 'dep:cpp_demangle']
gc = []
38 changes: 25 additions & 13 deletions crates/environ/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,8 @@ macro_rules! foreach_builtin_function {
table_get_lazy_init_func_ref(vmctx: vmctx, table: i32, index: i32) -> pointer;
/// Returns an index for Wasm's `table.grow` instruction for `funcref`s.
table_grow_func_ref(vmctx: vmctx, table: i32, delta: i32, init: pointer) -> i32;
/// Returns an index for Wasm's `table.grow` instruction for `externref`s.
table_grow_externref(vmctx: vmctx, table: i32, delta: i32, init: reference) -> i32;
/// Returns an index for Wasm's `table.fill` instruction for `externref`s.
table_fill_externref(vmctx: vmctx, table: i32, dst: i32, val: reference, len: i32);
/// Returns an index for Wasm's `table.fill` instruction for `funcref`s.
table_fill_func_ref(vmctx: vmctx, table: i32, dst: i32, val: pointer, len: i32);
/// Returns an index to drop a `VMExternRef`.
drop_externref(vmctx: vmctx, val: pointer);
/// Returns an index to do a GC and then insert a `VMExternRef` into the
/// `VMExternRefActivationsTable`.
activations_table_insert_with_gc(vmctx: vmctx, val: reference);
/// Returns an index for Wasm's `global.get` instruction for `externref`s.
externref_global_get(vmctx: vmctx, global: i32) -> reference;
/// Returns an index for Wasm's `global.get` instruction for `externref`s.
externref_global_set(vmctx: vmctx, global: i32, val: reference);
/// Returns an index for wasm's `memory.atomic.notify` instruction.
memory_atomic_notify(vmctx: vmctx, memory: i32, addr: i64, count: i32) -> i32;
/// Returns an index for wasm's `memory.atomic.wait32` instruction.
Expand All @@ -67,6 +54,31 @@ macro_rules! foreach_builtin_function {
update_stack_pointer(vmctx: vmctx, value: i32);
/// Invoked before memory.grow is called.
update_mem_size(vmctx: vmctx, num_bytes: i32);

/// Returns an index to drop a `VMExternRef`.
#[cfg(feature = "gc")]
drop_externref(vmctx: vmctx, val: pointer);

/// Returns an index to do a GC and then insert a `VMExternRef` into the
/// `VMExternRefActivationsTable`.
#[cfg(feature = "gc")]
activations_table_insert_with_gc(vmctx: vmctx, val: reference);

/// Returns an index for Wasm's `global.get` instruction for `externref`s.
#[cfg(feature = "gc")]
externref_global_get(vmctx: vmctx, global: i32) -> reference;

/// Returns an index for Wasm's `global.get` instruction for `externref`s.
#[cfg(feature = "gc")]
externref_global_set(vmctx: vmctx, global: i32, val: reference);

/// Returns an index for Wasm's `table.grow` instruction for `externref`s.
#[cfg(feature = "gc")]
table_grow_externref(vmctx: vmctx, table: i32, delta: i32, init: reference) -> i32;

/// Returns an index for Wasm's `table.fill` instruction for `externref`s.
#[cfg(feature = "gc")]
table_fill_externref(vmctx: vmctx, table: i32, dst: i32, val: reference, len: i32);
}
};
}
Expand Down
2 changes: 1 addition & 1 deletion crates/fuzzing/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ target-lexicon = { workspace = true }
tempfile = "3.3.0"
wasmparser = { workspace = true }
wasmprinter = { workspace = true }
wasmtime = { workspace = true, features = ['default', 'winch'] }
wasmtime = { workspace = true, features = ['default', 'winch', 'gc'] }
wasmtime-wast = { workspace = true }
wasm-encoder = { workspace = true }
wasm-smith = { workspace = true }
Expand Down
1 change: 1 addition & 0 deletions crates/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,4 @@ pooling-allocator = []
component-model = ["wasmtime-environ/component-model", "dep:encoding_rs"]
wmemcheck = []
debug-builtins = ['wasmtime-jit-debug']
gc = ["wasmtime-environ/gc"]
Loading