Skip to main content

wasmer_interface_types/interpreter/
mod.rs

1//! A stack-based interpreter to execute instructions of WIT adapters.
2
3mod instructions;
4pub mod stack;
5pub mod wasm;
6
7use crate::{
8    errors::{InstructionResult, InterpreterResult},
9    values::InterfaceValue,
10};
11pub use instructions::Instruction;
12use stack::Stack;
13use std::{convert::TryFrom, marker::PhantomData};
14
15/// Represents the `Runtime`, which is used by an adapter to execute
16/// its instructions.
17pub(crate) struct Runtime<'invocation, 'instance, Instance, Export, LocalImport, Memory, MemoryView>
18where
19    Export: wasm::structures::Export + 'instance,
20    LocalImport: wasm::structures::LocalImport + 'instance,
21    Memory: wasm::structures::Memory<MemoryView> + 'instance,
22    MemoryView: wasm::structures::MemoryView,
23    Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView> + 'instance,
24{
25    /// The invocation inputs are all the arguments received by an
26    /// adapter.
27    invocation_inputs: &'invocation [InterfaceValue],
28
29    /// Each runtime (so adapter) has its own stack instance.
30    stack: Stack<InterfaceValue>,
31
32    /// The WebAssembly module instance. It is used by adapter's
33    /// instructions.
34    wasm_instance: &'instance mut Instance,
35
36    /// Phantom data.
37    _phantom: PhantomData<(Export, LocalImport, Memory, MemoryView)>,
38}
39
40/// Type alias for an executable instruction. It's an implementation
41/// details, but an instruction is a boxed closure instance.
42pub(crate) type ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView> = Box<
43    dyn Fn(
44        &mut Runtime<Instance, Export, LocalImport, Memory, MemoryView>,
45    ) -> InstructionResult<()>,
46>;
47
48/// An interpreter is the central piece of this crate. It is a set of
49/// executable instructions. Each instruction takes the runtime as
50/// argument. The runtime holds the invocation inputs, [the
51/// stack](stack), and [the WebAssembly instance](wasm).
52///
53/// When the interpreter executes the instructions, each of them can
54/// query the WebAssembly instance, operates on the stack, or reads
55/// the invocation inputs. At the end of the execution, the stack
56/// supposedly contains a result. Since an interpreter is used by a
57/// WIT adapter to execute its instructions, the result on the stack
58/// is the result of the adapter.
59///
60/// # Example
61///
62/// ```rust,ignore
63/// use std::{cell::Cell, collections::HashMap, convert::TryInto};
64/// use wasmer_interface_types::{
65///     interpreter::{
66///         instructions::tests::{Export, Instance, LocalImport, Memory, MemoryView},
67/// //      ^^^^^^^^^^^^ This is private and for testing purposes only.
68/// //                   It is basically a fake WebAssembly runtime.
69///         stack::Stackable,
70///         Instruction, Interpreter,
71///     },
72///     types::InterfaceType,
73///     values::InterfaceValue,
74/// };
75///
76/// // 1. Creates an interpreter from a set of instructions. They will
77/// //    be transformed into executable instructions.
78/// let interpreter: Interpreter<Instance, Export, LocalImport, Memory, MemoryView> = (&vec![
79///     Instruction::ArgumentGet { index: 1 },
80///     Instruction::ArgumentGet { index: 0 },
81///     Instruction::CallCore { function_index: 42 },
82/// ])
83///     .try_into()
84///     .unwrap();
85///
86/// // 2. Defines the arguments of the adapter.
87/// let invocation_inputs = vec![InterfaceValue::I32(3), InterfaceValue::I32(4)];
88///
89/// // 3. Creates a WebAssembly instance.
90/// let mut instance = Instance {
91///     // 3.1. Defines one function: `fn sum(a: i32, b: i32) -> i32 { a + b }`.
92///     locals_or_imports: {
93///         let mut hashmap = HashMap::new();
94///         hashmap.insert(
95///             42,
96///             LocalImport {
97///                 // Defines the argument types of the function.
98///                 inputs: vec![InterfaceType::I32, InterfaceType::I32],
99///
100///                 // Defines the result types.
101///                 outputs: vec![InterfaceType::I32],
102///
103///                 // Defines the function implementation.
104///                 function: |arguments: &[InterfaceValue]| {
105///                     let a: i32 = (&arguments[0]).try_into().unwrap();
106///                     let b: i32 = (&arguments[1]).try_into().unwrap();
107///
108///                     Ok(vec![InterfaceValue::I32(a + b)])
109///                 },
110///             },
111///         );
112///     },
113///     ..Default::default()
114/// };
115///
116/// // 4. Executes the instructions.
117/// let run = interpreter.run(&invocation_inputs, &mut instance);
118///
119/// assert!(run.is_ok());
120///
121/// let stack = run.unwrap();
122///
123/// // 5. Read the stack to get the result.
124/// assert_eq!(stack.as_slice(), &[InterfaceValue::I32(7)]);
125/// ```
126pub struct Interpreter<Instance, Export, LocalImport, Memory, MemoryView>
127where
128    Export: wasm::structures::Export,
129    LocalImport: wasm::structures::LocalImport,
130    Memory: wasm::structures::Memory<MemoryView>,
131    MemoryView: wasm::structures::MemoryView,
132    Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
133{
134    executable_instructions:
135        Vec<ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView>>,
136}
137
138impl<Instance, Export, LocalImport, Memory, MemoryView>
139    Interpreter<Instance, Export, LocalImport, Memory, MemoryView>
140where
141    Export: wasm::structures::Export,
142    LocalImport: wasm::structures::LocalImport,
143    Memory: wasm::structures::Memory<MemoryView>,
144    MemoryView: wasm::structures::MemoryView,
145    Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
146{
147    fn iter(
148        &self,
149    ) -> impl Iterator<
150        Item = &ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView>,
151    > + '_ {
152        self.executable_instructions.iter()
153    }
154
155    /// Runs the interpreter, such as:
156    ///   1. Create a fresh stack,
157    ///   2. Create a fresh stack,
158    ///   3. Execute the instructions one after the other, and
159    ///      returns the stack.
160    pub fn run(
161        &self,
162        invocation_inputs: &[InterfaceValue],
163        wasm_instance: &mut Instance,
164    ) -> InterpreterResult<Stack<InterfaceValue>> {
165        let mut runtime = Runtime {
166            invocation_inputs,
167            stack: Stack::new(),
168            wasm_instance,
169            _phantom: PhantomData,
170        };
171
172        for executable_instruction in self.iter() {
173            executable_instruction(&mut runtime)?;
174        }
175
176        Ok(runtime.stack)
177    }
178}
179
180/// Transforms a `Vec<Instruction>` into an `Interpreter`.
181impl<Instance, Export, LocalImport, Memory, MemoryView> TryFrom<&Vec<Instruction>>
182    for Interpreter<Instance, Export, LocalImport, Memory, MemoryView>
183where
184    Export: wasm::structures::Export,
185    LocalImport: wasm::structures::LocalImport,
186    Memory: wasm::structures::Memory<MemoryView>,
187    MemoryView: wasm::structures::MemoryView,
188    Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
189{
190    type Error = ();
191
192    fn try_from(instructions: &Vec<Instruction>) -> Result<Self, Self::Error> {
193        let executable_instructions = instructions
194            .iter()
195            .map(|instruction| match instruction {
196                Instruction::ArgumentGet { index } => {
197                    instructions::argument_get(*index, *instruction)
198                }
199
200                Instruction::CallCore { function_index } => {
201                    instructions::call_core(*function_index, *instruction)
202                }
203
204                Instruction::S8FromI32 => instructions::s8_from_i32(*instruction),
205                Instruction::S8FromI64 => instructions::s8_from_i64(*instruction),
206                Instruction::S16FromI32 => instructions::s16_from_i32(*instruction),
207                Instruction::S16FromI64 => instructions::s16_from_i64(*instruction),
208                Instruction::S32FromI32 => instructions::s32_from_i32(*instruction),
209                Instruction::S32FromI64 => instructions::s32_from_i64(*instruction),
210                Instruction::S64FromI32 => instructions::s64_from_i32(*instruction),
211                Instruction::S64FromI64 => instructions::s64_from_i64(*instruction),
212                Instruction::I32FromS8 => instructions::i32_from_s8(*instruction),
213                Instruction::I32FromS16 => instructions::i32_from_s16(*instruction),
214                Instruction::I32FromS32 => instructions::i32_from_s32(*instruction),
215                Instruction::I32FromS64 => instructions::i32_from_s64(*instruction),
216                Instruction::I64FromS8 => instructions::i64_from_s8(*instruction),
217                Instruction::I64FromS16 => instructions::i64_from_s16(*instruction),
218                Instruction::I64FromS32 => instructions::i64_from_s32(*instruction),
219                Instruction::I64FromS64 => instructions::i64_from_s64(*instruction),
220                Instruction::U8FromI32 => instructions::u8_from_i32(*instruction),
221                Instruction::U8FromI64 => instructions::u8_from_i64(*instruction),
222                Instruction::U16FromI32 => instructions::u16_from_i32(*instruction),
223                Instruction::U16FromI64 => instructions::u16_from_i64(*instruction),
224                Instruction::U32FromI32 => instructions::u32_from_i32(*instruction),
225                Instruction::U32FromI64 => instructions::u32_from_i64(*instruction),
226                Instruction::U64FromI32 => instructions::u64_from_i32(*instruction),
227                Instruction::U64FromI64 => instructions::u64_from_i64(*instruction),
228                Instruction::I32FromU8 => instructions::i32_from_u8(*instruction),
229                Instruction::I32FromU16 => instructions::i32_from_u16(*instruction),
230                Instruction::I32FromU32 => instructions::i32_from_u32(*instruction),
231                Instruction::I32FromU64 => instructions::i32_from_u64(*instruction),
232                Instruction::I64FromU8 => instructions::i64_from_u8(*instruction),
233                Instruction::I64FromU16 => instructions::i64_from_u16(*instruction),
234                Instruction::I64FromU32 => instructions::i64_from_u32(*instruction),
235                Instruction::I64FromU64 => instructions::i64_from_u64(*instruction),
236
237                Instruction::StringLiftMemory => instructions::string_lift_memory(*instruction),
238                Instruction::StringLowerMemory => instructions::string_lower_memory(*instruction),
239                Instruction::StringSize => instructions::string_size(*instruction),
240
241                Instruction::RecordLift { type_index } => {
242                    instructions::record_lift(*type_index, *instruction)
243                }
244                Instruction::RecordLower { type_index } => {
245                    instructions::record_lower(*type_index, *instruction)
246                }
247            })
248            .collect();
249
250        Ok(Interpreter {
251            executable_instructions,
252        })
253    }
254}