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}