wasmi/engine/config.rs
1use super::{EnforcedLimits, StackLimits};
2use crate::core::UntypedVal;
3use core::{mem::size_of, num::NonZeroU64};
4use wasmparser::WasmFeatures;
5
6/// The default amount of stacks kept in the cache at most.
7const DEFAULT_CACHED_STACKS: usize = 2;
8
9/// Configuration for an [`Engine`].
10///
11/// [`Engine`]: [`crate::Engine`]
12#[derive(Debug, Copy, Clone)]
13pub struct Config {
14 /// The limits set on the value stack and call stack.
15 stack_limits: StackLimits,
16 /// The amount of Wasm stacks to keep in cache at most.
17 cached_stacks: usize,
18 /// Is `true` if the `mutable-global` Wasm proposal is enabled.
19 mutable_global: bool,
20 /// Is `true` if the `sign-extension` Wasm proposal is enabled.
21 sign_extension: bool,
22 /// Is `true` if the `saturating-float-to-int` Wasm proposal is enabled.
23 saturating_float_to_int: bool,
24 /// Is `true` if the [`multi-value`] Wasm proposal is enabled.
25 multi_value: bool,
26 /// Is `true` if the [`bulk-memory`] Wasm proposal is enabled.
27 bulk_memory: bool,
28 /// Is `true` if the [`reference-types`] Wasm proposal is enabled.
29 reference_types: bool,
30 /// Is `true` if the [`tail-call`] Wasm proposal is enabled.
31 tail_call: bool,
32 /// Is `true` if the [`extended-const`] Wasm proposal is enabled.
33 extended_const: bool,
34 /// Is `true` if Wasm instructions on `f32` and `f64` types are allowed.
35 floats: bool,
36 /// Is `true` if Wasmi executions shall consume fuel.
37 consume_fuel: bool,
38 /// The configured fuel costs of all Wasmi bytecode instructions.
39 fuel_costs: FuelCosts,
40 /// The mode of Wasm to Wasmi bytecode compilation.
41 compilation_mode: CompilationMode,
42 /// Enforced limits for Wasm module parsing and compilation.
43 limits: EnforcedLimits,
44}
45
46/// Type storing all kinds of fuel costs of instructions.
47#[derive(Debug, Copy, Clone)]
48pub struct FuelCosts {
49 /// The base fuel costs for all instructions.
50 base: u64,
51 /// The register copies that can be performed per unit of fuel.
52 copies_per_fuel: NonZeroU64,
53 /// The bytes that can be copied per unit of fuel.
54 bytes_per_fuel: NonZeroU64,
55}
56
57impl FuelCosts {
58 /// Returns the base fuel costs for all Wasmi IR instructions.
59 pub fn base(&self) -> u64 {
60 self.base
61 }
62
63 /// Returns the base fuel costs for all Wasmi IR entity related instructions.
64 pub fn entity(&self) -> u64 {
65 // Note: For simplicity we currently simply use base costs.
66 self.base
67 }
68
69 /// Returns the base fuel costs for all Wasmi IR load instructions.
70 pub fn load(&self) -> u64 {
71 // Note: For simplicity we currently simply use base costs.
72 self.base
73 }
74
75 /// Returns the base fuel costs for all Wasmi IR store instructions.
76 pub fn store(&self) -> u64 {
77 // Note: For simplicity we currently simply use base costs.
78 self.base
79 }
80
81 /// Returns the base fuel costs for all Wasmi IR call instructions.
82 pub fn call(&self) -> u64 {
83 // Note: For simplicity we currently simply use base costs.
84 self.base
85 }
86
87 /// Returns the number of register copies performed per unit of fuel.
88 fn copies_per_fuel(&self) -> NonZeroU64 {
89 self.copies_per_fuel
90 }
91
92 /// Returns the number of byte copies performed per unit of fuel.
93 fn bytes_per_fuel(&self) -> NonZeroU64 {
94 self.bytes_per_fuel
95 }
96
97 /// Returns the fuel costs for `len_copies` register copies in Wasmi IR.
98 ///
99 /// # Note
100 ///
101 /// Registers are copied for the following Wasmi IR instructions:
102 ///
103 /// - calls (parameter passing)
104 /// - `copy_span`
105 /// - `copy_many`
106 /// - `return_span`
107 /// - `return_many`
108 /// - `table.grow` (+ variants)
109 /// - `table.copy` (+ variants)
110 /// - `table.fill` (+ variants)
111 /// - `table.init` (+ variants)
112 pub fn fuel_for_copies(&self, len_copies: u64) -> u64 {
113 Self::costs_per(len_copies, self.copies_per_fuel())
114 }
115
116 /// Returns the fuel costs for `len_copies` register copies in Wasmi IR.
117 ///
118 /// # Note
119 ///
120 /// Registers are copied for the following Wasmi IR instructions:
121 ///
122 /// - `memory.grow`
123 /// - `memory.copy`
124 /// - `memory.fill`
125 /// - `memory.init`
126 pub fn fuel_for_bytes(&self, len_bytes: u64) -> u64 {
127 Self::costs_per(len_bytes, self.bytes_per_fuel())
128 }
129
130 /// Returns the fuel consumption of the amount of items with costs per items.
131 fn costs_per(len_items: u64, items_per_fuel: NonZeroU64) -> u64 {
132 len_items / items_per_fuel
133 }
134}
135
136impl Default for FuelCosts {
137 fn default() -> Self {
138 let bytes_per_fuel = 64;
139 let bytes_per_register = size_of::<UntypedVal>() as u64;
140 let registers_per_fuel = bytes_per_fuel / bytes_per_register;
141 Self {
142 base: 1,
143 copies_per_fuel: NonZeroU64::new(registers_per_fuel)
144 .unwrap_or_else(|| panic!("invalid zero value for copies_per_fuel value")),
145 bytes_per_fuel: NonZeroU64::new(bytes_per_fuel)
146 .unwrap_or_else(|| panic!("invalid zero value for copies_per_fuel value")),
147 }
148 }
149}
150
151/// The chosen mode of Wasm to Wasmi bytecode compilation.
152#[derive(Debug, Default, Copy, Clone)]
153pub enum CompilationMode {
154 /// The Wasm code is compiled eagerly to Wasmi bytecode.
155 #[default]
156 Eager,
157 /// The Wasm code is validated eagerly and translated lazily on first use.
158 LazyTranslation,
159 /// The Wasm code is validated and translated lazily on first use.
160 ///
161 /// # Note
162 ///
163 /// This mode must not be used if the result of Wasm execution
164 /// must be deterministic amongst multiple Wasm implementations.
165 Lazy,
166}
167
168impl Default for Config {
169 fn default() -> Self {
170 Self {
171 stack_limits: StackLimits::default(),
172 cached_stacks: DEFAULT_CACHED_STACKS,
173 mutable_global: true,
174 sign_extension: true,
175 saturating_float_to_int: true,
176 multi_value: true,
177 bulk_memory: true,
178 reference_types: true,
179 tail_call: true,
180 extended_const: true,
181 floats: true,
182 consume_fuel: false,
183 fuel_costs: FuelCosts::default(),
184 compilation_mode: CompilationMode::default(),
185 limits: EnforcedLimits::default(),
186 }
187 }
188}
189
190impl Config {
191 /// Sets the [`StackLimits`] for the [`Config`].
192 pub fn set_stack_limits(&mut self, stack_limits: StackLimits) -> &mut Self {
193 self.stack_limits = stack_limits;
194 self
195 }
196
197 /// Returns the [`StackLimits`] of the [`Config`].
198 pub(super) fn stack_limits(&self) -> StackLimits {
199 self.stack_limits
200 }
201
202 /// Sets the maximum amount of cached stacks for reuse for the [`Config`].
203 ///
204 /// # Note
205 ///
206 /// Defaults to 2.
207 pub fn set_cached_stacks(&mut self, amount: usize) -> &mut Self {
208 self.cached_stacks = amount;
209 self
210 }
211
212 /// Returns the maximum amount of cached stacks for reuse of the [`Config`].
213 pub(super) fn cached_stacks(&self) -> usize {
214 self.cached_stacks
215 }
216
217 /// Enable or disable the [`mutable-global`] Wasm proposal for the [`Config`].
218 ///
219 /// # Note
220 ///
221 /// Enabled by default.
222 ///
223 /// [`mutable-global`]: https://github.com/WebAssembly/mutable-global
224 pub fn wasm_mutable_global(&mut self, enable: bool) -> &mut Self {
225 self.mutable_global = enable;
226 self
227 }
228
229 /// Enable or disable the [`sign-extension`] Wasm proposal for the [`Config`].
230 ///
231 /// # Note
232 ///
233 /// Enabled by default.
234 ///
235 /// [`sign-extension`]: https://github.com/WebAssembly/sign-extension-ops
236 pub fn wasm_sign_extension(&mut self, enable: bool) -> &mut Self {
237 self.sign_extension = enable;
238 self
239 }
240
241 /// Enable or disable the [`saturating-float-to-int`] Wasm proposal for the [`Config`].
242 ///
243 /// # Note
244 ///
245 /// Enabled by default.
246 ///
247 /// [`saturating-float-to-int`]:
248 /// https://github.com/WebAssembly/nontrapping-float-to-int-conversions
249 pub fn wasm_saturating_float_to_int(&mut self, enable: bool) -> &mut Self {
250 self.saturating_float_to_int = enable;
251 self
252 }
253
254 /// Enable or disable the [`multi-value`] Wasm proposal for the [`Config`].
255 ///
256 /// # Note
257 ///
258 /// Enabled by default.
259 ///
260 /// [`multi-value`]: https://github.com/WebAssembly/multi-value
261 pub fn wasm_multi_value(&mut self, enable: bool) -> &mut Self {
262 self.multi_value = enable;
263 self
264 }
265
266 /// Enable or disable the [`bulk-memory`] Wasm proposal for the [`Config`].
267 ///
268 /// # Note
269 ///
270 /// Enabled by default.
271 ///
272 /// [`bulk-memory`]: https://github.com/WebAssembly/bulk-memory-operations
273 pub fn wasm_bulk_memory(&mut self, enable: bool) -> &mut Self {
274 self.bulk_memory = enable;
275 self
276 }
277
278 /// Enable or disable the [`reference-types`] Wasm proposal for the [`Config`].
279 ///
280 /// # Note
281 ///
282 /// Enabled by default.
283 ///
284 /// [`reference-types`]: https://github.com/WebAssembly/reference-types
285 pub fn wasm_reference_types(&mut self, enable: bool) -> &mut Self {
286 self.reference_types = enable;
287 self
288 }
289
290 /// Enable or disable the [`tail-call`] Wasm proposal for the [`Config`].
291 ///
292 /// # Note
293 ///
294 /// Enabled by default.
295 ///
296 /// [`tail-call`]: https://github.com/WebAssembly/tail-calls
297 pub fn wasm_tail_call(&mut self, enable: bool) -> &mut Self {
298 self.tail_call = enable;
299 self
300 }
301
302 /// Enable or disable the [`extended-const`] Wasm proposal for the [`Config`].
303 ///
304 /// # Note
305 ///
306 /// Enabled by default.
307 ///
308 /// [`extended-const`]: https://github.com/WebAssembly/extended-const
309 pub fn wasm_extended_const(&mut self, enable: bool) -> &mut Self {
310 self.extended_const = enable;
311 self
312 }
313
314 /// Enable or disable Wasm floating point (`f32` and `f64`) instructions and types.
315 ///
316 /// Enabled by default.
317 pub fn floats(&mut self, enable: bool) -> &mut Self {
318 self.floats = enable;
319 self
320 }
321
322 /// Configures whether Wasmi will consume fuel during execution to either halt execution as desired.
323 ///
324 /// # Note
325 ///
326 /// This configuration can be used to make Wasmi instrument its internal bytecode
327 /// so that it consumes fuel as it executes. Once an execution runs out of fuel
328 /// a [`TrapCode::OutOfFuel`](crate::core::TrapCode::OutOfFuel) trap is raised.
329 /// This way users can deterministically halt or yield the execution of WebAssembly code.
330 ///
331 /// - Use [`Store::set_fuel`](crate::Store::set_fuel) to set the remaining fuel of the [`Store`] before
332 /// executing some code as the [`Store`] start with no fuel.
333 /// - Use [`Caller::set_fuel`](crate::Caller::set_fuel) to update the remaining fuel when executing host functions.
334 ///
335 /// Disabled by default.
336 ///
337 /// [`Store`]: crate::Store
338 /// [`Engine`]: crate::Engine
339 pub fn consume_fuel(&mut self, enable: bool) -> &mut Self {
340 self.consume_fuel = enable;
341 self
342 }
343
344 /// Returns `true` if the [`Config`] enables fuel consumption by the [`Engine`].
345 ///
346 /// [`Engine`]: crate::Engine
347 pub(crate) fn get_consume_fuel(&self) -> bool {
348 self.consume_fuel
349 }
350
351 /// Returns the configured [`FuelCosts`].
352 pub(crate) fn fuel_costs(&self) -> &FuelCosts {
353 &self.fuel_costs
354 }
355
356 /// Sets the [`CompilationMode`] used for the [`Engine`].
357 ///
358 /// By default [`CompilationMode::Eager`] is used.
359 ///
360 /// [`Engine`]: crate::Engine
361 pub fn compilation_mode(&mut self, mode: CompilationMode) -> &mut Self {
362 self.compilation_mode = mode;
363 self
364 }
365
366 /// Returns the [`CompilationMode`] used for the [`Engine`].
367 ///
368 /// [`Engine`]: crate::Engine
369 pub(super) fn get_compilation_mode(&self) -> CompilationMode {
370 self.compilation_mode
371 }
372
373 /// Sets the [`EnforcedLimits`] enforced by the [`Engine`] for Wasm module parsing and compilation.
374 ///
375 /// By default no limits are enforced.
376 ///
377 /// [`Engine`]: crate::Engine
378 pub fn enforced_limits(&mut self, limits: EnforcedLimits) -> &mut Self {
379 self.limits = limits;
380 self
381 }
382
383 /// Returns the [`EnforcedLimits`] used for the [`Engine`].
384 ///
385 /// [`Engine`]: crate::Engine
386 pub(crate) fn get_engine_limits(&self) -> &EnforcedLimits {
387 &self.limits
388 }
389
390 /// Returns the [`WasmFeatures`] represented by the [`Config`].
391 pub(crate) fn wasm_features(&self) -> WasmFeatures {
392 WasmFeatures {
393 multi_value: self.multi_value,
394 mutable_global: self.mutable_global,
395 saturating_float_to_int: self.saturating_float_to_int,
396 sign_extension: self.sign_extension,
397 bulk_memory: self.bulk_memory,
398 reference_types: self.reference_types,
399 tail_call: self.tail_call,
400 extended_const: self.extended_const,
401 floats: self.floats,
402 component_model: false,
403 simd: false,
404 relaxed_simd: false,
405 threads: false,
406 multi_memory: false,
407 exceptions: false,
408 memory64: false,
409 memory_control: false,
410 }
411 }
412}