2020-02-10 15:27:04 +01:00
|
|
|
//! A stack-based interpreter to execute instructions of WIT adapters.
|
|
|
|
|
2019-09-26 14:14:46 +02:00
|
|
|
mod instruction;
|
|
|
|
mod instructions;
|
|
|
|
pub mod stack;
|
|
|
|
pub mod wasm;
|
|
|
|
|
2020-03-10 15:41:49 +01:00
|
|
|
use crate::errors::{InstructionResult, InterpreterResult};
|
2019-09-26 14:14:46 +02:00
|
|
|
pub use instruction::Instruction;
|
|
|
|
use stack::Stack;
|
|
|
|
use std::{convert::TryFrom, marker::PhantomData};
|
|
|
|
use wasm::values::InterfaceValue;
|
|
|
|
|
2020-02-12 17:37:06 +01:00
|
|
|
/// Represents the `Runtime`, which is used by an adapter to execute
|
|
|
|
/// its instructions.
|
2019-09-28 00:55:35 +02:00
|
|
|
pub(crate) struct Runtime<'invocation, 'instance, Instance, Export, LocalImport, Memory, MemoryView>
|
2019-09-26 14:14:46 +02:00
|
|
|
where
|
|
|
|
Export: wasm::structures::Export + 'instance,
|
|
|
|
LocalImport: wasm::structures::LocalImport + 'instance,
|
2019-09-28 00:55:35 +02:00
|
|
|
Memory: wasm::structures::Memory<MemoryView> + 'instance,
|
|
|
|
MemoryView: wasm::structures::MemoryView,
|
|
|
|
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView> + 'instance,
|
2019-09-26 14:14:46 +02:00
|
|
|
{
|
2020-02-12 17:37:06 +01:00
|
|
|
/// The invocation inputs are all the arguments received by an
|
|
|
|
/// adapter.
|
2019-09-26 14:14:46 +02:00
|
|
|
invocation_inputs: &'invocation [InterfaceValue],
|
2020-02-12 17:37:06 +01:00
|
|
|
|
|
|
|
/// Each runtime (so adapter) has its own stack instance.
|
2019-09-26 14:14:46 +02:00
|
|
|
stack: Stack<InterfaceValue>,
|
2020-02-12 17:37:06 +01:00
|
|
|
|
|
|
|
/// The WebAssembly module instance. It is used by adapter's
|
|
|
|
/// instructions.
|
2019-10-03 00:13:07 +02:00
|
|
|
wasm_instance: &'instance mut Instance,
|
2020-02-12 17:37:06 +01:00
|
|
|
|
|
|
|
/// Phantom data.
|
2019-09-28 00:55:35 +02:00
|
|
|
_phantom: PhantomData<(Export, LocalImport, Memory, MemoryView)>,
|
2019-09-26 14:14:46 +02:00
|
|
|
}
|
|
|
|
|
2020-02-12 17:37:06 +01:00
|
|
|
/// Type alias for an executable instruction. It's an implementation
|
|
|
|
/// details, but an instruction is a boxed closure instance.
|
2019-09-28 00:55:35 +02:00
|
|
|
pub(crate) type ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView> = Box<
|
2020-03-10 15:41:49 +01:00
|
|
|
dyn Fn(
|
|
|
|
&mut Runtime<Instance, Export, LocalImport, Memory, MemoryView>,
|
|
|
|
) -> InstructionResult<()>,
|
2019-09-28 00:55:35 +02:00
|
|
|
>;
|
2019-09-26 14:14:46 +02:00
|
|
|
|
2020-02-12 17:37:06 +01:00
|
|
|
/// An interpreter is the central piece of this crate. It is a set of
|
|
|
|
/// executable instructions. Each instruction takes the runtime as
|
2020-02-21 12:23:58 +01:00
|
|
|
/// argument. The runtime holds the invocation inputs, [the
|
|
|
|
/// stack](stack), and [the WebAssembly instance](wasm).
|
2020-02-12 17:37:06 +01:00
|
|
|
///
|
|
|
|
/// When the interpreter executes the instructions, each of them can
|
|
|
|
/// query the WebAssembly instance, operates on the stack, or reads
|
|
|
|
/// the invocation inputs. At the end of the execution, the stack
|
|
|
|
/// supposedly contains a result. Since an interpreter is used by a
|
|
|
|
/// WIT adapter to execute its instructions, the result on the stack
|
|
|
|
/// is the result of the adapter.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```rust,ignore
|
|
|
|
/// use std::{cell::Cell, collections::HashMap, convert::TryInto};
|
|
|
|
/// use wasmer_interface_types::interpreter::{
|
|
|
|
/// instructions::tests::{Export, Instance, LocalImport, Memory, MemoryView},
|
|
|
|
/// // ^^^^^^^^^^^^ This is private and for testing purposes only.
|
|
|
|
/// // It is basically a fake WebAssembly runtime.
|
|
|
|
/// stack::Stackable,
|
|
|
|
/// wasm::values::{InterfaceType, InterfaceValue},
|
|
|
|
/// Instruction, Interpreter,
|
|
|
|
/// };
|
|
|
|
///
|
|
|
|
/// // 1. Creates an interpreter from a set of instructions. They will
|
|
|
|
/// // be transformed into executable instructions.
|
|
|
|
/// let interpreter: Interpreter<Instance, Export, LocalImport, Memory, MemoryView> = (&vec![
|
|
|
|
/// Instruction::ArgumentGet { index: 1 },
|
|
|
|
/// Instruction::ArgumentGet { index: 0 },
|
2020-03-09 14:33:17 +01:00
|
|
|
/// Instruction::CallCore { function_index: 42 },
|
2020-02-12 17:37:06 +01:00
|
|
|
/// ])
|
|
|
|
/// .try_into()
|
|
|
|
/// .unwrap();
|
|
|
|
///
|
|
|
|
/// // 2. Defines the arguments of the adapter.
|
|
|
|
/// let invocation_inputs = vec![InterfaceValue::I32(3), InterfaceValue::I32(4)];
|
|
|
|
///
|
|
|
|
/// // 3. Creates a WebAssembly instance.
|
|
|
|
/// let mut instance = Instance {
|
2020-03-09 14:33:17 +01:00
|
|
|
/// // 3.1. Defines one function: `fn sum(a: i32, b: i32) -> i32 { a + b }`.
|
|
|
|
/// locals_or_imports: {
|
2020-02-12 17:37:06 +01:00
|
|
|
/// let mut hashmap = HashMap::new();
|
|
|
|
/// hashmap.insert(
|
2020-03-09 14:33:17 +01:00
|
|
|
/// 42,
|
|
|
|
/// LocalImport {
|
2020-02-12 17:37:06 +01:00
|
|
|
/// // Defines the argument types of the function.
|
|
|
|
/// inputs: vec![InterfaceType::I32, InterfaceType::I32],
|
|
|
|
///
|
|
|
|
/// // Defines the result types.
|
|
|
|
/// outputs: vec![InterfaceType::I32],
|
|
|
|
///
|
|
|
|
/// // Defines the function implementation.
|
|
|
|
/// function: |arguments: &[InterfaceValue]| {
|
|
|
|
/// let a: i32 = (&arguments[0]).try_into().unwrap();
|
|
|
|
/// let b: i32 = (&arguments[1]).try_into().unwrap();
|
|
|
|
///
|
|
|
|
/// Ok(vec![InterfaceValue::I32(a + b)])
|
|
|
|
/// },
|
|
|
|
/// },
|
|
|
|
/// );
|
|
|
|
/// },
|
|
|
|
/// ..Default::default()
|
|
|
|
/// };
|
|
|
|
///
|
|
|
|
/// // 4. Executes the instructions.
|
|
|
|
/// let run = interpreter.run(&invocation_inputs, &mut instance);
|
|
|
|
///
|
|
|
|
/// assert!(run.is_ok());
|
|
|
|
///
|
|
|
|
/// let stack = run.unwrap();
|
|
|
|
///
|
|
|
|
/// // 5. Read the stack to get the result.
|
|
|
|
/// assert_eq!(stack.as_slice(), &[InterfaceValue::I32(7)]);
|
|
|
|
/// ```
|
2019-09-28 00:55:35 +02:00
|
|
|
pub struct Interpreter<Instance, Export, LocalImport, Memory, MemoryView>
|
2019-09-26 14:14:46 +02:00
|
|
|
where
|
|
|
|
Export: wasm::structures::Export,
|
|
|
|
LocalImport: wasm::structures::LocalImport,
|
2019-09-28 00:55:35 +02:00
|
|
|
Memory: wasm::structures::Memory<MemoryView>,
|
|
|
|
MemoryView: wasm::structures::MemoryView,
|
|
|
|
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
2019-09-26 14:14:46 +02:00
|
|
|
{
|
2019-09-28 00:55:35 +02:00
|
|
|
executable_instructions:
|
|
|
|
Vec<ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView>>,
|
2019-09-26 14:14:46 +02:00
|
|
|
}
|
|
|
|
|
2019-09-28 00:55:35 +02:00
|
|
|
impl<Instance, Export, LocalImport, Memory, MemoryView>
|
|
|
|
Interpreter<Instance, Export, LocalImport, Memory, MemoryView>
|
2019-09-26 14:14:46 +02:00
|
|
|
where
|
|
|
|
Export: wasm::structures::Export,
|
|
|
|
LocalImport: wasm::structures::LocalImport,
|
2019-09-28 00:55:35 +02:00
|
|
|
Memory: wasm::structures::Memory<MemoryView>,
|
|
|
|
MemoryView: wasm::structures::MemoryView,
|
|
|
|
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
2019-09-26 14:14:46 +02:00
|
|
|
{
|
|
|
|
fn iter(
|
|
|
|
&self,
|
2019-09-28 00:55:35 +02:00
|
|
|
) -> impl Iterator<
|
|
|
|
Item = &ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView>,
|
|
|
|
> + '_ {
|
2019-09-26 14:14:46 +02:00
|
|
|
self.executable_instructions.iter()
|
|
|
|
}
|
|
|
|
|
2020-02-12 17:37:06 +01:00
|
|
|
/// Runs the interpreter, such as:
|
|
|
|
/// 1. Create a fresh stack,
|
|
|
|
/// 2. Create a fresh stack,
|
|
|
|
/// 3. Execute the instructions one after the other, and
|
|
|
|
/// returns the stack.
|
2019-09-26 14:14:46 +02:00
|
|
|
pub fn run(
|
|
|
|
&self,
|
|
|
|
invocation_inputs: &[InterfaceValue],
|
2019-10-03 00:13:07 +02:00
|
|
|
wasm_instance: &mut Instance,
|
2020-03-10 15:41:49 +01:00
|
|
|
) -> InterpreterResult<Stack<InterfaceValue>> {
|
2019-09-26 14:14:46 +02:00
|
|
|
let mut runtime = Runtime {
|
|
|
|
invocation_inputs,
|
|
|
|
stack: Stack::new(),
|
|
|
|
wasm_instance,
|
2019-09-28 00:55:35 +02:00
|
|
|
_phantom: PhantomData,
|
2019-09-26 14:14:46 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
for executable_instruction in self.iter() {
|
2020-03-12 14:51:18 +01:00
|
|
|
executable_instruction(&mut runtime)?;
|
2019-09-26 14:14:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(runtime.stack)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-12 17:37:06 +01:00
|
|
|
/// Transforms a `Vec<Instruction>` into an `Interpreter`.
|
2020-03-10 10:37:09 +01:00
|
|
|
impl<Instance, Export, LocalImport, Memory, MemoryView> TryFrom<&Vec<Instruction>>
|
2019-09-28 00:55:35 +02:00
|
|
|
for Interpreter<Instance, Export, LocalImport, Memory, MemoryView>
|
2019-09-26 14:14:46 +02:00
|
|
|
where
|
|
|
|
Export: wasm::structures::Export,
|
|
|
|
LocalImport: wasm::structures::LocalImport,
|
2019-09-28 00:55:35 +02:00
|
|
|
Memory: wasm::structures::Memory<MemoryView>,
|
|
|
|
MemoryView: wasm::structures::MemoryView,
|
|
|
|
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
2019-09-26 14:14:46 +02:00
|
|
|
{
|
2020-03-10 15:41:49 +01:00
|
|
|
type Error = ();
|
2019-09-26 14:14:46 +02:00
|
|
|
|
|
|
|
fn try_from(instructions: &Vec<Instruction>) -> Result<Self, Self::Error> {
|
|
|
|
let executable_instructions = instructions
|
|
|
|
.iter()
|
2020-03-24 12:43:57 +01:00
|
|
|
.map(|instruction| match instruction {
|
|
|
|
Instruction::ArgumentGet { index } => {
|
|
|
|
instructions::argument_get(*index, *instruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
Instruction::CallCore { function_index } => {
|
|
|
|
instructions::call_core(*function_index, *instruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
Instruction::S8FromI32 => instructions::s8_from_i32(*instruction),
|
|
|
|
Instruction::S8FromI64 => instructions::s8_from_i64(*instruction),
|
|
|
|
Instruction::S16FromI32 => instructions::s16_from_i32(*instruction),
|
|
|
|
Instruction::S16FromI64 => instructions::s16_from_i64(*instruction),
|
|
|
|
Instruction::S32FromI32 => instructions::s32_from_i32(*instruction),
|
|
|
|
Instruction::S32FromI64 => instructions::s32_from_i64(*instruction),
|
|
|
|
Instruction::S64FromI32 => instructions::s64_from_i32(*instruction),
|
|
|
|
Instruction::S64FromI64 => instructions::s64_from_i64(*instruction),
|
|
|
|
Instruction::I32FromS8 => instructions::i32_from_s8(*instruction),
|
|
|
|
Instruction::I32FromS16 => instructions::i32_from_s16(*instruction),
|
|
|
|
Instruction::I32FromS32 => instructions::i32_from_s32(*instruction),
|
|
|
|
Instruction::I32FromS64 => instructions::i32_from_s64(*instruction),
|
|
|
|
Instruction::I64FromS8 => instructions::i64_from_s8(*instruction),
|
|
|
|
Instruction::I64FromS16 => instructions::i64_from_s16(*instruction),
|
|
|
|
Instruction::I64FromS32 => instructions::i64_from_s32(*instruction),
|
|
|
|
Instruction::I64FromS64 => instructions::i64_from_s64(*instruction),
|
|
|
|
Instruction::U8FromI32 => instructions::u8_from_i32(*instruction),
|
|
|
|
Instruction::U8FromI64 => instructions::u8_from_i64(*instruction),
|
|
|
|
Instruction::U16FromI32 => instructions::u16_from_i32(*instruction),
|
|
|
|
Instruction::U16FromI64 => instructions::u16_from_i64(*instruction),
|
|
|
|
Instruction::U32FromI32 => instructions::u32_from_i32(*instruction),
|
|
|
|
Instruction::U32FromI64 => instructions::u32_from_i64(*instruction),
|
|
|
|
Instruction::U64FromI32 => instructions::u64_from_i32(*instruction),
|
|
|
|
Instruction::U64FromI64 => instructions::u64_from_i64(*instruction),
|
|
|
|
Instruction::I32FromU8 => instructions::i32_from_u8(*instruction),
|
|
|
|
Instruction::I32FromU16 => instructions::i32_from_u16(*instruction),
|
|
|
|
Instruction::I32FromU32 => instructions::i32_from_u32(*instruction),
|
|
|
|
Instruction::I32FromU64 => instructions::i32_from_u64(*instruction),
|
|
|
|
Instruction::I64FromU8 => instructions::i64_from_u8(*instruction),
|
|
|
|
Instruction::I64FromU16 => instructions::i64_from_u16(*instruction),
|
|
|
|
Instruction::I64FromU32 => instructions::i64_from_u32(*instruction),
|
|
|
|
Instruction::I64FromU64 => instructions::i64_from_u64(*instruction),
|
|
|
|
|
|
|
|
Instruction::MemoryToString => instructions::memory_to_string(*instruction),
|
|
|
|
Instruction::StringToMemory { allocator_index } => {
|
|
|
|
instructions::string_to_memory(*allocator_index, *instruction)
|
2019-09-26 14:37:29 +02:00
|
|
|
}
|
|
|
|
})
|
2019-09-26 14:14:46 +02:00
|
|
|
.collect();
|
|
|
|
|
|
|
|
Ok(Interpreter {
|
|
|
|
executable_instructions,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|