Skip to content

Commit 63d482c

Browse files
Stack switching: Infrastructure and runtime support (#10388)
* [pr1] base * prtest:full * make sure to use ControlFlow result in trace_suspended_continuation * stack-switching: cleanup: remove stray c-api changes These are remnants of unrelated wasmfx wasmtime experiments, possibly suitable for later submission against upstream. * stack-switching: reuse async_stack_size * stack-switching: delete delete_me debugging * stack-switching: address feedback in environ::types * stack-switching: remove unused code from vmoffsets * stack-switching: drop dependency on std * stack-switching: add compilation checks to ci matrix * stack-switching: remove debug_println cruft * stack-switching: export environ consts consistently * stack-switching: export vm pub items consistently * table_pool: reduced capacity for large elements VMContRef elements which takes up two words and we don't want to double the size of all tables in order to support storing these. This change changes the table to target storing the requested max number of elements if they are "nominally" sized with (potentially) reduced capacity for non-nominally sized types when encountered. Continuations are the only type of element which may result in fewer table slots being available than requested. * stack-switching: extend conditional compilation A fair bit of the definitions for stack switching are still enabled, but this patch takes things a bit further to avoid compilation problems; notably, cont_new is now not compiled in unless the feature is enabled. * stack-switching: formatting fixes * stack-switching: address new clippy checks In addition, to get clippy to fully pass, plumbed in additional config to make winch paths happy; there's no impl for winch yet but plumbing through the feature is required to make paths incorporating macros at various layers satisfied (and it is expected we'll use the features in the future). * stack-switching: more conditional compilation fixes * stack-switching: additional conditional compile on table builtins for continuations * stack-switching: additional conditional compile fixes * stack-switching: additional conditional compile in store * stack-switching: remove overly strict assertion * stack-switching: remove errantly dropped no_mangle in config c-api * stack-switching: VMContObj::from_raw_parts * stack-switching: remove duplicate async_stack_size feature check * stack-switching: VMArray -> VMHostArray * stack-switching: remove unnecessary clippy exception * stack-switching: fix docs referenced VMRuntimeLimits * stack-switching: fix doc typo * stack-switching: follow recommendations for type casts * stack-switching: use usize::next_multiple_of * stack-switching: update outdated comment * stack-switching: use feature gate instead of allow(dead_code) * stack-switching: rework backtrace using chunks/zip * stack-switching: move tests to footer module This is a bit more consistent with the prevailing style in tree and (subjectively) makes finding the tests as a reader more straightforward. Tests left unchanged sans some import cleanup. * stack-swictchding: verify stack_chain offsets at runtime * fixup! stack-switching: use feature gate instead of allow(dead_code) * stack-switching: document continuation roots tracing using match arms --------- Co-authored-by: Paul Osborne <paul.osborne@fastly.com>
1 parent c71d3aa commit 63d482c

File tree

50 files changed

+2666
-124
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+2666
-124
lines changed

.github/workflows/main.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,9 @@ jobs:
371371
-p wasmtime --no-default-features --features threads
372372
-p wasmtime --no-default-features --features runtime,threads
373373
-p wasmtime --no-default-features --features cranelift,threads
374+
-p wasmtime --no-default-features --features stack-switching
375+
-p wasmtime --no-default-features --features cranelift,stack-switching
376+
-p wasmtime --no-default-features --features runtime,stack-switching
374377
-p wasmtime --features incremental-cache
375378
-p wasmtime --features profile-pulley
376379
-p wasmtime --all-features

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,7 @@ default = [
431431
"gc",
432432
"gc-drc",
433433
"gc-null",
434+
"stack-switching",
434435
"winch",
435436
"pulley",
436437

@@ -489,6 +490,7 @@ gc = ["wasmtime-cli-flags/gc", "wasmtime/gc"]
489490
gc-drc = ["gc", "wasmtime/gc-drc", "wasmtime-cli-flags/gc-drc"]
490491
gc-null = ["gc", "wasmtime/gc-null", "wasmtime-cli-flags/gc-null"]
491492
pulley = ["wasmtime-cli-flags/pulley"]
493+
stack-switching = ["wasmtime/stack-switching", "wasmtime-cli-flags/stack-switching"]
492494

493495
# CLI subcommands for the `wasmtime` executable. See `wasmtime $cmd --help`
494496
# for more information on each subcommand.

crates/c-api/include/wasmtime/config.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,14 @@ WASMTIME_CONFIG_PROP(void, wasm_wide_arithmetic, bool)
250250

251251
#ifdef WASMTIME_FEATURE_COMPILER
252252

253+
/**
254+
* \brief Configures whether the WebAssembly stack switching
255+
* proposal is enabled.
256+
*
257+
* This setting is `false` by default.
258+
*/
259+
WASMTIME_CONFIG_PROP(void, wasm_stack_switching, bool)
260+
253261
/**
254262
* \brief Configures how JIT code will be compiled.
255263
*

crates/c-api/src/config.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,11 @@ pub extern "C" fn wasmtime_config_wasm_memory64_set(c: &mut wasm_config_t, enabl
140140
c.config.wasm_memory64(enable);
141141
}
142142

143+
#[unsafe(no_mangle)]
144+
pub extern "C" fn wasmtime_config_wasm_stack_switching_set(c: &mut wasm_config_t, enable: bool) {
145+
c.config.wasm_stack_switching(enable);
146+
}
147+
143148
#[unsafe(no_mangle)]
144149
#[cfg(any(feature = "cranelift", feature = "winch"))]
145150
pub extern "C" fn wasmtime_config_strategy_set(

crates/cli-flags/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,4 @@ gc-null = ["gc", "wasmtime/gc-null"]
3939
threads = ["wasmtime/threads"]
4040
memory-protection-keys = ["wasmtime/memory-protection-keys"]
4141
pulley = ["wasmtime/pulley"]
42+
stack-switching = ["wasmtime/stack-switching"]

crates/cli-flags/src/lib.rs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,8 @@ wasmtime_option_group! {
377377
pub component_model_error_context: Option<bool>,
378378
/// Configure support for the function-references proposal.
379379
pub function_references: Option<bool>,
380+
/// Configure support for the stack-switching proposal.
381+
pub stack_switching: Option<bool>,
380382
/// Configure support for the GC proposal.
381383
pub gc: Option<bool>,
382384
/// Configure support for the custom-page-sizes proposal.
@@ -818,6 +820,23 @@ impl CommonOptions {
818820
config.native_unwind_info(enable);
819821
}
820822

823+
// async_stack_size enabled by either async or stack-switching, so
824+
// cannot directly use match_feature!
825+
#[cfg(any(feature = "async", feature = "stack-switching"))]
826+
{
827+
if let Some(size) = self.wasm.async_stack_size {
828+
config.async_stack_size(size);
829+
}
830+
}
831+
#[cfg(not(any(feature = "async", feature = "stack-switching")))]
832+
{
833+
if let Some(_size) = self.wasm.async_stack_size {
834+
anyhow::bail!(concat!(
835+
"support for async/stack-switching disabled at compile time"
836+
));
837+
}
838+
}
839+
821840
match_feature! {
822841
["pooling-allocator" : self.opts.pooling_allocator.or(pooling_allocator_default)]
823842
enable => {
@@ -923,11 +942,6 @@ impl CommonOptions {
923942
);
924943
}
925944

926-
match_feature! {
927-
["async" : self.wasm.async_stack_size]
928-
size => config.async_stack_size(size),
929-
_ => err,
930-
}
931945
match_feature! {
932946
["async" : self.wasm.async_stack_zeroing]
933947
enable => config.async_stack_zeroing(enable),
@@ -940,7 +954,7 @@ impl CommonOptions {
940954
// If `-Wasync-stack-size` isn't passed then automatically adjust it
941955
// to the wasm stack size provided here too. That prevents the need
942956
// to pass both when one can generally be inferred from the other.
943-
#[cfg(feature = "async")]
957+
#[cfg(any(feature = "async", feature = "stack-switching"))]
944958
if self.wasm.async_stack_size.is_none() {
945959
const DEFAULT_HOST_STACK: usize = 512 << 10;
946960
config.async_stack_size(max + DEFAULT_HOST_STACK);
@@ -983,6 +997,9 @@ impl CommonOptions {
983997
if let Some(enable) = self.wasm.memory64.or(all) {
984998
config.wasm_memory64(enable);
985999
}
1000+
if let Some(enable) = self.wasm.stack_switching {
1001+
config.wasm_stack_switching(enable);
1002+
}
9861003
if let Some(enable) = self.wasm.custom_page_sizes.or(all) {
9871004
config.wasm_custom_page_sizes(enable);
9881005
}
@@ -1023,6 +1040,7 @@ impl CommonOptions {
10231040
("gc", gc, wasm_gc)
10241041
("gc", reference_types, wasm_reference_types)
10251042
("gc", function_references, wasm_function_references)
1043+
("stack-switching", stack_switching, wasm_stack_switching)
10261044
}
10271045
Ok(())
10281046
}

crates/cranelift/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,5 @@ wmemcheck = ["wasmtime-environ/wmemcheck"]
4646
gc = ["wasmtime-environ/gc"]
4747
gc-drc = ["gc", "wasmtime-environ/gc-drc"]
4848
gc-null = ["gc", "wasmtime-environ/gc-null"]
49+
stack-switching = []
4950
threads = ["wasmtime-environ/threads"]

crates/cranelift/src/func_environ.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3793,3 +3793,17 @@ fn index_type_to_ir_type(index_type: IndexType) -> ir::Type {
37933793
IndexType::I64 => I64,
37943794
}
37953795
}
3796+
3797+
/// TODO(10248) This is removed in the next stack switching PR. It stops the
3798+
/// compiler from complaining about the stack switching libcalls being dead
3799+
/// code.
3800+
#[cfg(feature = "stack-switching")]
3801+
#[allow(
3802+
dead_code,
3803+
reason = "Dummy function to supress more dead code warnings"
3804+
)]
3805+
pub fn use_stack_switching_libcalls() {
3806+
let _ = BuiltinFunctions::cont_new;
3807+
let _ = BuiltinFunctions::table_grow_cont_obj;
3808+
let _ = BuiltinFunctions::table_fill_cont_obj;
3809+
}

crates/cranelift/src/func_environ/gc/enabled.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,12 @@ fn read_field_at_addr(
153153
.call(get_interned_func_ref, &[vmctx, func_ref_id, expected_ty]);
154154
builder.func.dfg.first_result(call_inst)
155155
}
156-
WasmHeapTopType::Cont => todo!(), // FIXME: #10248 stack switching support.
156+
WasmHeapTopType::Cont => {
157+
// TODO(#10248) GC integration for stack switching
158+
return Err(wasmtime_environ::WasmError::Unsupported(
159+
"Stack switching feature not compatbile with GC, yet".to_string(),
160+
));
161+
}
157162
},
158163
},
159164
};
@@ -1032,6 +1037,8 @@ pub fn translate_ref_test(
10321037
| WasmHeapType::NoExtern
10331038
| WasmHeapType::Func
10341039
| WasmHeapType::NoFunc
1040+
| WasmHeapType::Cont
1041+
| WasmHeapType::NoCont
10351042
| WasmHeapType::I31 => unreachable!("handled top, bottom, and i31 types above"),
10361043

10371044
// For these abstract but non-top and non-bottom types, we check the
@@ -1086,8 +1093,12 @@ pub fn translate_ref_test(
10861093

10871094
func_env.is_subtype(builder, actual_shared_ty, expected_shared_ty)
10881095
}
1089-
1090-
WasmHeapType::Cont | WasmHeapType::ConcreteCont(_) | WasmHeapType::NoCont => todo!(), // FIXME: #10248 stack switching support.
1096+
WasmHeapType::ConcreteCont(_) => {
1097+
// TODO(#10248) GC integration for stack switching
1098+
return Err(wasmtime_environ::WasmError::Unsupported(
1099+
"Stack switching feature not compatbile with GC, yet".to_string(),
1100+
));
1101+
}
10911102
};
10921103
builder.ins().jump(continue_block, &[result.into()]);
10931104

@@ -1409,8 +1420,9 @@ impl FuncEnvironment<'_> {
14091420
WasmHeapType::Func | WasmHeapType::ConcreteFunc(_) | WasmHeapType::NoFunc => {
14101421
unreachable!()
14111422
}
1412-
1413-
WasmHeapType::Cont | WasmHeapType::ConcreteCont(_) | WasmHeapType::NoCont => todo!(), // FIXME: #10248 stack switching support.
1423+
WasmHeapType::Cont | WasmHeapType::ConcreteCont(_) | WasmHeapType::NoCont => {
1424+
unreachable!()
1425+
}
14141426
};
14151427

14161428
match (ty.nullable, might_be_i31) {

crates/cranelift/src/lib.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ pub const TRAP_HEAP_MISALIGNED: TrapCode =
6161
TrapCode::unwrap_user(Trap::HeapMisaligned as u8 + TRAP_OFFSET);
6262
pub const TRAP_TABLE_OUT_OF_BOUNDS: TrapCode =
6363
TrapCode::unwrap_user(Trap::TableOutOfBounds as u8 + TRAP_OFFSET);
64+
pub const TRAP_UNHANDLED_TAG: TrapCode =
65+
TrapCode::unwrap_user(Trap::UnhandledTag as u8 + TRAP_OFFSET);
66+
pub const TRAP_CONTINUATION_ALREADY_CONSUMED: TrapCode =
67+
TrapCode::unwrap_user(Trap::ContinuationAlreadyConsumed as u8 + TRAP_OFFSET);
6468
pub const TRAP_CAST_FAILURE: TrapCode =
6569
TrapCode::unwrap_user(Trap::CastFailure as u8 + TRAP_OFFSET);
6670

@@ -202,7 +206,11 @@ fn reference_type(wasm_ht: WasmHeapType, pointer_type: ir::Type) -> ir::Type {
202206
match wasm_ht.top() {
203207
WasmHeapTopType::Func => pointer_type,
204208
WasmHeapTopType::Any | WasmHeapTopType::Extern => ir::types::I32,
205-
WasmHeapTopType::Cont => todo!(), // FIXME: #10248 stack switching support.
209+
WasmHeapTopType::Cont =>
210+
// TODO(10248) This is added in a follow-up PR
211+
{
212+
unimplemented!("codegen for stack switching types not implemented, yet")
213+
}
206214
}
207215
}
208216

0 commit comments

Comments
 (0)