diff --git a/examples/interpret.rs b/examples/interpret.rs index 0e4a400..ae11d2b 100644 --- a/examples/interpret.rs +++ b/examples/interpret.rs @@ -3,7 +3,7 @@ extern crate parity_wasm; use std::env::args; -use parity_wasm::interpreter::{ModuleInstance, HostState}; +use parity_wasm::interpreter::{ModuleInstance, EmptyExternals}; fn main() { let args: Vec<_> = args().collect(); @@ -23,12 +23,12 @@ fn main() { // - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here // This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197 let main = ModuleInstance::new(&module) - .run_start(&mut HostState::default()) + .run_start(&mut EmptyExternals) .expect("Failed to initialize module"); // The argument should be parsable as a valid integer let argument: i32 = args[2].parse().expect("Integer argument required"); // "_call" export of function to be executed with an i32 argument and prints the result of execution - println!("Result: {:?}", main.invoke_export("_call", &[parity_wasm::RuntimeValue::I32(argument)], &mut HostState::default())); + println!("Result: {:?}", main.invoke_export("_call", &[parity_wasm::RuntimeValue::I32(argument)], &mut EmptyExternals)); } diff --git a/examples/invoke.rs b/examples/invoke.rs index 65a84bf..50326eb 100644 --- a/examples/invoke.rs +++ b/examples/invoke.rs @@ -4,7 +4,7 @@ use std::env::args; use parity_wasm::RuntimeValue; use parity_wasm::elements::{Internal, External, Type, FunctionType, ValueType}; -use parity_wasm::interpreter::{ModuleInstance, HostState}; +use parity_wasm::interpreter::{ModuleInstance, EmptyExternals}; fn main() { @@ -75,8 +75,8 @@ fn main() { // - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here // This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197 let main = ModuleInstance::new(&module) - .run_start(&mut HostState::default()) + .run_start(&mut EmptyExternals) .expect("Failed to initialize module"); - println!("Result: {:?}", main.invoke_export(func_name, &args, &mut HostState::default()).expect("")); + println!("Result: {:?}", main.invoke_export(func_name, &args, &mut EmptyExternals).expect("")); } diff --git a/examples/tictactoe.rs b/examples/tictactoe.rs index cda18e3..b0de699 100644 --- a/examples/tictactoe.rs +++ b/examples/tictactoe.rs @@ -3,10 +3,11 @@ extern crate parity_wasm; use std::env; use std::fmt; use std::rc::Rc; -use parity_wasm::elements::Module; +use parity_wasm::elements::{Module, FunctionType, ValueType, TableType, GlobalType, MemoryType}; use parity_wasm::interpreter::{ - Error as InterpreterError, HostModule, HostModuleBuilder, - ModuleInstance, UserError, HostState, StateKey + Error as InterpreterError, ModuleInstance, UserError, + HostFuncIndex, Externals, RuntimeValue, GlobalInstance, TableInstance, MemoryInstance, + TableRef, MemoryRef, GlobalRef, FuncRef, TryInto, ImportResolver, FuncInstance, }; #[derive(Debug)] @@ -139,54 +140,123 @@ struct Runtime<'a> { game: &'a mut tictactoe::Game, } -unsafe impl<'a> StateKey for Runtime<'a> { - type Static = Runtime<'static>; +const SET_FUNC_INDEX: HostFuncIndex = 0; +const GET_FUNC_INDEX: HostFuncIndex = 1; + +impl<'a> Externals for Runtime<'a> { + fn invoke_index( + &mut self, + index: HostFuncIndex, + args: &[RuntimeValue], + ) -> Result, InterpreterError> { + match index { + SET_FUNC_INDEX => { + let idx: i32 = args[0].try_into().unwrap(); + self.game.set(idx, self.player)?; + Ok(None) + } + GET_FUNC_INDEX => { + let idx: i32 = args[0].try_into().unwrap(); + let val: i32 = tictactoe::Player::into_i32(self.game.get(idx)?); + Ok(Some(val.into())) + } + _ => panic!("unknown function index") + } + } + + fn check_signature(&self, index: HostFuncIndex, sig: &FunctionType) -> bool { + match index { + SET_FUNC_INDEX => { + sig.params() == &[ValueType::I32] && sig.return_type() == None + } + GET_FUNC_INDEX => { + sig.params() == &[ValueType::I32] && sig.return_type() == Some(ValueType::I32) + } + _ => panic!("unknown function index") + } + } + + fn memory_by_index(&self, _index: usize) -> &MemoryInstance { + panic!("host module doesn't export any memories") + } + + fn table_by_index(&self, _index: usize) -> &TableInstance { + panic!("host module doesn't export any tables") + } + + fn global_by_index(&self, _index: usize) -> &GlobalInstance { + panic!("host module doesn't export any globals") + } +} + +struct RuntimeImportResolver; + +impl<'a> ImportResolver for RuntimeImportResolver { + fn resolve_func( + &self, + field_name: &str, + _func_type: &FunctionType, + ) -> Result { + let func_ref = match field_name { + "set" => { + FuncInstance::alloc_host(FunctionType::new(vec![ValueType::I32], None), SET_FUNC_INDEX) + }, + "get" => FuncInstance::alloc_host(FunctionType::new(vec![ValueType::I32], Some(ValueType::I32)), GET_FUNC_INDEX), + _ => return Err( + InterpreterError::Function( + format!("host module doesn't export function with name {}", field_name) + ) + ) + }; + Ok(func_ref) + } + + fn resolve_global( + &self, + _field_name: &str, + _global_type: &GlobalType, + ) -> Result { + Err( + InterpreterError::Global("host module doesn't export any globals".to_owned()) + ) + } + + fn resolve_memory( + &self, + _field_name: &str, + _memory_type: &MemoryType, + ) -> Result { + Err( + InterpreterError::Global("host module doesn't export any memories".to_owned()) + ) + } + + fn resolve_table( + &self, + _field_name: &str, + _table_type: &TableType, + ) -> Result { + Err( + InterpreterError::Global("host module doesn't export any tables".to_owned()) + ) + } } fn instantiate( module: &Module, - env: &HostModule, ) -> Result, Error> { let instance = ModuleInstance::new(module) - .with_import("env", &*env) - .run_start(&mut HostState::default())?; + .with_import("env", &RuntimeImportResolver) + .assert_no_start()?; Ok(instance) } -fn env_host_module() -> HostModule { - HostModuleBuilder::new() - .with_func1( - "set", - |state: &mut HostState, idx: i32| -> Result<(), InterpreterError> { - state.with_mut(move |runtime: &mut Runtime| -> Result<(), InterpreterError> { - runtime.game.set(idx, runtime.player)?; - Ok(()) - }) - }, - ) - .with_func1( - "get", - |state: &mut HostState, idx: i32| -> Result { - state.with(move |runtime: &Runtime| -> Result { - let val: i32 = tictactoe::Player::into_i32(runtime.game.get(idx)?); - Ok(val) - }) - }, - ) - .build() -} - -fn play<'a>( - x_module: &Module, - o_module: &Module, - host_module: &HostModule, - game: &'a mut tictactoe::Game, +fn play( + x_instance: Rc, + o_instance: Rc, + game: &mut tictactoe::Game, ) -> Result { - // Instantiate modules of X and O players. - let x_instance = instantiate(x_module, host_module)?; - let o_instance = instantiate(o_module, host_module)?; - let mut turn_of = tictactoe::Player::X; let game_result = loop { let (instance, next_turn_of) = match turn_of { @@ -199,11 +269,7 @@ fn play<'a>( player: turn_of, game: game, }; - { - let mut host_state = HostState::new(); - host_state.insert::(&mut runtime); - let _ = instance.invoke_export("mk_turn", &[], &mut host_state)?; - } + let _ = instance.invoke_export("mk_turn", &[], &mut runtime)?; } match game.game_result() { @@ -219,7 +285,6 @@ fn play<'a>( fn main() { let mut game = tictactoe::Game::new(); - let env_host_module = env_host_module(); let args: Vec<_> = env::args().collect(); if args.len() < 3 { @@ -229,6 +294,10 @@ fn main() { let x_module = parity_wasm::deserialize_file(&args[1]).expect("X player module to load"); let o_module = parity_wasm::deserialize_file(&args[2]).expect("Y player module to load"); - let result = play(&x_module, &o_module, &env_host_module, &mut game); + // Instantiate modules of X and O players. + let x_instance = instantiate(&x_module).unwrap(); + let o_instance = instantiate(&o_module).unwrap(); + + let result = play(x_instance, o_instance, &mut game); println!("result = {:?}, game = {:#?}", result, game); } diff --git a/src/interpreter/func.rs b/src/interpreter/func.rs index 6abe716..8d4e3ec 100644 --- a/src/interpreter/func.rs +++ b/src/interpreter/func.rs @@ -4,10 +4,9 @@ use std::collections::HashMap; use std::borrow::Cow; use elements::{FunctionType, Local, Opcodes}; use interpreter::{Error, ModuleInstance}; +use interpreter::host::{Externals, HostFuncIndex}; use interpreter::runner::{prepare_function_args, FunctionContext, Interpreter}; -use interpreter::host::HostFunc; use interpreter::value::RuntimeValue; -use interpreter::state::HostState; use common::stack::StackWithLimit; use common::{DEFAULT_FRAME_STACK_LIMIT, DEFAULT_VALUE_STACK_LIMIT}; @@ -29,8 +28,8 @@ pub enum FuncInstance { body: Rc, }, Host { - func_type: Rc, - host_func: Rc, + func_type: FunctionType, + host_func: HostFuncIndex, }, } @@ -57,7 +56,7 @@ impl fmt::Debug for FuncInstance { } impl FuncInstance { - pub fn alloc_internal( + pub(crate) fn alloc_internal( module: Rc, func_type: Rc, body: FuncBody, @@ -70,7 +69,7 @@ impl FuncInstance { FuncRef(Rc::new(func)) } - pub fn alloc_host(func_type: Rc, host_func: Rc) -> FuncRef { + pub fn alloc_host(func_type: FunctionType, host_func: HostFuncIndex) -> FuncRef { let func = FuncInstance::Host { func_type, host_func, @@ -78,10 +77,10 @@ impl FuncInstance { FuncRef(Rc::new(func)) } - pub fn func_type(&self) -> Rc { + pub fn func_type(&self) -> &FunctionType { match *self { - FuncInstance::Internal { ref func_type, .. } | - FuncInstance::Host { ref func_type, .. } => Rc::clone(func_type), + FuncInstance::Internal { ref func_type, .. } => func_type, + FuncInstance::Host { ref func_type, .. } => func_type, } } @@ -92,14 +91,14 @@ impl FuncInstance { } } - pub fn invoke<'a, 'b: 'a>( + pub fn invoke( func: FuncRef, args: Cow<[RuntimeValue]>, - state: &'a mut HostState<'b>, + externals: &mut E, ) -> Result, Error> { enum InvokeKind<'a> { Internal(FunctionContext), - Host(Rc, &'a [RuntimeValue]), + Host(HostFuncIndex, &'a [RuntimeValue]), } let result = match *func { @@ -117,16 +116,16 @@ impl FuncInstance { InvokeKind::Internal(context) } FuncInstance::Host { ref host_func, .. } => { - InvokeKind::Host(Rc::clone(host_func), &*args) + InvokeKind::Host(*host_func, &*args) } }; match result { InvokeKind::Internal(ctx) => { - let mut interpreter = Interpreter::new(state); + let mut interpreter = Interpreter::new(externals); interpreter.run_function(ctx) } - InvokeKind::Host(host_func, args) => host_func(state, args), + InvokeKind::Host(host_func, args) => externals.invoke_index(host_func, args), } } } diff --git a/src/interpreter/host.rs b/src/interpreter/host.rs index 46d0205..20b8c55 100644 --- a/src/interpreter/host.rs +++ b/src/interpreter/host.rs @@ -1,405 +1,50 @@ -use std::rc::Rc; -use std::collections::HashMap; -use std::collections::hash_map::Entry; -use elements::{FunctionType, GlobalType, MemoryType, TableType, ValueType}; -use interpreter::module::{ExternVal, ModuleInstance}; -use interpreter::func::FuncRef; -use interpreter::global::GlobalRef; -use interpreter::memory::MemoryRef; -use interpreter::table::TableRef; -use interpreter::func::FuncInstance; +use elements::FunctionType; use interpreter::global::GlobalInstance; use interpreter::memory::MemoryInstance; use interpreter::table::TableInstance; -use interpreter::value::{RuntimeValue, TryInto}; +use interpreter::value::RuntimeValue; use interpreter::Error; -use interpreter::ImportResolver; -use interpreter::state::HostState; -pub type HostFunc = Fn(&mut HostState, &[RuntimeValue]) - -> Result, Error>; +pub type HostFuncIndex = u32; -pub struct HostModuleBuilder { - exports: HashMap, -} - -impl HostModuleBuilder { - pub fn new() -> Self { - HostModuleBuilder { - exports: HashMap::new(), - } - } - - pub fn insert_func0< - Cl: Fn(&mut HostState) -> Result + 'static, - Ret: IntoReturnVal + 'static, - N: Into, - >( - &mut self, - name: N, - f: Cl, - ) { - let func_type = FunctionType::new(vec![], Ret::value_type()); - let host_func = Rc::new( - move |state: &mut HostState, args: &[RuntimeValue]| -> Result, Error> { - assert!(args.len() == 0); - let result = f(state)?.into_return_val(); - Ok(result) - }, - ); - - let func = FuncInstance::alloc_host(Rc::new(func_type), host_func); - self.insert_func(name, func); - } - - pub fn insert_func1< - Cl: Fn(&mut HostState, P1) -> Result + 'static, - Ret: IntoReturnVal + 'static, - P1: FromArg + 'static, - N: Into, - >( - &mut self, - name: N, - f: Cl, - ) { - let func_type = FunctionType::new(vec![P1::value_type()], Ret::value_type()); - let host_func = Rc::new( - move |state: &mut HostState, args: &[RuntimeValue]| -> Result, Error> { - assert!(args.len() == 1); - let mut args = args.into_iter(); - let result = f( - state, - P1::from_arg(args.next().unwrap()) - )?.into_return_val(); - Ok(result) - }, - ); - - let func = FuncInstance::alloc_host(Rc::new(func_type), host_func); - self.insert_func(name, func); - } - - pub fn insert_func2< - Cl: Fn(&mut HostState, P1, P2) -> Result + 'static, - Ret: IntoReturnVal + 'static, - P1: FromArg + 'static, - P2: FromArg + 'static, - N: Into, - >( - &mut self, - name: N, - f: Cl, - ) { - let func_type = - FunctionType::new(vec![P1::value_type(), P2::value_type()], Ret::value_type()); - let host_func = Rc::new( - move |state: &mut HostState, args: &[RuntimeValue]| -> Result, Error> { - assert!(args.len() == 2); - let mut args = args.into_iter(); - let result = f( - state, - P1::from_arg(args.next().unwrap()), - P2::from_arg(args.next().unwrap()), - )?.into_return_val(); - Ok(result) - }, - ); - - let func = FuncInstance::alloc_host(Rc::new(func_type), host_func); - self.insert_func(name, func); - } - - pub fn insert_func3< - Cl: Fn(&mut HostState, P1, P2, P3) -> Result + 'static, - Ret: IntoReturnVal + 'static, - P1: FromArg + 'static, - P2: FromArg + 'static, - P3: FromArg + 'static, - N: Into, - >( - &mut self, - name: N, - f: Cl, - ) { - let func_type = FunctionType::new( - vec![P1::value_type(), P2::value_type(), P3::value_type()], - Ret::value_type(), - ); - let host_func = Rc::new( - move |state: &mut HostState, args: &[RuntimeValue]| -> Result, Error> { - assert!(args.len() == 3); - let mut args = args.into_iter(); - let result = f( - state, - P1::from_arg(args.next().unwrap()), - P2::from_arg(args.next().unwrap()), - P3::from_arg(args.next().unwrap()), - )?.into_return_val(); - Ok(result) - }, - ); - - let func = FuncInstance::alloc_host(Rc::new(func_type), host_func); - self.insert_func(name, func); - } - - pub fn insert_func4< - Cl: Fn(&mut HostState, P1, P2, P3, P4) -> Result + 'static, - Ret: IntoReturnVal + 'static, - P1: FromArg + 'static, - P2: FromArg + 'static, - P3: FromArg + 'static, - P4: FromArg + 'static, - N: Into, - >( - &mut self, - name: N, - f: Cl, - ) { - let func_type = FunctionType::new( - vec![ - P1::value_type(), - P2::value_type(), - P3::value_type(), - P4::value_type(), - ], - Ret::value_type(), - ); - let host_func = Rc::new( - move |state: &mut HostState, args: &[RuntimeValue]| -> Result, Error> { - assert!(args.len() == 4); - let mut args = args.into_iter(); - let result = f( - state, - P1::from_arg(args.next().unwrap()), - P2::from_arg(args.next().unwrap()), - P3::from_arg(args.next().unwrap()), - P4::from_arg(args.next().unwrap()), - )?.into_return_val(); - Ok(result) - }, - ); - - let func = FuncInstance::alloc_host(Rc::new(func_type), host_func); - self.insert_func(name, func); - } - - pub fn with_func0< - Cl: Fn(&mut HostState) -> Result + 'static, - Ret: IntoReturnVal + 'static, - N: Into, - >( - mut self, - name: N, - f: Cl, - ) -> Self { - self.insert_func0(name, f); - self - } - - pub fn with_func1< - Cl: Fn(&mut HostState, P1) -> Result + 'static, - Ret: IntoReturnVal + 'static, - P1: FromArg + 'static, - N: Into, - >( - mut self, - name: N, - f: Cl, - ) -> Self { - self.insert_func1(name, f); - self - } - - pub fn with_func2< - Cl: Fn(&mut HostState, P1, P2) -> Result + 'static, - Ret: IntoReturnVal + 'static, - P1: FromArg + 'static, - P2: FromArg + 'static, - N: Into, - >( - mut self, - name: N, - f: Cl, - ) -> Self { - self.insert_func2(name, f); - self - } - - pub fn insert_func>(&mut self, name: N, func: FuncRef) { - self.insert(name, ExternVal::Func(func)); - } - - pub fn insert_global>(&mut self, name: N, global: GlobalRef) { - self.insert(name, ExternVal::Global(global)); - } - - pub fn insert_memory>(&mut self, name: N, memory: MemoryRef) { - self.insert(name, ExternVal::Memory(memory)); - } - - pub fn insert_table>(&mut self, name: N, table: TableRef) { - self.insert(name, ExternVal::Table(table)); - } - - pub fn with_global>(mut self, name: N, global: GlobalRef) -> Self { - self.insert_global(name, global); - self - } - - pub fn with_memory>(mut self, name: N, memory: MemoryRef) -> Self { - self.insert_memory(name, memory); - self - } - - pub fn with_table>(mut self, name: N, table: TableRef) -> Self { - self.insert_table(name, table); - self - } - - fn insert>(&mut self, name: N, extern_val: ExternVal) { - match self.exports.entry(name.into()) { - Entry::Vacant(v) => v.insert(extern_val), - Entry::Occupied(o) => panic!("Duplicate export name {}", o.key()), - }; - } - - pub fn build(self) -> HostModule { - let internal_instance = Rc::new(ModuleInstance::with_exports(self.exports)); - HostModule { internal_instance } - } -} - -pub struct HostModule { - internal_instance: Rc, -} - -impl HostModule { - pub fn export_by_name(&self, name: &str) -> Option { - self.internal_instance.export_by_name(name) - } -} - -impl ImportResolver for HostModule { - fn resolve_func( - &self, - field_name: &str, - func_type: &FunctionType, - ) -> Result { - self.internal_instance.resolve_func(field_name, func_type) - } - - fn resolve_global( - &self, - field_name: &str, - global_type: &GlobalType, - ) -> Result { - self.internal_instance - .resolve_global(field_name, global_type) - } - - fn resolve_memory( - &self, - field_name: &str, - memory_type: &MemoryType, - ) -> Result { - self.internal_instance - .resolve_memory(field_name, memory_type) - } - - fn resolve_table( - &self, - field_name: &str, - table_type: &TableType, - ) -> Result { - self.internal_instance.resolve_table(field_name, table_type) - } -} - -pub trait FromArg -where - Self: Sized, -{ - fn from_arg(arg: &RuntimeValue) -> Self; - fn value_type() -> ValueType; -} - -macro_rules! impl_from_arg { - ($ty: ident, $val_ty: ident) => { - impl FromArg for $ty { - fn from_arg(arg: &RuntimeValue) -> Self { - arg - .try_into() - .expect( - concat!("Due to validation, arg expected to be ", stringify!($val_ty)) - ) - } - - fn value_type() -> ValueType { - use self::ValueType::*; - $val_ty - } - } - } -} - -impl_from_arg!(i32, I32); -impl_from_arg!(u32, I32); -impl_from_arg!(i64, I64); -impl_from_arg!(u64, I64); -impl_from_arg!(f32, F32); -impl_from_arg!(f64, F64); - -pub trait IntoReturnVal { - fn into_return_val(self) -> Option; - fn value_type() -> Option; -} - -macro_rules! impl_into_return_val { - ($ty: ident, $val_ty: ident) => { - impl IntoReturnVal for $ty { - fn into_return_val(self) -> Option { - Some(self.into()) - } - - fn value_type() -> Option { - use self::ValueType::*; - Some($val_ty) - } - } - } -} - -impl_into_return_val!(i32, I32); -impl_into_return_val!(u32, I32); -impl_into_return_val!(i64, I64); -impl_into_return_val!(u64, I64); -impl_into_return_val!(f32, F32); -impl_into_return_val!(f64, F64); - -impl IntoReturnVal for () { - fn into_return_val(self) -> Option { - None - } - - fn value_type() -> Option { - None - } -} - -trait Externals { +pub trait Externals { fn invoke_index( &mut self, - index: u32, + index: HostFuncIndex, args: &[RuntimeValue], ) -> Result, Error>; - // TODO: or check signature? - fn signature(&self, index: usize) -> &FunctionType; + fn check_signature(&self, index: HostFuncIndex, signature: &FunctionType) -> bool; fn memory_by_index(&self, index: usize) -> &MemoryInstance; fn table_by_index(&self, index: usize) -> &TableInstance; fn global_by_index(&self, index: usize) -> &GlobalInstance; } +pub struct EmptyExternals; +impl Externals for EmptyExternals { + fn invoke_index( + &mut self, + _index: HostFuncIndex, + _args: &[RuntimeValue], + ) -> Result, Error> { + panic!("called invoke_index on EmptyExternals") + } + + fn check_signature(&self, _index: HostFuncIndex, _signature: &FunctionType) -> bool { + panic!("called check_signature on EmptyExternals") + } + + fn memory_by_index(&self, _index: usize) -> &MemoryInstance { + panic!("called memory_by_index on EmptyExternals") + } + + fn table_by_index(&self, _index: usize) -> &TableInstance { + panic!("called table_by_index on EmptyExternals") + } + + fn global_by_index(&self, _index: usize) -> &GlobalInstance { + panic!("called global_by_index on EmptyExternals") + } +} diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index cb5fa2c..9d25eb3 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -146,7 +146,6 @@ mod host; mod imports; mod global; mod func; -mod state; #[cfg(test)] mod tests; @@ -154,10 +153,9 @@ mod tests; pub use self::memory::{MemoryInstance, MemoryRef}; pub use self::table::{TableInstance, TableRef}; pub use self::program::ProgramInstance; -pub use self::value::RuntimeValue; -pub use self::host::{HostModule, HostModuleBuilder, HostFunc, IntoReturnVal, FromArg}; +pub use self::value::{RuntimeValue, TryInto}; +pub use self::host::{Externals, HostFuncIndex, EmptyExternals}; pub use self::imports::{ImportResolver, Imports}; pub use self::module::ModuleInstance; pub use self::global::{GlobalInstance, GlobalRef}; pub use self::func::{FuncInstance, FuncRef}; -pub use self::state::{HostState, StateKey}; diff --git a/src/interpreter/module.rs b/src/interpreter/module.rs index 4480140..b39890c 100644 --- a/src/interpreter/module.rs +++ b/src/interpreter/module.rs @@ -10,8 +10,8 @@ use interpreter::imports::{ImportResolver, Imports}; use interpreter::global::{GlobalInstance, GlobalRef}; use interpreter::func::{FuncRef, FuncBody, FuncInstance}; use interpreter::table::TableRef; -use interpreter::state::HostState; use interpreter::memory::MemoryRef; +use interpreter::host::Externals; use validation::validate_module; use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; @@ -187,7 +187,7 @@ impl ModuleInstance { "Due to validation function type should exists", ); let actual_fn_type = func.func_type(); - if expected_fn_type != actual_fn_type { + if &*expected_fn_type != actual_fn_type { return Err(Error::Instantiation(format!( "Expected function with type {:?}, but actual type is {:?} for entry {}", expected_fn_type, @@ -405,11 +405,11 @@ impl ModuleInstance { InstantiationBuilder::new(module) } - pub fn invoke_index<'a>( + pub fn invoke_index( &self, func_idx: u32, args: &[RuntimeValue], - state: &'a mut HostState<'a>, + state: &mut E, ) -> Result, Error> { let func_instance = self.func_by_index(func_idx).ok_or_else(|| { Error::Program(format!( @@ -420,11 +420,11 @@ impl ModuleInstance { FuncInstance::invoke(func_instance, Cow::Borrowed(args), state) } - pub fn invoke_export<'a>( + pub fn invoke_export( &self, func_name: &str, args: &[RuntimeValue], - state: &'a mut HostState<'a>, + state: &mut E, ) -> Result, Error> { let extern_val = self.export_by_name(func_name).ok_or_else(|| { Error::Program(format!("Module doesn't have export {}", func_name)) @@ -474,7 +474,7 @@ impl<'a> InstantiationBuilder<'a> { self } - pub fn run_start<'b>(mut self, state: &'b mut HostState<'b>) -> Result, Error> { + pub fn run_start<'b, E: Externals>(mut self, state: &'b mut E) -> Result, Error> { let imports = self.imports.get_or_insert_with(|| Imports::default()); let instance = ModuleInstance::instantiate_with_imports(self.module, imports)?; diff --git a/src/interpreter/program.rs b/src/interpreter/program.rs index b9af891..08ebc91 100644 --- a/src/interpreter/program.rs +++ b/src/interpreter/program.rs @@ -5,10 +5,9 @@ use elements::Module; use interpreter::Error; use interpreter::module::{ModuleInstance}; use interpreter::func::{FuncInstance, FuncRef}; -use interpreter::host::HostModule; use interpreter::value::RuntimeValue; use interpreter::imports::{Imports, ImportResolver}; -use interpreter::state::HostState; +use interpreter::host::Externals; /// Program instance. Program is a set of instantiated modules. #[deprecated] @@ -27,11 +26,11 @@ impl ProgramInstance { } /// Instantiate module with validation. - pub fn add_module<'a>( + pub fn add_module<'a, E: Externals>( &mut self, name: &str, module: Module, - state: &'a mut HostState<'a>, + externals: &'a mut E, ) -> Result, Error> { let module_instance = { let mut imports = Imports::new(); @@ -43,7 +42,7 @@ impl ProgramInstance { } ModuleInstance::new(&module) .with_imports(imports) - .run_start(state)? + .run_start(externals)? }; self.modules.insert(name.to_owned(), Rc::clone(&module_instance)); @@ -58,49 +57,41 @@ impl ProgramInstance { self.resolvers.insert(name.to_owned(), import_resolver); } - pub fn add_host_module( - &mut self, - name: &str, - host_module: HostModule, - ) { - self.resolvers.insert(name.to_owned(), Box::new(host_module) as Box); - } - pub fn insert_loaded_module(&mut self, name: &str, module: Rc) { self.modules.insert(name.to_owned(), module); } - pub fn invoke_export<'a>( + pub fn invoke_export<'a, E: Externals>( &mut self, module_name: &str, func_name: &str, args: &[RuntimeValue], - state: &'a mut HostState<'a>, + externals: &'a mut E, ) -> Result, Error> { let module_instance = self.modules.get(module_name).ok_or_else(|| { Error::Program(format!("Module {} not found", module_name)) })?; - module_instance.invoke_export(func_name, args, state) + module_instance.invoke_export(func_name, args, externals) } - pub fn invoke_index<'a>( + pub fn invoke_index<'a, E: Externals>( &mut self, module_name: &str, func_idx: u32, args: &[RuntimeValue], - state: &'a mut HostState<'a>, + externals: &'a mut E, ) -> Result, Error> { let module_instance = self.modules.get(module_name).cloned().ok_or_else(|| { Error::Program(format!("Module {} not found", module_name)) })?; - module_instance.invoke_index(func_idx, args, state) + module_instance.invoke_index(func_idx, args, externals) } - pub fn invoke_func<'a>( + pub fn invoke_func<'a, E: Externals>( &mut self, func_instance: FuncRef, args: &[RuntimeValue], - state: &'a mut HostState<'a>, + state: &'a mut E, ) -> Result, Error> { FuncInstance::invoke(func_instance.clone(), Cow::Borrowed(args), state) } diff --git a/src/interpreter/runner.rs b/src/interpreter/runner.rs index 458cdca..2d9bfc7 100644 --- a/src/interpreter/runner.rs +++ b/src/interpreter/runner.rs @@ -14,13 +14,13 @@ use interpreter::value::{ RuntimeValue, TryInto, WrapInto, TryTruncateInto, ExtendInto, ArithmeticOps, Integer, Float, LittleEndianConvert, TransmuteInto, }; +use interpreter::host::Externals; use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX, BlockFrame, BlockFrameType}; use common::stack::StackWithLimit; -use interpreter::state::HostState; /// Function interpreter. -pub struct Interpreter<'a, 'b: 'a> { - state: &'a mut HostState<'b>, +pub struct Interpreter<'a, E: Externals + 'a> { + externals: &'a mut E, } /// Function execution context. @@ -64,10 +64,10 @@ enum RunResult { NestedCall(FuncRef), } -impl<'a, 'b: 'a> Interpreter<'a, 'b> { - pub fn new(state: &'a mut HostState<'b>) -> Interpreter<'a, 'b> { +impl<'a, E: Externals> Interpreter<'a, E> { + pub fn new(externals: &'a mut E) -> Interpreter<'a, E> { Interpreter { - state: state, + externals, } } @@ -105,7 +105,7 @@ impl<'a, 'b: 'a> Interpreter<'a, 'b> { }, FuncInstance::Host { ref func_type, .. } => { let args = prepare_function_args(func_type, &mut function_context.value_stack)?; - let return_val = FuncInstance::invoke(nested_func.clone(), args.into(), self.state)?; + let return_val = FuncInstance::invoke(nested_func.clone(), args.into(), self.externals)?; if let Some(return_val) = return_val { function_context.value_stack_mut().push(return_val)?; } @@ -439,20 +439,22 @@ impl<'a, 'b: 'a> Interpreter<'a, 'b> { .expect("Due to validation table should exists"); let func_ref = table.get(table_func_idx)?; - let actual_function_type = func_ref.func_type(); - let required_function_type = context - .module() - .type_by_index(type_idx) - .expect("Due to validation type should exists"); + { + let actual_function_type = func_ref.func_type(); + let required_function_type = context + .module() + .type_by_index(type_idx) + .expect("Due to validation type should exists"); - if required_function_type != actual_function_type { - return Err(Error::Function(format!( - "expected function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}", - required_function_type.params(), - required_function_type.return_type(), - actual_function_type.params(), - actual_function_type.return_type() - ))); + if &*required_function_type != actual_function_type { + return Err(Error::Function(format!( + "expected function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}", + required_function_type.params(), + required_function_type.return_type(), + actual_function_type.params(), + actual_function_type.return_type() + ))); + } } Ok(InstructionOutcome::ExecuteCall(func_ref)) diff --git a/src/interpreter/state.rs b/src/interpreter/state.rs deleted file mode 100644 index 826f062..0000000 --- a/src/interpreter/state.rs +++ /dev/null @@ -1,138 +0,0 @@ - -use std::any::{Any, TypeId}; -use std::collections::HashMap; - -pub unsafe trait StateKey { - type Static: ?Sized + 'static; -} - -pub fn type_id() -> TypeId -where - T: StateKey, - T::Static: Any, -{ - TypeId::of::() -} - -#[derive(Default)] -pub struct HostState<'a> { - data: HashMap, - _marker: ::std::marker::PhantomData<&'a mut ()>, -} - -impl<'a> HostState<'a> { - pub fn new() -> Self { - HostState { - data: HashMap::default(), - _marker: ::std::marker::PhantomData, - } - } - - pub fn insert(&mut self, val: &'a mut V) { - let ty_id = type_id::(); - let ptr = val as *mut V as *mut (); - let existing = self.data.insert(ty_id, ptr); - assert!(existing.is_none()); - } - - pub fn with R>(&self, f: F) -> R { - let ptr = self.data.get(&type_id::()).unwrap(); - unsafe { - let val_ref = &*(*ptr as *const V); - f(val_ref) - } - } - - pub fn with_mut R + 'static>(&mut self, f: F) -> R { - let ptr = self.data.get_mut(&type_id::()).unwrap(); - unsafe { - let val_ref = &mut *(*ptr as *mut V); - f(val_ref) - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - struct MyState<'a>(&'a mut i32); - impl<'a> MyState<'a> { - fn inc(&mut self) { - *self.0 += 1; - } - - fn get(&self) -> i32 { - *self.0 - } - } - - /// Safety of this impl should be ensured by a macro. - unsafe impl<'a> StateKey for MyState<'a> { - type Static = MyState<'static>; - } - - #[test] - fn it_works() { - let mut counter = 33i32; - - let new_value = { - let mut my_state = MyState(&mut counter); - let mut host_state = HostState::new(); - host_state.insert::(&mut my_state); - host_state.with_mut(|my_state: &mut MyState| { - my_state.inc(); - my_state.get() - }) - }; - - assert_eq!(new_value, counter); - } - - struct MyImmutableState<'a>(&'a i32); - /// Safety of this impl should be ensured by a macro. - unsafe impl<'a> StateKey for MyImmutableState<'a> { - type Static = MyImmutableState<'static>; - } - - struct StaticState(i32); - - impl StaticState { - fn inc(&mut self) { - self.0 += 1; - } - - fn get(&self) -> i32 { - self.0 - } - } - - /// Safety of this impl should be ensured by a macro. - unsafe impl<'a> StateKey for StaticState { - type Static = StaticState; - } - - #[test] - fn compiles_with_static() { - let mut static_state = StaticState(45); - let mut host_state = HostState::new(); - host_state.insert::(&mut static_state); - host_state.with_mut(|my_state: &mut StaticState| { - my_state.inc(); - }); - host_state.with_mut(|my_state: &mut StaticState| { - my_state.inc(); - assert_eq!(47, my_state.get()); - }) - } - - #[test] - #[should_panic] - fn doesnt_allow_dups() { - let mut static_state_1 = StaticState(45); - let mut static_state_2 = StaticState(45); - let mut host_state = HostState::new(); - host_state.insert::(&mut static_state_1); - host_state.insert::(&mut static_state_2); - } -}