From f206ccd55f3d30cf537a9735a7a4953e865b74ef Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Sat, 28 Sep 2019 00:55:35 +0200 Subject: [PATCH] feat(interface-types) Introduce the `wasm::structures::MemoryView` trait. --- src/ast.rs | 2 +- src/interpreter/instructions/mod.rs | 35 ++++++++----- src/interpreter/instructions/read_utf8.rs | 2 +- src/interpreter/instructions/write_utf8.rs | 2 +- src/interpreter/mod.rs | 58 ++++++++++++---------- src/interpreter/wasm/structures.rs | 39 +++++++++++---- src/interpreter/wasm/values.rs | 20 -------- src/macros.rs | 17 ++++--- 8 files changed, 96 insertions(+), 79 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 2bcabfb..1dc9ab9 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1,7 +1,7 @@ use crate::interpreter::Instruction; use std::str; -#[derive(PartialEq, Debug)] +#[derive(PartialEq, Clone, Debug)] pub enum InterfaceType { Int, Float, diff --git a/src/interpreter/instructions/mod.rs b/src/interpreter/instructions/mod.rs index 05c3f97..e38dcf3 100644 --- a/src/interpreter/instructions/mod.rs +++ b/src/interpreter/instructions/mod.rs @@ -14,9 +14,9 @@ pub(crate) use write_utf8::write_utf8; pub(crate) mod tests { use crate::interpreter::wasm::{ self, - values::{InterfaceType, InterfaceValue, ValueType}, + values::{InterfaceType, InterfaceValue}, }; - use std::{cell::Cell, collections::HashMap, convert::TryInto}; + use std::{cell::Cell, collections::HashMap, convert::TryInto, ops::Deref, rc::Rc}; pub(crate) struct Export { pub(crate) inputs: Vec, @@ -74,24 +74,35 @@ pub(crate) mod tests { } } + #[derive(Default, Clone)] + pub(crate) struct MemoryView(Rc>>); + + impl wasm::structures::MemoryView for MemoryView {} + + impl Deref for MemoryView { + type Target = [Cell]; + + fn deref(&self) -> &[Cell] { + self.0.as_slice() + } + } + #[derive(Default)] pub(crate) struct Memory { - pub(crate) data: Vec>, + pub(crate) view: MemoryView, } impl Memory { pub(crate) fn new(data: Vec>) -> Self { - Self { data } + Self { + view: MemoryView(Rc::new(data)), + } } } - impl wasm::structures::Memory for Memory { - fn view(&self) -> &[Cell] { - use std::slice; - - let slice = self.data.as_slice(); - - unsafe { slice::from_raw_parts(slice.as_ptr() as *const Cell, slice.len()) } + impl wasm::structures::Memory for Memory { + fn view(&self) -> MemoryView { + self.view.clone() } } @@ -158,7 +169,7 @@ pub(crate) mod tests { } } - impl wasm::structures::Instance for Instance { + impl wasm::structures::Instance for Instance { fn export(&self, export_name: &str) -> Option<&Export> { self.exports.get(export_name) } diff --git a/src/interpreter/instructions/read_utf8.rs b/src/interpreter/instructions/read_utf8.rs index 55fe350..a06bc56 100644 --- a/src/interpreter/instructions/read_utf8.rs +++ b/src/interpreter/instructions/read_utf8.rs @@ -9,7 +9,7 @@ executable_instruction!( Some(memory) => { let length = i32::try_from(&inputs[0])? as usize; let pointer = i32::try_from(&inputs[1])? as usize; - let memory_view = memory.view::(); + let memory_view = memory.view(); if memory_view.len() < pointer + length { return Err(format!( diff --git a/src/interpreter/instructions/write_utf8.rs b/src/interpreter/instructions/write_utf8.rs index 34e148f..b0738f3 100644 --- a/src/interpreter/instructions/write_utf8.rs +++ b/src/interpreter/instructions/write_utf8.rs @@ -20,7 +20,7 @@ executable_instruction!( match runtime.wasm_instance.memory(0) { Some(memory) => match runtime.stack.pop1() { Some(string) => { - let memory_view = memory.view::(); + let memory_view = memory.view(); let string: String = (&string).try_into()?; let string_bytes = string.as_bytes(); diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index a6c11f2..1b133a7 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -8,45 +8,50 @@ use stack::Stack; use std::{convert::TryFrom, marker::PhantomData}; use wasm::values::InterfaceValue; -pub(crate) struct Runtime<'invocation, 'instance, Instance, Export, LocalImport, Memory> +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 + 'instance, - Instance: wasm::structures::Instance + 'instance, + Memory: wasm::structures::Memory + 'instance, + MemoryView: wasm::structures::MemoryView, + Instance: wasm::structures::Instance + 'instance, { invocation_inputs: &'invocation [InterfaceValue], stack: Stack, wasm_instance: &'instance Instance, - _wasm_exports: PhantomData, - _wasm_locals_or_imports: PhantomData, - _wasm_memories: PhantomData, + _phantom: PhantomData<(Export, LocalImport, Memory, MemoryView)>, } -pub(crate) type ExecutableInstruction = - Box) -> Result<(), String>>; +pub(crate) type ExecutableInstruction = Box< + dyn Fn(&mut Runtime) -> Result<(), String>, +>; -pub struct Interpreter +pub struct Interpreter where Export: wasm::structures::Export, LocalImport: wasm::structures::LocalImport, - Memory: wasm::structures::Memory, - Instance: wasm::structures::Instance, + Memory: wasm::structures::Memory, + MemoryView: wasm::structures::MemoryView, + Instance: wasm::structures::Instance, { - executable_instructions: Vec>, + executable_instructions: + Vec>, } -impl Interpreter +impl + Interpreter where Export: wasm::structures::Export, LocalImport: wasm::structures::LocalImport, - Memory: wasm::structures::Memory, - Instance: wasm::structures::Instance, + Memory: wasm::structures::Memory, + MemoryView: wasm::structures::MemoryView, + Instance: wasm::structures::Instance, { fn iter( &self, - ) -> impl Iterator> + '_ - { + ) -> impl Iterator< + Item = &ExecutableInstruction, + > + '_ { self.executable_instructions.iter() } @@ -59,9 +64,7 @@ where invocation_inputs, stack: Stack::new(), wasm_instance, - _wasm_exports: PhantomData, - _wasm_locals_or_imports: PhantomData, - _wasm_memories: PhantomData, + _phantom: PhantomData, }; for executable_instruction in self.iter() { @@ -75,13 +78,15 @@ where } } -impl<'binary_input, Instance, Export, LocalImport, Memory> TryFrom<&Vec>> - for Interpreter +impl<'binary_input, Instance, Export, LocalImport, Memory, MemoryView> + TryFrom<&Vec>> + for Interpreter where Export: wasm::structures::Export, LocalImport: wasm::structures::LocalImport, - Memory: wasm::structures::Memory, - Instance: wasm::structures::Instance, + Memory: wasm::structures::Memory, + MemoryView: wasm::structures::MemoryView, + Instance: wasm::structures::Instance, { type Error = String; @@ -118,7 +123,7 @@ where #[cfg(test)] mod tests { - use super::{Instruction, Interpreter}; + use super::{wasm::structures::EmptyMemoryView, Instruction, Interpreter}; use std::convert::TryInto; #[test] @@ -130,7 +135,8 @@ mod tests { Instruction::ReadUtf8, Instruction::Call { function_index: 7 }, ]; - let interpreter: Interpreter<(), (), (), ()> = (&instructions).try_into().unwrap(); + let interpreter: Interpreter<(), (), (), (), EmptyMemoryView> = + (&instructions).try_into().unwrap(); assert_eq!(interpreter.executable_instructions.len(), 5); } diff --git a/src/interpreter/wasm/structures.rs b/src/interpreter/wasm/structures.rs index d1fa583..eb0a511 100644 --- a/src/interpreter/wasm/structures.rs +++ b/src/interpreter/wasm/structures.rs @@ -1,5 +1,5 @@ -use super::values::{InterfaceType, InterfaceValue, ValueType}; -use std::cell::Cell; +use super::values::{InterfaceType, InterfaceValue}; +use std::{cell::Cell, ops::Deref}; pub trait TypedIndex: Copy + Clone { fn new(index: usize) -> Self; @@ -53,15 +53,21 @@ pub trait LocalImport { fn call(&self, arguments: &[InterfaceValue]) -> Result, ()>; } -pub trait Memory { - fn view(&self) -> &[Cell]; +pub trait MemoryView: Deref]> {} + +pub trait Memory +where + View: MemoryView, +{ + fn view(&self) -> View; } -pub trait Instance +pub trait Instance where E: Export, LI: LocalImport, - M: Memory, + M: Memory, + MV: MemoryView, { fn export(&self, export_name: &str) -> Option<&E>; fn local_or_import(&self, index: I) -> Option<&LI>; @@ -112,17 +118,30 @@ impl LocalImport for () { } } -impl Memory for () { - fn view(&self) -> &[Cell] { +pub(crate) struct EmptyMemoryView; + +impl MemoryView for EmptyMemoryView {} + +impl Deref for EmptyMemoryView { + type Target = [Cell]; + + fn deref(&self) -> &[Cell] { &[] } } -impl Instance for () +impl Memory for () { + fn view(&self) -> EmptyMemoryView { + EmptyMemoryView + } +} + +impl Instance for () where E: Export, LI: LocalImport, - M: Memory, + M: Memory, + MV: MemoryView, { fn export(&self, _export_name: &str) -> Option<&E> { None diff --git a/src/interpreter/wasm/values.rs b/src/interpreter/wasm/values.rs index 1cfac91..632a88f 100644 --- a/src/interpreter/wasm/values.rs +++ b/src/interpreter/wasm/values.rs @@ -63,23 +63,3 @@ from_x_for_interface_value!(i32, I32); from_x_for_interface_value!(i64, I64); from_x_for_interface_value!(f32, F32); from_x_for_interface_value!(f64, F64); - -pub trait ValueType: Copy -where - Self: Sized, -{ -} - -macro_rules! value_type { - ($native_type:ty) => { - impl ValueType for $native_type {} - }; - - ($($native_type:ty),*) => { - $( - value_type!($native_type); - )* - }; -} - -value_type!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64); diff --git a/src/macros.rs b/src/macros.rs index 2d2e146..aee8178 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -28,14 +28,15 @@ macro_rules! executable_instruction { ($name:ident ( $($argument_name:ident: $argument_type:ty),* ) -> _ $implementation:block ) => { use crate::interpreter::{ExecutableInstruction, wasm, stack::Stackable}; - pub(crate) fn $name( + pub(crate) fn $name( $($argument_name: $argument_type),* - ) -> ExecutableInstruction + ) -> ExecutableInstruction where Export: wasm::structures::Export, LocalImport: wasm::structures::LocalImport, - Memory: wasm::structures::Memory, - Instance: wasm::structures::Instance, + Memory: wasm::structures::Memory, + MemoryView: wasm::structures::MemoryView, + Instance: wasm::structures::Instance, { Box::new($implementation) } @@ -56,14 +57,14 @@ macro_rules! test_executable_instruction { #[allow(non_snake_case, unused)] fn $test_name() { use crate::interpreter::{ - instructions::tests::{Export, Instance, LocalImport, Memory}, + instructions::tests::{Export, Instance, LocalImport, Memory, MemoryView}, stack::Stackable, wasm::values::{InterfaceType, InterfaceValue}, Instruction, Interpreter, }; use std::{cell::Cell, collections::HashMap, convert::TryInto}; - let interpreter: Interpreter = + let interpreter: Interpreter = (&vec![$($instructions),*]).try_into().unwrap(); let invocation_inputs = vec![$($invocation_inputs),*]; @@ -90,14 +91,14 @@ macro_rules! test_executable_instruction { #[allow(non_snake_case, unused)] fn $test_name() { use crate::interpreter::{ - instructions::tests::{Export, Instance, LocalImport, Memory}, + instructions::tests::{Export, Instance, LocalImport, Memory, MemoryView}, stack::Stackable, wasm::values::{InterfaceType, InterfaceValue}, Instruction, Interpreter, }; use std::{cell::Cell, collections::HashMap, convert::TryInto}; - let interpreter: Interpreter = + let interpreter: Interpreter = (&vec![$($instructions),*]).try_into().unwrap(); let invocation_inputs = vec![$($invocation_inputs),*];