mod argument_get;
mod byte_arrays;
mod call_core;
mod dup;
mod numbers;
mod records;
mod strings;
mod swap2;
use crate::{
errors::{InstructionError, InstructionErrorKind, InstructionResult, WasmValueNativeCastError},
values::{InterfaceValue, NativeType},
};
pub(crate) use argument_get::argument_get;
pub(crate) use byte_arrays::*;
pub(crate) use call_core::call_core;
pub(crate) use dup::dup;
pub(crate) use numbers::*;
pub(crate) use records::*;
use std::convert::TryFrom;
pub(crate) use strings::*;
pub(crate) use swap2::swap2;
pub(self) const ALLOCATE_FUNC_INDEX: u32 = 0;
pub(self) const DEALLOCATE_FUNC_INDEX: u32 = 1;
#[derive(PartialEq, Debug, Clone, Copy)]
pub enum Instruction {
ArgumentGet {
index: u32,
},
CallCore {
function_index: u32,
},
S8FromI32,
S8FromI64,
S16FromI32,
S16FromI64,
S32FromI32,
S32FromI64,
S64FromI32,
S64FromI64,
I32FromS8,
I32FromS16,
I32FromS32,
I32FromS64,
I64FromS8,
I64FromS16,
I64FromS32,
I64FromS64,
U8FromI32,
U8FromI64,
U16FromI32,
U16FromI64,
U32FromI32,
U32FromI64,
U64FromI32,
U64FromI64,
I32FromU8,
I32FromU16,
I32FromU32,
I32FromU64,
I64FromU8,
I64FromU16,
I64FromU32,
I64FromU64,
StringLiftMemory,
StringLowerMemory,
StringSize,
ByteArrayLiftMemory,
ByteArrayLowerMemory,
ByteArraySize,
RecordLift {
type_index: u32,
},
RecordLower {
type_index: u32,
},
RecordLiftMemory {
type_index: u32,
},
RecordLowerMemory {
type_index: u32,
},
Dup,
Swap2,
}
pub(crate) fn to_native<'a, T>(
wit_value: &'a InterfaceValue,
instruction: Instruction,
) -> InstructionResult<T>
where
T: NativeType + TryFrom<&'a InterfaceValue, Error = WasmValueNativeCastError>,
{
T::try_from(wit_value)
.map_err(|error| InstructionError::new(instruction, InstructionErrorKind::ToNative(error)))
}
#[cfg(test)]
pub(crate) mod tests {
use crate::{ast::*, interpreter::wasm, types::*, values::*};
use std::{cell::Cell, collections::HashMap, convert::TryInto, ops::Deref, rc::Rc};
pub(crate) struct Export {
pub(crate) inputs: Vec<InterfaceType>,
pub(crate) outputs: Vec<InterfaceType>,
pub(crate) function: fn(arguments: &[InterfaceValue]) -> Result<Vec<InterfaceValue>, ()>,
}
impl wasm::structures::Export for Export {
fn inputs_cardinality(&self) -> usize {
self.inputs.len() as usize
}
fn outputs_cardinality(&self) -> usize {
self.outputs.len()
}
fn inputs(&self) -> &[InterfaceType] {
&self.inputs
}
fn outputs(&self) -> &[InterfaceType] {
&self.outputs
}
fn call(&self, arguments: &[InterfaceValue]) -> Result<Vec<InterfaceValue>, ()> {
(self.function)(arguments)
}
}
pub(crate) struct LocalImport {
pub(crate) inputs: Vec<InterfaceType>,
pub(crate) outputs: Vec<InterfaceType>,
pub(crate) function: fn(arguments: &[InterfaceValue]) -> Result<Vec<InterfaceValue>, ()>,
}
impl wasm::structures::LocalImport for LocalImport {
fn inputs_cardinality(&self) -> usize {
self.inputs.len()
}
fn outputs_cardinality(&self) -> usize {
self.outputs.len()
}
fn inputs(&self) -> &[InterfaceType] {
&self.inputs
}
fn outputs(&self) -> &[InterfaceType] {
&self.outputs
}
fn call(&self, arguments: &[InterfaceValue]) -> Result<Vec<InterfaceValue>, ()> {
(self.function)(arguments)
}
}
#[derive(Default, Clone)]
pub(crate) struct MemoryView(Rc<Vec<Cell<u8>>>);
impl wasm::structures::MemoryView for MemoryView {}
impl Deref for MemoryView {
type Target = [Cell<u8>];
fn deref(&self) -> &Self::Target {
self.0.as_slice()
}
}
#[derive(Default)]
pub(crate) struct Memory {
pub(crate) view: MemoryView,
}
impl Memory {
pub(crate) fn new(data: Vec<Cell<u8>>) -> Self {
Self {
view: MemoryView(Rc::new(data)),
}
}
}
impl wasm::structures::Memory<MemoryView> for Memory {
fn view(&self) -> MemoryView {
self.view.clone()
}
}
#[derive(Default)]
pub(crate) struct Instance {
pub(crate) exports: HashMap<String, Export>,
pub(crate) locals_or_imports: HashMap<usize, LocalImport>,
pub(crate) memory: Memory,
pub(crate) wit_types: Vec<Type>,
}
impl Instance {
pub(crate) fn new() -> Self {
Self {
exports: {
let mut hashmap = HashMap::new();
hashmap.insert(
"sum".into(),
Export {
inputs: vec![InterfaceType::I32, InterfaceType::I32],
outputs: vec![InterfaceType::I32],
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)])
},
},
);
hashmap
},
locals_or_imports: {
let mut hashmap = HashMap::new();
hashmap.insert(
42,
LocalImport {
inputs: vec![InterfaceType::I32, InterfaceType::I32],
outputs: vec![InterfaceType::I32],
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)])
},
},
);
hashmap.insert(
43,
LocalImport {
inputs: vec![InterfaceType::I32],
outputs: vec![InterfaceType::I32],
function: |arguments: &[InterfaceValue]| {
let _size: i32 = (&arguments[0]).try_into().unwrap();
Ok(vec![InterfaceValue::I32(0)])
},
},
);
hashmap
},
memory: Memory::new(vec![Cell::new(0); 128]),
wit_types: vec![Type::Record(RecordType {
fields: vec1![
InterfaceType::I32,
InterfaceType::Record(RecordType {
fields: vec1![InterfaceType::String, InterfaceType::F32],
}),
InterfaceType::I64,
],
})],
}
}
}
impl wasm::structures::Instance<Export, LocalImport, Memory, MemoryView> for Instance {
fn export(&self, export_name: &str) -> Option<&Export> {
self.exports.get(export_name)
}
fn local_or_import<I: wasm::structures::TypedIndex + wasm::structures::LocalImportIndex>(
&mut self,
index: I,
) -> Option<&LocalImport> {
self.locals_or_imports.get(&index.index())
}
fn memory(&self, _index: usize) -> Option<&Memory> {
Some(&self.memory)
}
fn wit_type(&self, index: u32) -> Option<&Type> {
self.wit_types.get(index as usize)
}
}
}