diff --git a/Cargo.toml b/Cargo.toml index e7f58b73bf54..dc4e0fe5e54c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -435,12 +435,25 @@ gc = ["wasmtime-cli-flags/gc"] # CLI subcommands for the `wasmtime` executable. See `wasmtime $cmd --help` # for more information on each subcommand. -serve = ["wasi-http", "component-model", "dep:http-body-util", "dep:http"] +serve = [ + "wasi-http", + "component-model", + "dep:http-body-util", + "dep:http", + "wasmtime-cli-flags/async", +] explore = ["dep:wasmtime-explorer", "dep:tempfile"] wast = ["dep:wasmtime-wast"] config = ["cache"] compile = ["cranelift"] -run = ["dep:wasmtime-wasi", "wasmtime/runtime", "dep:listenfd", "dep:wasi-common", "dep:tokio"] +run = [ + "dep:wasmtime-wasi", + "wasmtime/runtime", + "dep:listenfd", + "dep:wasi-common", + "dep:tokio", + "wasmtime-cli-flags/async", +] [[test]] name = "host_segfault" diff --git a/crates/cli-flags/src/lib.rs b/crates/cli-flags/src/lib.rs index 8a7bb6dc9b6b..adeb216ec0da 100644 --- a/crates/cli-flags/src/lib.rs +++ b/crates/cli-flags/src/lib.rs @@ -199,6 +199,12 @@ wasmtime_option_group! { /// Maximum stack size, in bytes, that wasm is allowed to consume before a /// stack overflow is reported. pub max_wasm_stack: Option, + /// Stack size, in bytes, that will be allocated for async stacks. + /// + /// Note that this must be larger than `max-wasm-stack` and the + /// difference between the two is how much stack the host has to execute + /// on. + pub async_stack_size: Option, /// Allow unknown exports when running commands. pub unknown_exports_allow: Option, /// Allow the main module to import unknown functions, using an @@ -652,8 +658,23 @@ impl CommonOptions { anyhow::bail!("memory protection keys require the pooling allocator"); } + match_feature! { + ["async" : self.wasm.async_stack_size] + size => config.async_stack_size(size), + _ => err, + } + if let Some(max) = self.wasm.max_wasm_stack { config.max_wasm_stack(max); + + // If `-Wasync-stack-size` isn't passed then automatically adjust it + // to the wasm stack size provided here too. That prevents the need + // to pass both when one can generally be inferred from the other. + #[cfg(feature = "async")] + if self.wasm.async_stack_size.is_none() { + const DEFAULT_HOST_STACK: usize = 512 << 10; + config.async_stack_size(max + DEFAULT_HOST_STACK); + } } if let Some(enable) = self.wasm.relaxed_simd_deterministic { diff --git a/tests/all/cli_tests.rs b/tests/all/cli_tests.rs index dfb31842a91b..f93ea38e81a7 100644 --- a/tests/all/cli_tests.rs +++ b/tests/all/cli_tests.rs @@ -1093,6 +1093,21 @@ fn mpk_without_pooling() -> Result<()> { Ok(()) } +// Very basic use case: compile binary wasm file and run specific function with arguments. +#[test] +fn increase_stack_size() -> Result<()> { + run_wasmtime(&[ + "run", + "--invoke", + "simple", + &format!("-Wmax-wasm-stack={}", 5 << 20), + "-Ccache=n", + "tests/all/cli_tests/simple.wat", + "4", + ])?; + Ok(()) +} + mod test_programs { use super::{get_wasmtime_command, run_wasmtime}; use anyhow::{bail, Context, Result};