mod instruction;
mod instructions;
pub mod stack;
pub mod wasm;
pub use instruction::Instruction;
use stack::Stack;
use std::{convert::TryFrom, marker::PhantomData};
use wasm::values::InterfaceValue;
pub(crate) struct Runtime<'invocation, 'instance, Instance, Export, LocalImport, Memory, MemoryView>
where
Export: wasm::structures::Export + 'instance,
LocalImport: wasm::structures::LocalImport + 'instance,
Memory: wasm::structures::Memory<MemoryView> + 'instance,
MemoryView: wasm::structures::MemoryView,
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView> + 'instance,
{
invocation_inputs: &'invocation [InterfaceValue],
stack: Stack<InterfaceValue>,
wasm_instance: &'instance mut Instance,
_phantom: PhantomData<(Export, LocalImport, Memory, MemoryView)>,
}
pub(crate) type ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView> = Box<
dyn Fn(&mut Runtime<Instance, Export, LocalImport, Memory, MemoryView>) -> Result<(), String>,
>;
pub struct Interpreter<Instance, Export, LocalImport, Memory, MemoryView>
where
Export: wasm::structures::Export,
LocalImport: wasm::structures::LocalImport,
Memory: wasm::structures::Memory<MemoryView>,
MemoryView: wasm::structures::MemoryView,
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
{
executable_instructions:
Vec<ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView>>,
}
impl<Instance, Export, LocalImport, Memory, MemoryView>
Interpreter<Instance, Export, LocalImport, Memory, MemoryView>
where
Export: wasm::structures::Export,
LocalImport: wasm::structures::LocalImport,
Memory: wasm::structures::Memory<MemoryView>,
MemoryView: wasm::structures::MemoryView,
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
{
fn iter(
&self,
) -> impl Iterator<
Item = &ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView>,
> + '_ {
self.executable_instructions.iter()
}
pub fn run(
&self,
invocation_inputs: &[InterfaceValue],
wasm_instance: &mut Instance,
) -> Result<Stack<InterfaceValue>, String> {
let mut runtime = Runtime {
invocation_inputs,
stack: Stack::new(),
wasm_instance,
_phantom: PhantomData,
};
for executable_instruction in self.iter() {
match executable_instruction(&mut runtime) {
Ok(_) => continue,
Err(message) => return Err(message),
}
}
Ok(runtime.stack)
}
}
impl<Instance, Export, LocalImport, Memory, MemoryView> TryFrom<&Vec<Instruction>>
for Interpreter<Instance, Export, LocalImport, Memory, MemoryView>
where
Export: wasm::structures::Export,
LocalImport: wasm::structures::LocalImport,
Memory: wasm::structures::Memory<MemoryView>,
MemoryView: wasm::structures::MemoryView,
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
{
type Error = String;
fn try_from(instructions: &Vec<Instruction>) -> Result<Self, Self::Error> {
let executable_instructions = instructions
.iter()
.map(|instruction| {
let instruction_name = instruction.to_string();
match instruction {
Instruction::ArgumentGet { index } => {
instructions::argument_get(*index, instruction_name)
}
Instruction::CallCore { function_index } => {
instructions::call_core(*function_index, instruction_name)
}
Instruction::MemoryToString => instructions::memory_to_string(instruction_name),
Instruction::StringToMemory { allocator_index } => {
instructions::string_to_memory(*allocator_index, instruction_name)
}
Instruction::I32ToS8 => instructions::i32_to_s8(),
Instruction::I32ToU8 => instructions::i32_to_u8(),
Instruction::I32ToS16 => instructions::i32_to_s16(),
Instruction::I32ToU16 => instructions::i32_to_u16(),
Instruction::I32ToS32 => instructions::i32_to_s32(),
Instruction::I32ToU32 => instructions::i32_to_u32(),
Instruction::I32ToS64 => instructions::i32_to_s64(),
Instruction::I32ToU64 => instructions::i32_to_u64(),
Instruction::I64ToS8 => instructions::i64_to_s8(),
Instruction::I64ToU8 => instructions::i64_to_u8(),
Instruction::I64ToS16 => instructions::i64_to_s16(),
Instruction::I64ToU16 => instructions::i64_to_u16(),
Instruction::I64ToS32 => instructions::i64_to_s32(),
Instruction::I64ToU32 => instructions::i64_to_u32(),
Instruction::I64ToS64 => instructions::i64_to_s64(),
Instruction::I64ToU64 => instructions::i64_to_u64(),
Instruction::S8ToI32 => instructions::s8_to_i32(),
Instruction::U8ToI32 => instructions::u8_to_i32(),
Instruction::S16ToI32 => instructions::s16_to_i32(),
Instruction::U16ToI32 => instructions::u16_to_i32(),
Instruction::S32ToI32 => instructions::s32_to_i32(),
Instruction::U32ToI32 => instructions::u32_to_i32(),
Instruction::S64ToI32 | Instruction::S64ToI32X => instructions::s64_to_i32(),
Instruction::U64ToI32 | Instruction::U64ToI32X => instructions::u64_to_i32(),
Instruction::S8ToI64 => instructions::s8_to_i64(),
Instruction::U8ToI64 => instructions::u8_to_i64(),
Instruction::S16ToI64 => instructions::s16_to_i64(),
Instruction::U16ToI64 => instructions::u16_to_i64(),
Instruction::S32ToI64 => instructions::s32_to_i64(),
Instruction::U32ToI64 => instructions::u32_to_i64(),
Instruction::S64ToI64 => instructions::s64_to_i64(),
Instruction::U64ToI64 => instructions::u64_to_i64(),
_ => unimplemented!(),
}
})
.collect();
Ok(Interpreter {
executable_instructions,
})
}
}