Skip to content

Commit 020a3f6

Browse files
authored
Redesign StackLimits API for Engine's config (#1631)
* redesign StackLimits API for Engine's config - Removed `StackLimits` - Removed `Config::set_stack_limits` method - Add `Config::set_{min_stack_height,max_stack_height,max_cached_stacks}` - Add and use `StackConfig` internally * fix broken doc links * fix more broken doc links * apply rustfmt * add Error and Display impls to StackConfigError * re-add deprecated types and APIs with deprecation note * fix Wasmi fuzz configuration
1 parent 9037273 commit 020a3f6

File tree

9 files changed

+235
-87
lines changed

9 files changed

+235
-87
lines changed

crates/fuzz/src/oracle/wasmi.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use wasmi::{
1111
Instance,
1212
Linker,
1313
Module,
14-
StackLimits,
1514
Store,
1615
StoreLimits,
1716
StoreLimitsBuilder,
@@ -62,14 +61,9 @@ impl DifferentialOracleMeta for WasmiOracle {
6261
//
6362
// We increase the maximum stack space for Wasmi (register) to avoid
6463
// common stack overflows in certain generated fuzz test cases this way.
65-
config.set_stack_limits(
66-
StackLimits::new(
67-
1024, // 1 kiB
68-
1024 * 1024 * 10, // 10 MiB
69-
1024,
70-
)
71-
.unwrap(),
72-
);
64+
config.set_min_stack_height(1024); // 1 kiB
65+
config.set_max_stack_height(1024 * 1024 * 10); // 10 MiB
66+
config.set_max_recursion_depth(1024);
7367
config.wasm_custom_page_sizes(true);
7468
config.wasm_wide_arithmetic(true);
7569
let engine = Engine::new(&config);

crates/wasmi/benches/bench/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::{fs::File, io::Read as _};
2-
use wasmi::{Config, StackLimits};
2+
use wasmi::Config;
33

44
/// Returns the Wasm binary at the given `file_name` as `Vec<u8>`.
55
///
@@ -24,7 +24,9 @@ pub fn load_wasm_from_file(file_name: &str) -> Vec<u8> {
2424
pub fn bench_config() -> Config {
2525
let mut config = Config::default();
2626
config.wasm_tail_call(true);
27-
config.set_stack_limits(StackLimits::new(1024, 1024 * 1024, 64 * 1024).unwrap());
27+
config.set_min_stack_height(1024);
28+
config.set_max_stack_height(1024 * 1024);
29+
config.set_max_recursion_depth(64 * 1024);
2830
config
2931
}
3032

crates/wasmi/src/engine/config.rs

Lines changed: 78 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
1-
use super::{EnforcedLimits, StackLimits};
1+
#[expect(deprecated)]
2+
use super::StackLimits;
3+
use super::{EnforcedLimits, StackConfig};
24
use crate::core::FuelCostsProvider;
35
use wasmparser::WasmFeatures;
46

5-
/// The default amount of stacks kept in the cache at most.
6-
const DEFAULT_CACHED_STACKS: usize = 2;
7-
87
/// Configuration for an [`Engine`].
98
///
109
/// [`Engine`]: [`crate::Engine`]
1110
#[derive(Debug, Clone)]
1211
pub struct Config {
1312
/// The limits set on the value stack and call stack.
14-
stack_limits: StackLimits,
15-
/// The amount of Wasm stacks to keep in cache at most.
16-
cached_stacks: usize,
13+
pub(crate) stack: StackConfig,
1714
/// The Wasm features used when validating or translating functions.
1815
features: WasmFeatures,
1916
/// Is `true` if Wasmi executions shall consume fuel.
@@ -48,8 +45,7 @@ pub enum CompilationMode {
4845
impl Default for Config {
4946
fn default() -> Self {
5047
Self {
51-
stack_limits: StackLimits::default(),
52-
cached_stacks: DEFAULT_CACHED_STACKS,
48+
stack: StackConfig::default(),
5349
features: Self::default_features(),
5450
consume_fuel: false,
5551
ignore_custom_sections: false,
@@ -84,29 +80,91 @@ impl Config {
8480
}
8581

8682
/// Sets the [`StackLimits`] for the [`Config`].
87-
pub fn set_stack_limits(&mut self, stack_limits: StackLimits) -> &mut Self {
88-
self.stack_limits = stack_limits;
83+
#[deprecated(
84+
since = "0.51.0",
85+
note = "\
86+
use `Config::set_{min,max}_stack_height`, \
87+
`Config::max_recursion_depth` instead"
88+
)]
89+
#[expect(deprecated)]
90+
pub fn set_stack_limits(&mut self, limits: StackLimits) -> &mut Self {
91+
self.set_min_stack_height(limits.initial_value_stack_height);
92+
self.set_max_stack_height(limits.maximum_value_stack_height);
93+
self.set_max_recursion_depth(limits.maximum_recursion_depth);
8994
self
9095
}
9196

92-
/// Returns the [`StackLimits`] of the [`Config`].
93-
pub(super) fn stack_limits(&self) -> StackLimits {
94-
self.stack_limits
95-
}
96-
9797
/// Sets the maximum amount of cached stacks for reuse for the [`Config`].
9898
///
9999
/// # Note
100100
///
101101
/// Defaults to 2.
102+
#[deprecated(since = "0.51.0", note = "use `Config::set_max_cached_stacks` instead")]
102103
pub fn set_cached_stacks(&mut self, amount: usize) -> &mut Self {
103-
self.cached_stacks = amount;
104+
self.set_max_cached_stacks(amount);
105+
self
106+
}
107+
108+
/// Sets the maximum recursion depth of the [`Engine`]'s stack during execution.
109+
///
110+
/// # Note
111+
///
112+
/// An execution traps if it exceeds this limits.
113+
///
114+
/// [`Engine`]: [`crate::Engine`]
115+
pub fn set_max_recursion_depth(&mut self, value: usize) -> &mut Self {
116+
self.stack.set_max_recursion_depth(value);
117+
self
118+
}
119+
120+
/// Sets the minimum (or initial) height of the [`Engine`]'s value stack in bytes.
121+
///
122+
/// # Note
123+
///
124+
/// - Lower initial heights may improve memory consumption.
125+
/// - Higher initial heights may improve cold start times.
126+
///
127+
/// # Panics
128+
///
129+
/// If `value` is greater than the current maximum height of the value stack.
130+
///
131+
/// [`Engine`]: [`crate::Engine`]
132+
pub fn set_min_stack_height(&mut self, value: usize) -> &mut Self {
133+
if self.stack.set_min_stack_height(value).is_err() {
134+
let max = self.stack.max_stack_height();
135+
panic!("minimum stack height exceeds maximum: min={value}, max={max}");
136+
}
104137
self
105138
}
106139

107-
/// Returns the maximum amount of cached stacks for reuse of the [`Config`].
108-
pub(super) fn cached_stacks(&self) -> usize {
109-
self.cached_stacks
140+
/// Sets the maximum height of the [`Engine`]'s value stack in bytes.
141+
///
142+
/// # Note
143+
///
144+
/// An execution traps if it exceeds this limits.
145+
///
146+
/// # Panics
147+
///
148+
/// If `value` is less than the current minimum height of the value stack.
149+
///
150+
/// [`Engine`]: [`crate::Engine`]
151+
pub fn set_max_stack_height(&mut self, value: usize) -> &mut Self {
152+
if self.stack.set_max_stack_height(value).is_err() {
153+
let max = self.stack.min_stack_height();
154+
panic!("maximum stack height is lower than minimum: min={value}, max={max}");
155+
}
156+
self
157+
}
158+
159+
/// Sets the maximum number of cached stacks for reuse for the [`Config`].
160+
///
161+
/// # Note
162+
///
163+
/// - A higher value may improve execution performance.
164+
/// - A lower value may improve memory consumption.
165+
pub fn set_max_cached_stacks(&mut self, value: usize) -> &mut Self {
166+
self.stack.set_max_cached_stacks(value);
167+
self
110168
}
111169

112170
/// Enable or disable the [`mutable-global`] Wasm proposal for the [`Config`].

crates/wasmi/src/engine/executor/mod.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@ use crate::{
2424
StoreContextMut,
2525
};
2626

27-
#[cfg(doc)]
28-
use crate::engine::StackLimits;
29-
3027
use super::{code_map::CodeMap, ResumableError};
3128

3229
mod cache;
@@ -226,7 +223,7 @@ pub struct EngineExecutor<'engine> {
226223
fn do_nothing<T>(_: &mut T) {}
227224

228225
impl<'engine> EngineExecutor<'engine> {
229-
/// Creates a new [`EngineExecutor`] with the given [`StackLimits`].
226+
/// Creates a new [`EngineExecutor`] for the given [`Stack`].
230227
fn new(code_map: &'engine CodeMap, stack: &'engine mut Stack) -> Self {
231228
Self { code_map, stack }
232229
}

crates/wasmi/src/engine/executor/stack/mod.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub use self::{
1111
ValueStack,
1212
},
1313
};
14-
use crate::{Instance, StackLimits, TrapCode};
14+
use crate::{engine::StackConfig, Instance, TrapCode};
1515

1616
/// Returns a [`TrapCode`] signalling a stack overflow.
1717
#[cold]
@@ -32,12 +32,9 @@ impl Stack {
3232
/// Creates a new [`Stack`] given the [`Config`].
3333
///
3434
/// [`Config`]: [`crate::Config`]
35-
pub fn new(limits: StackLimits) -> Self {
36-
let calls = CallStack::new(limits.maximum_recursion_depth);
37-
let values = ValueStack::new(
38-
limits.initial_value_stack_height,
39-
limits.maximum_value_stack_height,
40-
);
35+
pub fn new(config: &StackConfig) -> Self {
36+
let calls = CallStack::new(config.max_recursion_depth());
37+
let values = ValueStack::new(config.min_stack_height(), config.max_stack_height());
4138
Self { calls, values }
4239
}
4340

crates/wasmi/src/engine/limits/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ mod stack;
44
#[cfg(test)]
55
mod tests;
66

7+
#[expect(deprecated)]
8+
pub use self::stack::StackLimits;
79
pub use self::{
810
engine::{EnforcedLimits, EnforcedLimitsError},
9-
stack::StackLimits,
11+
stack::StackConfig,
1012
};

0 commit comments

Comments
 (0)