wasm/execution/config.rs
1/// Trait that allows user specified configuration for various items during interpretation. Additionally, the types
2/// implementing this trait can act as custom user data within an interpreter instance, passed along to each method of
3/// this trait and host functions whenever they are invoked.
4///
5/// The default implementation of all trait methods have the least overhead, i. e. most can be optimized out fully.
6// It must always be checked that there is no additional performance penalty for the default config!
7pub trait Config {
8 /// Maximum number of values in the value stack
9 const MAX_VALUE_STACK_SIZE: usize = 0xf0000; // 64 Kibi-Values
10
11 /// Maximum number of cascading function invocations
12 const MAX_CALL_STACK_SIZE: usize = 0x1000; // 4 Kibi-Functions
13
14 /// A hook which is called before every wasm instruction
15 ///
16 /// This allows the most intricate insight into the interpreters behavior, at the cost of a
17 /// hefty performance penalty
18 #[inline(always)]
19 fn instruction_hook(&mut self, _bytecode: &[u8], _pc: usize) {}
20
21 /// Amount of fuel to be deducted when a single byte `instr` is hit. The cost corresponding to `UNREACHABLE` and
22 /// `END` instructions and other bytes that do not correspond to any Wasm instruction are ignored.
23 // It must always be checked that the calls to this method fold into a constant if it is just a match statement that
24 // yields constants.
25 #[inline(always)]
26 fn get_flat_cost(_instr: u8) -> u64 {
27 1
28 }
29
30 /// Amount of fuel to be deducted when a multi-byte instruction that starts with the byte 0xFC is hit. This method
31 /// should return the cost of an instruction obtained by prepending 0xFC to of an unsigned 32-bit LEB
32 /// representation of `instr`. Multi-byte sequences obtained this way that do not correspond to any Wasm instruction
33 /// are ignored.
34 // It must always be checked that the calls to this method fold into a constant if it is just a match statement that
35 // yields constants.
36 #[inline(always)]
37 fn get_fc_extension_flat_cost(_instr: u32) -> u64 {
38 1
39 }
40
41 /// Amount of fuel to be deducted when a multi-byte instruction that starts with the byte 0xFD is hit. This method
42 /// should return the cost of an instruction obtained by prepending 0xFD to of an unsigned 32-bit LEB
43 /// representation of `instr`. Multi-byte sequences obtained this way that do not correspond to any Wasm instruction
44 /// are ignored.
45 // It must always be checked that the calls to this method fold into a constant if it is just a match statement that
46 // yields constants.
47 #[inline(always)]
48 fn get_fd_extension_flat_cost(_instr: u32) -> u64 {
49 1
50 }
51
52 /// Amount of fuel to be deducted per element of a single byte instruction `instr` that executes in asymptotically
53 /// linear time with respect to one of the values it pops from the stack.
54 ///
55 /// In Wasm 2.0 specification, this applies to the following instructions:
56 /// - `MEMORY.GROW` of type `[n: i32] -> [i32]`
57 ///
58 /// The cost of the instruction is calculated as `cost := get_flat_cost(instr) + n*get_cost_per_element(instr)`.
59 /// where `n` is the stack value marked in the instruction type signature above. Other instructions and bytes that
60 /// do not correspond to any instruction are ignored.
61 // It must always be checked that the calls to this method fold into a constant if it is just a match statement that
62 // yields constants.
63 #[inline(always)]
64 fn get_cost_per_element(_instr: u8) -> u64 {
65 0
66 }
67
68 /// Amount of fuel to be deducted per element of a multi-byte instruction that starts with the byte 0xFC,
69 /// which executes in asymptotically linear time with respect to one of the values it pops from the stack. This
70 /// method should return the cost of an instruction obtained by prepending 0xFD to of an unsigned 32-bit LEB
71 /// representation of `instr`. Multi-byte sequences obtained this way that do not correspond to any Wasm instruction
72 /// are ignored.
73 ///
74 /// In Wasm 2.0 specification, this applies to the following instructions:
75 /// - `MEMORY.INIT x` of type `[d:i32 s: i32 n: i32] -> []`
76 /// - `MEMORY.FILL` of type `[d: i32 val: i32 n: i32] -> []`
77 /// - `MEMORY.COPY` of type `[d: i32 s: i32 n: i32] -> []`
78 /// - `TABLE.GROW x` of type `[val: ref n: i32] -> [i32]`
79 /// - `TABLE.INIT x y` of type `[d: i32 s: i32 n: i32] -> []`
80 /// - `TABLE.FILL x` of type `[i: i32 val: ref n: i32] -> []`
81 /// - `TABLE.COPY x y` of type `[d: i32 s: i32 n: i32] -> []`
82 ///
83 /// The cost of the instruction is calculated as `cost := get_flat_cost(instr) + n*get_cost_per_element(instr)`.
84 /// where `n` is the stack value marked in the instruction type signature above. Other instructions and multi-byte
85 /// sequences that do not correspond to any instruction are ignored.
86 // It must always be checked that the calls to this method fold into a constant if it is just a match statement that
87 // yields constants.
88 #[inline(always)]
89 fn get_fc_extension_cost_per_element(_instr: u32) -> u64 {
90 0
91 }
92}
93
94/// Default implementation of the interpreter configuration, with all hooks empty
95impl Config for () {}