Skip to content

Commit

Permalink
Wasmtime: Add a gc cargo feature (#7975)
Browse files Browse the repository at this point in the history
* Wasmtime: Add a `gc` cargo feature

This controls whether support for `ExternRef` and its associated deferred,
reference-counting garbage collector is enabled at compile time or not. It will
also be used for similarly for Wasmtime's full Wasm GC support as that gets
added.

* Add CI for `gc` Cargo feature

* Cut down on the number of `#[cfg(feature = "gc")]`s outside the implementation of `[VM]ExternRef`

* Fix wasmparser reference types configuration with GC disabled/enabled

* More config fix

* doc cfg

* Make the dummy `VMExternRefActivationsTable` inhabited

* Fix winch tests

* final review bits

* Enable wasmtime's gc cargo feature for the C API

* Enable wasmtime's gc cargo feature from wasmtime-cli-flags

* enable gc cargo feature in a couple other crates
  • Loading branch information
fitzgen authored Feb 23, 2024
1 parent 0724fe2 commit dd0364d
Show file tree
Hide file tree
Showing 35 changed files with 1,742 additions and 1,311 deletions.
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

0 comments on commit dd0364d

Please sign in to comment.