diff --git a/Cargo.toml b/Cargo.toml index ff1c1e00176d..ee5cce641c14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -437,12 +437,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 ece1e20bcdf9..c8ff1e2c4290 100644 --- a/crates/cli-flags/src/lib.rs +++ b/crates/cli-flags/src/lib.rs @@ -202,6 +202,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 @@ -658,8 +664,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 a8743c910785..7f8b6b2f20fa 100644 --- a/tests/all/cli_tests.rs +++ b/tests/all/cli_tests.rs @@ -1098,6 +1098,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};