diff --git a/examples/interpret.rs b/examples/interpret.rs index fad4c51..dfc10ab 100644 --- a/examples/interpret.rs +++ b/examples/interpret.rs @@ -2,7 +2,7 @@ extern crate parity_wasm; use std::env::args; -use parity_wasm::{interpreter, ModuleInstanceInterface}; +use parity_wasm::{interpreter, CustomModuleInstanceInterface}; fn main() { let args: Vec<_> = args().collect(); diff --git a/examples/invoke.rs b/examples/invoke.rs index 22a47e1..7171d6b 100644 --- a/examples/invoke.rs +++ b/examples/invoke.rs @@ -2,7 +2,7 @@ extern crate parity_wasm; use std::env::args; -use parity_wasm::{interpreter, ModuleInstanceInterface, RuntimeValue}; +use parity_wasm::{interpreter, CustomModuleInstanceInterface, RuntimeValue}; use parity_wasm::elements::{Internal, External, Type, FunctionType, ValueType}; diff --git a/spec/src/run.rs b/spec/src/run.rs index f212bdb..fc62b51 100644 --- a/spec/src/run.rs +++ b/spec/src/run.rs @@ -13,7 +13,8 @@ use parity_wasm::interpreter::{ RuntimeValue, ProgramInstance, ModuleInstance, ItemIndex, ExportEntryType, - Error as InterpreterError, + Error as InternalInterpreterError, + InterpreterError }; fn spec_test_module() -> elements::Module { @@ -60,7 +61,12 @@ fn try_deserialize(base_dir: &str, module_path: &str) -> Result Result<(), parity_wasm::interpreter::Error> { let module = try_deserialize(base_dir, module_path).map_err(|e| parity_wasm::interpreter::Error::Program(format!("{:?}", e)))?; let program = ProgramInstance::new().expect("Failed creating program"); - program.add_module("try_load", module, None).map(|_| ()) + program.add_module("try_load", module, None) + .map(|_| ()) + .map_err(|e| match e { + InterpreterError::Internal(e) => e, + _ => unreachable!(), + }) } fn runtime_value(test_val: &test::RuntimeValue) -> parity_wasm::RuntimeValue { @@ -90,7 +96,7 @@ fn runtime_values(test_vals: &[test::RuntimeValue]) -> Vec Result, InterpreterError> + -> Result, InternalInterpreterError> { match *action { test::Action::Invoke { ref module, ref field, ref args } => { @@ -98,6 +104,10 @@ fn run_action(program: &ProgramInstance, action: &test::Action) let module = module.trim_left_matches('$'); let module = program.module(&module).expect(&format!("Expected program to have loaded module {}", module)); module.execute_export(&jstring_to_rstring(field), runtime_values(args).into()) + .map_err(|e| match e { + InterpreterError::Internal(e) => e, + _ => unreachable!(), + }) }, test::Action::Get { ref module, ref field, .. } => { let module = module.clone().unwrap_or("wasm_test".into()); @@ -108,7 +118,7 @@ fn run_action(program: &ProgramInstance, action: &test::Action) module.export_entry(field.as_ref(), &ExportEntryType::Any) .and_then(|i| match i { elements::Internal::Global(global_index) => Ok(ItemIndex::IndexSpace(global_index)), - _ => Err(InterpreterError::Global(format!("Expected to have exported global with name {}", field))), + _ => Err(InternalInterpreterError::Global(format!("Expected to have exported global with name {}", field))), }) .and_then(|g| module.global(g, None, None).map(|g| Some(g.get()))) } diff --git a/src/interpreter/env.rs b/src/interpreter/env.rs index 6748f2b..e89e68a 100644 --- a/src/interpreter/env.rs +++ b/src/interpreter/env.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use builder::module; use elements::{Module, ExportEntry, Internal, GlobalEntry, GlobalType, ValueType, InitExpr, Opcode, Opcodes}; -use interpreter::Error; +use interpreter::{Error, CustomUserError, InterpreterError}; use interpreter::env_native::NATIVE_INDEX_FUNC_MIN; use interpreter::module::{ModuleInstanceInterface, ModuleInstance, ExecutionParams, ItemIndex, CallerContext, ExportEntryType, InternalFunctionReference, InternalFunction, FunctionSignature}; @@ -78,12 +78,12 @@ pub struct EnvParams { pub allow_memory_growth: bool, } -pub struct EnvModuleInstance { +pub struct EnvModuleInstance { _params: EnvParams, - instance: ModuleInstance, + instance: ModuleInstance, } -impl EnvModuleInstance { +impl EnvModuleInstance where E: CustomUserError { pub fn new(params: EnvParams, module: Module) -> Result { let mut instance = ModuleInstance::new(Weak::default(), "env".into(), module)?; instance.instantiate(None)?; @@ -95,12 +95,12 @@ impl EnvModuleInstance { } } -impl ModuleInstanceInterface for EnvModuleInstance { - fn execute_index(&self, index: u32, params: ExecutionParams) -> Result, Error> { +impl ModuleInstanceInterface for EnvModuleInstance where E: CustomUserError { + fn execute_index(&self, index: u32, params: ExecutionParams) -> Result, InterpreterError> { self.instance.execute_index(index, params) } - fn execute_export(&self, name: &str, params: ExecutionParams) -> Result, Error> { + fn execute_export(&self, name: &str, params: ExecutionParams) -> Result, InterpreterError> { self.instance.execute_export(name, params) } @@ -116,7 +116,7 @@ impl ModuleInstanceInterface for EnvModuleInstance { self.instance.memory(index) } - fn global<'a>(&self, index: ItemIndex, variable_type: Option, externals: Option<&'a HashMap>>) -> Result, Error> { + fn global<'a>(&self, index: ItemIndex, variable_type: Option, externals: Option<&'a HashMap + 'a>>>) -> Result, Error> { self.instance.global(index, variable_type, externals) } @@ -128,11 +128,11 @@ impl ModuleInstanceInterface for EnvModuleInstance { self.instance.function_type_by_index(type_index) } - fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap>>) -> Result, Error> { + fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap + 'a>>>) -> Result, Error> { self.instance.function_reference(index, externals) } - fn function_reference_indirect<'a>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'a HashMap>>) -> Result, Error> { + fn function_reference_indirect<'a>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'a HashMap + 'a>>>) -> Result, Error> { self.instance.function_reference_indirect(table_idx, type_idx, func_idx, externals) } @@ -140,12 +140,13 @@ impl ModuleInstanceInterface for EnvModuleInstance { Ok(None) } - fn call_internal_function(&self, outer: CallerContext, index: u32) -> Result, Error> { + fn call_internal_function(&self, outer: CallerContext, index: u32) -> Result, InterpreterError> { // to make interpreter independent of *SCRIPTEN runtime, just make abort/assert = interpreter Error match index { INDEX_FUNC_ABORT => self.global(ItemIndex::IndexSpace(INDEX_GLOBAL_ABORT), Some(VariableType::I32), None) .and_then(|g| g.set(RuntimeValue::I32(1))) - .and_then(|_| Err(Error::Trap("abort".into()))), + .and_then(|_| Err(Error::Trap("abort".into()))) + .map_err(Into::into), INDEX_FUNC_ASSERT => outer.value_stack.pop_as::() .and_then(|condition| if condition == 0 { self.global(ItemIndex::IndexSpace(INDEX_GLOBAL_ABORT), Some(VariableType::I32), None) @@ -153,18 +154,20 @@ impl ModuleInstanceInterface for EnvModuleInstance { .and_then(|_| Err(Error::Trap("assertion failed".into()))) } else { Ok(None) - }), + }) + .map_err(Into::into), INDEX_FUNC_ENLARGE_MEMORY => Ok(Some(RuntimeValue::I32(0))), // TODO: support memory enlarge INDEX_FUNC_GET_TOTAL_MEMORY => self.global(ItemIndex::IndexSpace(INDEX_GLOBAL_TOTAL_MEMORY), Some(VariableType::I32), None) .map(|g| g.get()) - .map(Some), - INDEX_FUNC_MIN_NONUSED ... INDEX_FUNC_MAX => Err(Error::Trap("unimplemented".into())), - _ => Err(Error::Trap(format!("trying to call function with index {} in env module", index))), + .map(Some) + .map_err(Into::into), + INDEX_FUNC_MIN_NONUSED ... INDEX_FUNC_MAX => Err(Error::Trap("unimplemented".into()).into()), + _ => Err(Error::Trap(format!("trying to call function with index {} in env module", index)).into()), } } } -pub fn env_module(params: EnvParams) -> Result { +pub fn env_module(params: EnvParams) -> Result, Error> { debug_assert!(params.total_stack < params.total_memory); debug_assert!((params.total_stack % LINEAR_MEMORY_PAGE_SIZE) == 0); debug_assert!((params.total_memory % LINEAR_MEMORY_PAGE_SIZE) == 0); diff --git a/src/interpreter/env_native.rs b/src/interpreter/env_native.rs index 921067f..22a7955 100644 --- a/src/interpreter/env_native.rs +++ b/src/interpreter/env_native.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use std::borrow::Cow; use parking_lot::RwLock; use elements::{Internal, ValueType}; -use interpreter::Error; +use interpreter::{Error, CustomUserError, InterpreterError}; use interpreter::module::{ModuleInstanceInterface, ExecutionParams, ItemIndex, CallerContext, ExportEntryType, InternalFunctionReference, InternalFunction, FunctionSignature}; use interpreter::memory::MemoryInstance; @@ -17,9 +17,9 @@ pub const NATIVE_INDEX_FUNC_MIN: u32 = 10001; pub const NATIVE_INDEX_GLOBAL_MIN: u32 = 20001; /// User functions executor. -pub trait UserFunctionExecutor { +pub trait UserFunctionExecutor { /// Execute function with given name. - fn execute(&mut self, name: &str, context: CallerContext) -> Result, Error>; + fn execute(&mut self, name: &str, context: CallerContext) -> Result, InterpreterError>; } /// User function descriptor @@ -68,21 +68,21 @@ impl UserFunctionDescriptor { } /// Set of user-defined module elements. -pub struct UserDefinedElements<'a> { +pub struct UserDefinedElements<'a, E: 'a + CustomUserError> { /// User globals list. pub globals: HashMap>, /// User functions list. pub functions: Cow<'static, [UserFunctionDescriptor]>, /// Functions executor. - pub executor: Option<&'a mut UserFunctionExecutor>, + pub executor: Option<&'a mut UserFunctionExecutor>, } /// Native module instance. -pub struct NativeModuleInstance<'a> { +pub struct NativeModuleInstance<'a, E: 'a + CustomUserError> { /// Underllying module reference. - env: Arc, + env: Arc>, /// User function executor. - executor: RwLock>, + executor: RwLock>>, /// By-name functions index. functions_by_name: HashMap, /// User functions list. @@ -93,9 +93,9 @@ pub struct NativeModuleInstance<'a> { globals: Vec>, } -impl<'a> NativeModuleInstance<'a> { +impl<'a, E> NativeModuleInstance<'a, E> where E: CustomUserError { /// Create new native module - pub fn new(env: Arc, elements: UserDefinedElements<'a>) -> Result { + pub fn new(env: Arc>, elements: UserDefinedElements<'a, E>) -> Result { if !elements.functions.is_empty() && elements.executor.is_none() { return Err(Error::Function("trying to construct native env module with functions, but without executor".into())); } @@ -111,12 +111,12 @@ impl<'a> NativeModuleInstance<'a> { } } -impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { - fn execute_index(&self, index: u32, params: ExecutionParams) -> Result, Error> { +impl<'a, E> ModuleInstanceInterface for NativeModuleInstance<'a, E> where E: CustomUserError { + fn execute_index(&self, index: u32, params: ExecutionParams) -> Result, InterpreterError> { self.env.execute_index(index, params) } - fn execute_export(&self, name: &str, params: ExecutionParams) -> Result, Error> { + fn execute_export(&self, name: &str, params: ExecutionParams) -> Result, InterpreterError> { self.env.execute_export(name, params) } @@ -155,7 +155,7 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { self.env.memory(index) } - fn global<'b>(&self, global_index: ItemIndex, variable_type: Option, externals: Option<&'b HashMap>>) -> Result, Error> { + fn global<'b>(&self, global_index: ItemIndex, variable_type: Option, externals: Option<&'b HashMap + 'b>>>) -> Result, Error> { let index = match global_index { ItemIndex::IndexSpace(index) | ItemIndex::Internal(index) => index, ItemIndex::External(_) => unreachable!("trying to get global, exported by native env module"), @@ -190,11 +190,11 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { self.function_type(ItemIndex::Internal(type_index)) } - fn function_reference<'b>(&self, index: ItemIndex, externals: Option<&'b HashMap>>) -> Result, Error> { + fn function_reference<'b>(&self, index: ItemIndex, externals: Option<&'b HashMap + 'b>>>) -> Result, Error> { self.env.function_reference(index, externals) } - fn function_reference_indirect<'b>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'b HashMap>>) -> Result, Error> { + fn function_reference_indirect<'b>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'b HashMap + 'b>>>) -> Result, Error> { self.env.function_reference_indirect(table_idx, type_idx, func_idx, externals) } @@ -202,14 +202,14 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { Ok(None) } - fn call_internal_function(&self, outer: CallerContext, index: u32) -> Result, Error> { + fn call_internal_function(&self, outer: CallerContext, index: u32) -> Result, InterpreterError> { if index < NATIVE_INDEX_FUNC_MIN || index >= NATIVE_INDEX_GLOBAL_MIN { return self.env.call_internal_function(outer, index); } self.functions .get((index - NATIVE_INDEX_FUNC_MIN) as usize) - .ok_or(Error::Native(format!("trying to call native function with index {}", index))) + .ok_or(Error::Native(format!("trying to call native function with index {}", index)).into()) .and_then(|f| self.executor.write() .as_mut() .expect("function existss; if function exists, executor must also exists [checked in constructor]; qed") @@ -218,7 +218,7 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { } /// Create wrapper for env module with given native user functions. -pub fn env_native_module<'a>(env: Arc, user_elements: UserDefinedElements<'a>) -> Result { +pub fn env_native_module<'a, E: CustomUserError>(env: Arc>, user_elements: UserDefinedElements<'a, E>) -> Result, Error> { NativeModuleInstance::new(env, user_elements) } diff --git a/src/interpreter/imports.rs b/src/interpreter/imports.rs index 7243e27..e785cc3 100644 --- a/src/interpreter/imports.rs +++ b/src/interpreter/imports.rs @@ -1,7 +1,7 @@ use std::sync::{Arc, Weak}; use std::collections::HashMap; use elements::{ImportSection, ImportEntry, External, Internal}; -use interpreter::Error; +use interpreter::{Error, CustomUserError}; use interpreter::memory::MemoryInstance; use interpreter::module::{ModuleInstanceInterface, ItemIndex, ExportEntryType, FunctionSignature}; use interpreter::program::ProgramInstanceEssence; @@ -9,9 +9,9 @@ use interpreter::table::TableInstance; use interpreter::variable::{VariableInstance, VariableType}; /// Module imports. -pub struct ModuleImports { +pub struct ModuleImports { /// Program instance. - program: Weak, + program: Weak>, /// External functions. functions: Vec, /// External tables. @@ -22,9 +22,9 @@ pub struct ModuleImports { globals: Vec, } -impl ModuleImports { +impl ModuleImports where E: CustomUserError { /// Create new imports for given import section. - pub fn new(program: Weak, import_section: Option<&ImportSection>) -> Self { + pub fn new(program: Weak>, import_section: Option<&ImportSection>) -> Self { let mut functions = Vec::new(); let mut tables = Vec::new(); let mut memory = Vec::new(); @@ -104,7 +104,7 @@ impl ModuleImports { } /// Get module reference. - pub fn module<'a>(&self, externals: Option<&'a HashMap>>, name: &str) -> Result, Error> { + pub fn module<'a>(&self, externals: Option<&'a HashMap + 'a>>>, name: &str) -> Result + 'a>, Error> { if let Some(externals) = externals { if let Some(module) = externals.get(name).cloned() { return Ok(module); @@ -118,7 +118,7 @@ impl ModuleImports { } /// Get function index. - pub fn function<'a>(&self, externals: Option<&'a HashMap>>, import: &ImportEntry, required_type: Option) -> Result { + pub fn function<'a>(&self, externals: Option<&'a HashMap + 'a>>>, import: &ImportEntry, required_type: Option) -> Result { let (_, export) = self.external_export(externals, import, &required_type.map(|ft| ExportEntryType::Function(ft)).unwrap_or(ExportEntryType::Any))?; if let Internal::Function(external_index) = export { return Ok(external_index); @@ -128,7 +128,7 @@ impl ModuleImports { } /// Get table reference. - pub fn table<'a>(&self, externals: Option<&'a HashMap>>, import: &ImportEntry) -> Result, Error> { + pub fn table<'a>(&self, externals: Option<&'a HashMap + 'a>>>, import: &ImportEntry) -> Result, Error> { let (module, export) = self.external_export(externals, import, &ExportEntryType::Any)?; if let Internal::Table(external_index) = export { return module.table(ItemIndex::Internal(external_index)); @@ -138,7 +138,7 @@ impl ModuleImports { } /// Get memory reference. - pub fn memory<'a>(&self, externals: Option<&'a HashMap>>, import: &ImportEntry) -> Result, Error> { + pub fn memory<'a>(&self, externals: Option<&'a HashMap + 'a>>>, import: &ImportEntry) -> Result, Error> { let (module, export) = self.external_export(externals, import, &ExportEntryType::Any)?; if let Internal::Memory(external_index) = export { return module.memory(ItemIndex::Internal(external_index)); @@ -148,7 +148,7 @@ impl ModuleImports { } /// Get global reference. - pub fn global<'a>(&self, externals: Option<&'a HashMap>>, import: &ImportEntry, required_type: Option) -> Result, Error> { + pub fn global<'a>(&self, externals: Option<&'a HashMap + 'a>>>, import: &ImportEntry, required_type: Option) -> Result, Error> { let (module, export) = self.external_export(externals, import, &required_type.clone().map(|rt| ExportEntryType::Global(rt)).unwrap_or(ExportEntryType::Any))?; if let Internal::Global(external_index) = export { return module.global(ItemIndex::Internal(external_index), required_type, externals); @@ -157,7 +157,7 @@ impl ModuleImports { Err(Error::Program(format!("wrong import {} from module {} (expecting global)", import.field(), import.module()))) } - fn external_export<'a>(&self, externals: Option<&'a HashMap>>, import: &ImportEntry, required_type: &ExportEntryType) -> Result<(Arc, Internal), Error> { + fn external_export<'a>(&self, externals: Option<&'a HashMap + 'a>>>, import: &ImportEntry, required_type: &ExportEntryType) -> Result<(Arc + 'a>, Internal), Error> { self.module(externals, import.module()) .and_then(|m| m.export_entry(import.field(), required_type) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 3ebeccd..c369434 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -2,6 +2,19 @@ /// Interpreter error. #[derive(Debug, Clone, PartialEq)] +pub enum InterpreterError { + /// Internal error. + Internal(Error), + /// Custom user error. + User(E), +} + +/// Custom user error. +pub trait CustomUserError: 'static + ::std::fmt::Display + ::std::fmt::Debug + Clone + PartialEq { +} + +/// Internal interpreter error. +#[derive(Debug, Clone, PartialEq)] pub enum Error { /// Program-level error. Program(String), @@ -35,6 +48,12 @@ pub enum Error { Trap(String), } +impl From for InterpreterError where E: CustomUserError { + fn from(other: Error) -> Self { + InterpreterError::Internal(other) + } +} + impl Into for Error { fn into(self) -> String { match self { @@ -57,6 +76,16 @@ impl Into for Error { } } +/// Dummy user error. +#[derive(Debug, Clone, PartialEq)] +pub struct DummyCustomUserError; + +impl CustomUserError for DummyCustomUserError {} + +impl ::std::fmt::Display for DummyCustomUserError { + fn fmt(&self, _f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { Ok(()) } +} + mod env; mod env_native; mod imports; @@ -74,10 +103,24 @@ mod variable; mod tests; pub use self::memory::MemoryInstance; -pub use self::module::{ModuleInstance, ModuleInstanceInterface, ItemIndex, ExportEntryType, CallerContext, ExecutionParams, FunctionSignature}; +pub use self::module::{ModuleInstance as CustomModuleInstance, + ModuleInstanceInterface as CustomModuleInstanceInterface, + ItemIndex, ExportEntryType, CallerContext, ExecutionParams, FunctionSignature}; pub use self::table::TableInstance; -pub use self::program::ProgramInstance; +pub use self::program::ProgramInstance as CustomProgramInstance; pub use self::value::RuntimeValue; pub use self::variable::{VariableInstance, VariableType, ExternalVariableValue}; pub use self::env_native::{env_native_module, UserDefinedElements, UserFunctionExecutor, UserFunctionDescriptor}; -pub use self::env::EnvParams; \ No newline at end of file +pub use self::env::EnvParams; + +/// Default type of ProgramInstance if you do not need any custom user errors. +/// To work with custom user errors or interpreter internals, use CustomProgramInstance. +pub type ProgramInstance = self::program::ProgramInstance; + +/// Default type of ModuleInstance if you do not need any custom user errors. +/// To work with custom user errors or interpreter internals, use CustomModuleInstance. +pub type ModuleInstance = self::module::ModuleInstance; + +/// Default type of ModuleInstanceInterface if you do not need any custom user errors. +/// To work with custom user errors or interpreter internals, use CustomModuleInstanceInterface. +pub type ModuleInstanceInterface = self::module::ModuleInstanceInterface; diff --git a/src/interpreter/module.rs b/src/interpreter/module.rs index 9327154..35fb8a2 100644 --- a/src/interpreter/module.rs +++ b/src/interpreter/module.rs @@ -3,7 +3,7 @@ use std::iter::repeat; use std::sync::{Arc, Weak}; use std::fmt; use elements::{Module, InitExpr, Opcode, Type, FunctionType, Internal, External, BlockType, ResizableLimits, Local, ValueType}; -use interpreter::Error; +use interpreter::{Error, CustomUserError, InterpreterError}; use interpreter::env_native::UserFunctionDescriptor; use interpreter::imports::ModuleImports; use interpreter::memory::MemoryInstance; @@ -21,12 +21,12 @@ const DEFAULT_VALUE_STACK_LIMIT: usize = 16384; const DEFAULT_FRAME_STACK_LIMIT: usize = 1024; /// Execution context. -#[derive(Default, Clone)] -pub struct ExecutionParams<'a> { +#[derive(Clone)] +pub struct ExecutionParams<'a, E: CustomUserError> { /// Arguments. pub args: Vec, /// Execution-local external modules. - pub externals: HashMap>, + pub externals: HashMap + 'a>>, } /// Export type. @@ -50,11 +50,11 @@ pub enum FunctionSignature<'a> { } /// Module instance API. -pub trait ModuleInstanceInterface { +pub trait ModuleInstanceInterface { /// Execute function with the given index. - fn execute_index(&self, index: u32, params: ExecutionParams) -> Result, Error>; + fn execute_index(&self, index: u32, params: ExecutionParams) -> Result, InterpreterError>; /// Execute function with the given export name. - fn execute_export(&self, name: &str, params: ExecutionParams) -> Result, Error>; + fn execute_export(&self, name: &str, params: ExecutionParams) -> Result, InterpreterError>; /// Get export entry. fn export_entry<'a>(&self, name: &str, required_type: &ExportEntryType) -> Result; /// Get table reference. @@ -62,19 +62,19 @@ pub trait ModuleInstanceInterface { /// Get memory reference. fn memory(&self, index: ItemIndex) -> Result, Error>; /// Get global reference. - fn global<'a>(&self, index: ItemIndex, variable_type: Option, externals: Option<&'a HashMap>>) -> Result, Error>; + fn global<'a>(&self, index: ItemIndex, variable_type: Option, externals: Option<&'a HashMap + 'a>>>) -> Result, Error>; /// Get function type for given function index. fn function_type(&self, function_index: ItemIndex) -> Result; /// Get function type for given function index. fn function_type_by_index(&self, type_index: u32) -> Result; /// Get function reference. - fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap>>) -> Result, Error>; + fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap + 'a>>>) -> Result, Error>; /// Get function indirect reference. - fn function_reference_indirect<'a>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'a HashMap>>) -> Result, Error>; + fn function_reference_indirect<'a>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'a HashMap + 'a>>>) -> Result, Error>; /// Get internal function for interpretation. fn function_body<'a>(&'a self, internal_index: u32) -> Result>, Error>; /// Call function with given internal index. - fn call_internal_function(&self, outer: CallerContext, index: u32) -> Result, Error>; + fn call_internal_function(&self, outer: CallerContext, index: u32) -> Result, InterpreterError>; } /// Item index in items index space. @@ -89,7 +89,7 @@ pub enum ItemIndex { } /// Module instance. -pub struct ModuleInstance { +pub struct ModuleInstance { /// Module name. name: String, /// Module. @@ -97,7 +97,7 @@ pub struct ModuleInstance { /// Function labels. functions_labels: HashMap>, /// Module imports. - imports: ModuleImports, + imports: ModuleImports, /// Module exports. exports: HashMap>, /// Tables. @@ -109,7 +109,7 @@ pub struct ModuleInstance { } /// Caller context. -pub struct CallerContext<'a> { +pub struct CallerContext<'a, E: 'a + CustomUserError> { /// Value stack limit pub value_stack_limit: usize, /// Frame stack limit @@ -117,19 +117,19 @@ pub struct CallerContext<'a> { /// Stack of the input parameters pub value_stack: &'a mut StackWithLimit, /// Execution-local external modules. - pub externals: &'a HashMap>, + pub externals: &'a HashMap + 'a>>, } /// Internal function reference. #[derive(Clone)] -pub struct InternalFunctionReference<'a> { +pub struct InternalFunctionReference<'a, E: CustomUserError> { /// Module reference. - pub module: Arc, + pub module: Arc + 'a>, /// Internal function index. pub internal_index: u32, } -impl<'a> fmt::Debug for InternalFunctionReference<'a> { +impl<'a, E> fmt::Debug for InternalFunctionReference<'a, E> where E: CustomUserError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "InternalFunctionReference") } @@ -145,9 +145,9 @@ pub struct InternalFunction<'a> { pub labels: &'a HashMap, } -impl<'a> ExecutionParams<'a> { +impl<'a, E> ExecutionParams<'a, E> where E: CustomUserError { /// Create new execution params with given externa; module override. - pub fn with_external(name: String, module: Arc) -> Self { + pub fn with_external(name: String, module: Arc + 'a>) -> Self { let mut externals = HashMap::new(); externals.insert(name, module); ExecutionParams { @@ -163,8 +163,17 @@ impl<'a> ExecutionParams<'a> { } } -impl<'a> From> for ExecutionParams<'a> { - fn from(args: Vec) -> ExecutionParams<'a> { +impl<'a, E> Default for ExecutionParams<'a, E> where E: CustomUserError { + fn default() -> Self { + ExecutionParams { + args: Vec::default(), + externals: HashMap::default(), + } + } +} + +impl<'a, E> From> for ExecutionParams<'a, E> where E: CustomUserError { + fn from(args: Vec) -> ExecutionParams<'a, E> { ExecutionParams { args: args, externals: HashMap::new(), @@ -172,9 +181,9 @@ impl<'a> From> for ExecutionParams<'a> { } } -impl ModuleInstance { +impl ModuleInstance where E: CustomUserError { /// Instantiate given module within program context. - pub fn new<'a>(program: Weak, name: String, module: Module) -> Result { + pub fn new<'a>(program: Weak>, name: String, module: Module) -> Result { // load entries from import section let imports = ModuleImports::new(program, module.import_section()); @@ -222,7 +231,7 @@ impl ModuleInstance { } /// Run instantiation-time procedures (validation). Module is not completely validated until this call. - pub fn instantiate<'a>(&mut self, externals: Option<&'a HashMap>>) -> Result<(), Error> { + pub fn instantiate<'a>(&mut self, externals: Option<&'a HashMap + 'a>>>) -> Result<(), Error> { // validate start section if let Some(start_function) = self.module.start_section() { let func_type_index = self.require_function(ItemIndex::IndexSpace(start_function))?; @@ -388,7 +397,7 @@ impl ModuleInstance { } /// Run start function [if any]. - pub fn run_start_function(&self) -> Result<(), Error> { + pub fn run_start_function(&self) -> Result<(), InterpreterError> { // execute start function (if any) if let Some(start_function) = self.module.start_section() { self.execute_index(start_function, ExecutionParams::default())?; @@ -396,7 +405,7 @@ impl ModuleInstance { Ok(()) } - fn self_ref<'a>(&self, externals: Option<&'a HashMap>>) -> Result, Error> { + fn self_ref<'a>(&self, externals: Option<&'a HashMap + 'a>>>) -> Result + 'a>, Error> { self.imports.module(externals, &self.name) } @@ -420,8 +429,8 @@ impl ModuleInstance { } } -impl ModuleInstanceInterface for ModuleInstance { - fn execute_index(&self, index: u32, params: ExecutionParams) -> Result, Error> { +impl ModuleInstanceInterface for ModuleInstance where E: CustomUserError { + fn execute_index(&self, index: u32, params: ExecutionParams) -> Result, InterpreterError> { let ExecutionParams { args, externals } = params; let mut args = StackWithLimit::with_data(args, DEFAULT_VALUE_STACK_LIMIT); let function_reference = self.function_reference(ItemIndex::IndexSpace(index), Some(&externals))?; @@ -429,7 +438,7 @@ impl ModuleInstanceInterface for ModuleInstance { function_reference.module.call_internal_function(function_context, function_reference.internal_index) } - fn execute_export(&self, name: &str, params: ExecutionParams) -> Result, Error> { + fn execute_export(&self, name: &str, params: ExecutionParams) -> Result, InterpreterError> { let index = self.exports.get(name) .ok_or(Error::Function(format!("missing executable export with name {}", name))) .and_then(|l| l.iter() @@ -494,7 +503,7 @@ impl ModuleInstanceInterface for ModuleInstance { } } - fn global<'a>(&self, index: ItemIndex, variable_type: Option, externals: Option<&'a HashMap>>) -> Result, Error> { + fn global<'a>(&self, index: ItemIndex, variable_type: Option, externals: Option<&'a HashMap + 'a>>>) -> Result, Error> { match self.imports.parse_global_index(index) { ItemIndex::IndexSpace(_) => unreachable!("parse_global_index resolves IndexSpace option"), ItemIndex::Internal(index) => self.globals.get(index as usize).cloned() @@ -533,7 +542,7 @@ impl ModuleInstanceInterface for ModuleInstance { .map(FunctionSignature::Module) } - fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap>>) -> Result, Error> { + fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap + 'a>>>) -> Result, Error> { match self.imports.parse_function_index(index) { ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"), ItemIndex::Internal(index) => Ok(InternalFunctionReference { @@ -555,7 +564,7 @@ impl ModuleInstanceInterface for ModuleInstance { } } - fn function_reference_indirect<'a>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'a HashMap>>) -> Result, Error> { + fn function_reference_indirect<'a>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'a HashMap + 'a>>>) -> Result, Error> { let table = self.table(ItemIndex::IndexSpace(table_idx))?; let (module, index) = match table.get(func_idx)? { RuntimeValue::AnyFunc(module, index) => (module.clone(), index), @@ -591,7 +600,7 @@ impl ModuleInstanceInterface for ModuleInstance { })) } - fn call_internal_function(&self, mut outer: CallerContext, index: u32) -> Result, Error> { + fn call_internal_function(&self, mut outer: CallerContext, index: u32) -> Result, InterpreterError> { let function_type = self.function_type(ItemIndex::Internal(index))?; let args = prepare_function_args(&function_type, outer.value_stack)?; let function_ref = InternalFunctionReference { module: self.self_ref(Some(outer.externals))?, internal_index: index }; @@ -600,9 +609,9 @@ impl ModuleInstanceInterface for ModuleInstance { } } -impl<'a> CallerContext<'a> { +impl<'a, E> CallerContext<'a, E> where E: CustomUserError { /// Top most args - pub fn topmost(args: &'a mut StackWithLimit, externals: &'a HashMap>) -> Self { + pub fn topmost(args: &'a mut StackWithLimit, externals: &'a HashMap + 'a>>) -> Self { CallerContext { value_stack_limit: DEFAULT_VALUE_STACK_LIMIT, frame_stack_limit: DEFAULT_FRAME_STACK_LIMIT, @@ -612,7 +621,7 @@ impl<'a> CallerContext<'a> { } /// Nested context - pub fn nested(outer: &'a mut FunctionContext) -> Self { + pub fn nested(outer: &'a mut FunctionContext) -> Self { CallerContext { value_stack_limit: outer.value_stack().limit() - outer.value_stack().len(), frame_stack_limit: outer.frame_stack().limit() - outer.frame_stack().len(), @@ -632,7 +641,7 @@ pub fn check_limits(limits: &ResizableLimits) -> Result<(), Error> { Ok(()) } -fn get_initializer(expr: &InitExpr, module: &Module, imports: &ModuleImports, expected_type: VariableType) -> Result { +fn get_initializer(expr: &InitExpr, module: &Module, imports: &ModuleImports, expected_type: VariableType) -> Result { let first_opcode = match expr.code().len() { 1 => &expr.code()[0], 2 if expr.code().len() == 2 && expr.code()[1] == Opcode::End => &expr.code()[0], diff --git a/src/interpreter/program.rs b/src/interpreter/program.rs index 42b89db..01375fe 100644 --- a/src/interpreter/program.rs +++ b/src/interpreter/program.rs @@ -2,23 +2,23 @@ use std::sync::Arc; use std::collections::HashMap; use parking_lot::RwLock; use elements::Module; -use interpreter::Error; +use interpreter::{Error, CustomUserError, InterpreterError}; use interpreter::env::{self, env_module}; use interpreter::module::{ModuleInstance, ModuleInstanceInterface}; /// Program instance. Program is a set of instantiated modules. -pub struct ProgramInstance { +pub struct ProgramInstance { /// Shared data reference. - essence: Arc, + essence: Arc>, } /// Program instance essence. -pub struct ProgramInstanceEssence { +pub struct ProgramInstanceEssence { /// Loaded modules. - modules: RwLock>>, + modules: RwLock>>>, } -impl ProgramInstance { +impl ProgramInstance where E: CustomUserError { /// Create new program instance. pub fn new() -> Result { ProgramInstance::with_env_params(env::EnvParams::default()) @@ -32,7 +32,7 @@ impl ProgramInstance { } /// Instantiate module with validation. - pub fn add_module<'a>(&self, name: &str, module: Module, externals: Option<&'a HashMap>>) -> Result, Error> { + pub fn add_module<'a>(&self, name: &str, module: Module, externals: Option<&'a HashMap + 'a>>>) -> Result>, InterpreterError> { let mut module_instance = ModuleInstance::new(Arc::downgrade(&self.essence), name.into(), module)?; module_instance.instantiate(externals)?; @@ -43,19 +43,19 @@ impl ProgramInstance { } /// Insert instantiated module. - pub fn insert_loaded_module(&self, name: &str, module_instance: Arc) -> Result, Error> { + pub fn insert_loaded_module(&self, name: &str, module_instance: Arc>) -> Result>, Error> { // replace existing module with the same name with new one self.essence.modules.write().insert(name.into(), module_instance.clone()); Ok(module_instance) } /// Get one of the modules by name - pub fn module(&self, name: &str) -> Option> { + pub fn module(&self, name: &str) -> Option>> { self.essence.module(name) } } -impl ProgramInstanceEssence { +impl ProgramInstanceEssence where E: CustomUserError { /// Create new program essence. pub fn new() -> Result { ProgramInstanceEssence::with_env_params(env::EnvParams::default()) @@ -63,7 +63,7 @@ impl ProgramInstanceEssence { pub fn with_env_params(env_params: env::EnvParams) -> Result { let mut modules = HashMap::new(); - let env_module: Arc = Arc::new(env_module(env_params)?); + let env_module: Arc> = Arc::new(env_module(env_params)?); modules.insert("env".into(), env_module); Ok(ProgramInstanceEssence { modules: RwLock::new(modules), @@ -71,7 +71,7 @@ impl ProgramInstanceEssence { } /// Get module reference. - pub fn module(&self, name: &str) -> Option> { + pub fn module(&self, name: &str) -> Option>> { self.modules.read().get(name).cloned() } } diff --git a/src/interpreter/runner.rs b/src/interpreter/runner.rs index 906e48f..7e12c9d 100644 --- a/src/interpreter/runner.rs +++ b/src/interpreter/runner.rs @@ -6,7 +6,7 @@ use std::fmt::{self, Display}; use std::iter::repeat; use std::collections::{HashMap, VecDeque}; use elements::{Opcode, BlockType, Local}; -use interpreter::Error; +use interpreter::{Error, CustomUserError, InterpreterError}; use interpreter::module::{ModuleInstanceInterface, CallerContext, ItemIndex, InternalFunctionReference, FunctionSignature}; use interpreter::stack::StackWithLimit; use interpreter::value::{ @@ -22,16 +22,18 @@ pub const DEFAULT_MEMORY_INDEX: u32 = 0; pub const DEFAULT_TABLE_INDEX: u32 = 0; /// Function interpreter. -pub struct Interpreter; +pub struct Interpreter { + _dummy: ::std::marker::PhantomData, +} /// Function execution context. -pub struct FunctionContext<'a> { +pub struct FunctionContext<'a, E: 'a + CustomUserError> { /// Is context initialized. pub is_initialized: bool, /// Internal function reference. - pub function: InternalFunctionReference<'a>, + pub function: InternalFunctionReference<'a, E>, /// Execution-local external modules. - pub externals: &'a HashMap>, + pub externals: &'a HashMap + 'a>>, /// Function return type. pub return_type: BlockType, /// Local variables. @@ -46,13 +48,13 @@ pub struct FunctionContext<'a> { /// Interpreter action to execute after executing instruction. #[derive(Debug)] -pub enum InstructionOutcome<'a> { +pub enum InstructionOutcome<'a, E: CustomUserError> { /// Continue with next instruction. RunNextInstruction, /// Branch to given frame. Branch(usize), /// Execute function call. - ExecuteCall(InternalFunctionReference<'a>), + ExecuteCall(InternalFunctionReference<'a, E>), /// End current frame. End, /// Return from current function block. @@ -60,15 +62,15 @@ pub enum InstructionOutcome<'a> { } /// Function run result. -enum RunResult<'a> { +enum RunResult<'a, E: 'a + CustomUserError> { /// Function has returned (optional) value. Return(Option), /// Function is calling other function. - NestedCall(FunctionContext<'a>), + NestedCall(FunctionContext<'a, E>), } -impl Interpreter { - pub fn run_function(function_context: FunctionContext) -> Result, Error> { +impl Interpreter where E: CustomUserError { + pub fn run_function(function_context: FunctionContext) -> Result, InterpreterError> { let mut function_stack = VecDeque::new(); function_stack.push_back(function_context); @@ -118,7 +120,7 @@ impl Interpreter { } } - fn do_run_function<'a>(function_context: &mut FunctionContext<'a>, function_body: &[Opcode], function_labels: &HashMap) -> Result, Error> { + fn do_run_function<'a>(function_context: &mut FunctionContext<'a, E>, function_body: &[Opcode], function_labels: &HashMap) -> Result, Error> { loop { let instruction = &function_body[function_context.position]; @@ -156,7 +158,7 @@ impl Interpreter { })) } - fn run_instruction<'a>(context: &mut FunctionContext<'a>, labels: &HashMap, opcode: &Opcode) -> Result, Error> { + fn run_instruction<'a>(context: &mut FunctionContext<'a, E>, labels: &HashMap, opcode: &Opcode) -> Result, Error> { match opcode { &Opcode::Unreachable => Interpreter::run_unreachable(context), &Opcode::Nop => Interpreter::run_nop(context), @@ -350,25 +352,25 @@ impl Interpreter { } } - fn run_unreachable<'a>(_context: &mut FunctionContext) -> Result, Error> { + fn run_unreachable<'a>(_context: &mut FunctionContext) -> Result, Error> { Err(Error::Trap("programmatic".into())) } - fn run_nop<'a>(_context: &mut FunctionContext) -> Result, Error> { + fn run_nop<'a>(_context: &mut FunctionContext) -> Result, Error> { Ok(InstructionOutcome::RunNextInstruction) } - fn run_block<'a>(context: &mut FunctionContext<'a>, labels: &HashMap, block_type: BlockType) -> Result, Error> { + fn run_block<'a>(context: &mut FunctionContext<'a, E>, labels: &HashMap, block_type: BlockType) -> Result, Error> { context.push_frame(labels, BlockFrameType::Block, block_type)?; Ok(InstructionOutcome::RunNextInstruction) } - fn run_loop<'a>(context: &mut FunctionContext<'a>, labels: &HashMap, block_type: BlockType) -> Result, Error> { + fn run_loop<'a>(context: &mut FunctionContext<'a, E>, labels: &HashMap, block_type: BlockType) -> Result, Error> { context.push_frame(labels, BlockFrameType::Loop, block_type)?; Ok(InstructionOutcome::RunNextInstruction) } - fn run_if<'a>(context: &mut FunctionContext<'a>, labels: &HashMap, block_type: BlockType) -> Result, Error> { + fn run_if<'a>(context: &mut FunctionContext<'a, E>, labels: &HashMap, block_type: BlockType) -> Result, Error> { let branch = context.value_stack_mut().pop_as()?; let block_frame_type = if branch { BlockFrameType::IfTrue } else { let else_pos = labels[&context.position]; @@ -383,23 +385,23 @@ impl Interpreter { context.push_frame(labels, block_frame_type, block_type).map(|_| InstructionOutcome::RunNextInstruction) } - fn run_else<'a>(context: &mut FunctionContext, labels: &HashMap) -> Result, Error> { + fn run_else<'a>(context: &mut FunctionContext, labels: &HashMap) -> Result, Error> { let end_pos = labels[&context.position]; context.pop_frame(false)?; context.position = end_pos; Ok(InstructionOutcome::RunNextInstruction) } - fn run_end<'a>(context: &mut FunctionContext) -> Result, Error> { + fn run_end<'a>(context: &mut FunctionContext) -> Result, Error> { context.pop_frame(false)?; Ok(InstructionOutcome::End) } - fn run_br<'a>(_context: &mut FunctionContext, label_idx: u32) -> Result, Error> { + fn run_br<'a>(_context: &mut FunctionContext, label_idx: u32) -> Result, Error> { Ok(InstructionOutcome::Branch(label_idx as usize)) } - fn run_br_if<'a>(context: &mut FunctionContext, label_idx: u32) -> Result, Error> { + fn run_br_if<'a>(context: &mut FunctionContext, label_idx: u32) -> Result, Error> { if context.value_stack_mut().pop_as()? { Ok(InstructionOutcome::Branch(label_idx as usize)) } else { @@ -407,20 +409,20 @@ impl Interpreter { } } - fn run_br_table<'a>(context: &mut FunctionContext, table: &Vec, default: u32) -> Result, Error> { + fn run_br_table<'a>(context: &mut FunctionContext, table: &Vec, default: u32) -> Result, Error> { let index: u32 = context.value_stack_mut().pop_as()?; Ok(InstructionOutcome::Branch(table.get(index as usize).cloned().unwrap_or(default) as usize)) } - fn run_return<'a>(_context: &mut FunctionContext) -> Result, Error> { + fn run_return<'a>(_context: &mut FunctionContext) -> Result, Error> { Ok(InstructionOutcome::Return) } - fn run_call<'a>(context: &mut FunctionContext<'a>, func_idx: u32) -> Result, Error> { + fn run_call<'a>(context: &mut FunctionContext<'a, E>, func_idx: u32) -> Result, Error> { Ok(InstructionOutcome::ExecuteCall(context.module().function_reference(ItemIndex::IndexSpace(func_idx), Some(context.externals))?)) } - fn run_call_indirect<'a>(context: &mut FunctionContext<'a>, type_idx: u32) -> Result, Error> { + fn run_call_indirect<'a>(context: &mut FunctionContext<'a, E>, type_idx: u32) -> Result, Error> { let table_func_idx: u32 = context.value_stack_mut().pop_as()?; let function_reference = context.module().function_reference_indirect(DEFAULT_TABLE_INDEX, type_idx, table_func_idx, Some(context.externals))?; { @@ -435,14 +437,14 @@ impl Interpreter { Ok(InstructionOutcome::ExecuteCall(function_reference)) } - fn run_drop<'a>(context: &mut FunctionContext) -> Result, Error> { + fn run_drop<'a>(context: &mut FunctionContext) -> Result, Error> { context .value_stack_mut() .pop() .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_select<'a>(context: &mut FunctionContext) -> Result, Error> { + fn run_select<'a>(context: &mut FunctionContext) -> Result, Error> { context .value_stack_mut() .pop_triple() @@ -457,32 +459,32 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_get_local<'a>(context: &mut FunctionContext, index: u32) -> Result, Error> { + fn run_get_local<'a>(context: &mut FunctionContext, index: u32) -> Result, Error> { context.get_local(index as usize) .map(|value| context.value_stack_mut().push(value)) .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_set_local<'a>(context: &mut FunctionContext, index: u32) -> Result, Error> { + fn run_set_local<'a>(context: &mut FunctionContext, index: u32) -> Result, Error> { let arg = context.value_stack_mut().pop()?; context.set_local(index as usize, arg) .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_tee_local<'a>(context: &mut FunctionContext, index: u32) -> Result, Error> { + fn run_tee_local<'a>(context: &mut FunctionContext, index: u32) -> Result, Error> { let arg = context.value_stack().top()?.clone(); context.set_local(index as usize, arg) .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_get_global<'a>(context: &mut FunctionContext, index: u32) -> Result, Error> { + fn run_get_global<'a>(context: &mut FunctionContext, index: u32) -> Result, Error> { context.module() .global(ItemIndex::IndexSpace(index), None, Some(context.externals)) .and_then(|g| context.value_stack_mut().push(g.get())) .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_set_global<'a>(context: &mut FunctionContext, index: u32) -> Result, Error> { + fn run_set_global<'a>(context: &mut FunctionContext, index: u32) -> Result, Error> { context .value_stack_mut() .pop() @@ -490,7 +492,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_load<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result, Error> + fn run_load<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result, Error> where RuntimeValue: From, T: LittleEndianConvert { let address = effective_address(offset, context.value_stack_mut().pop_as()?)?; context.module() @@ -501,7 +503,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_load_extend<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result, Error> + fn run_load_extend<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result, Error> where T: ExtendInto, RuntimeValue: From, T: LittleEndianConvert { let address = effective_address(offset, context.value_stack_mut().pop_as()?)?; let stack_value: U = context.module() @@ -515,7 +517,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_store<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result, Error> + fn run_store<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result, Error> where RuntimeValue: TryInto, T: LittleEndianConvert { let stack_value = context .value_stack_mut() @@ -528,7 +530,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_store_wrap<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result, Error> + fn run_store_wrap<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result, Error> where RuntimeValue: TryInto, T: WrapInto, U: LittleEndianConvert { let stack_value: T = context.value_stack_mut().pop().and_then(|v| v.try_into())?; let stack_value = stack_value.wrap_into().into_little_endian(); @@ -539,7 +541,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_current_memory<'a>(context: &mut FunctionContext) -> Result, Error> { + fn run_current_memory<'a>(context: &mut FunctionContext) -> Result, Error> { context.module() .memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX)) .map(|m| m.size()) @@ -547,7 +549,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_grow_memory<'a>(context: &mut FunctionContext) -> Result, Error> { + fn run_grow_memory<'a>(context: &mut FunctionContext) -> Result, Error> { let pages: u32 = context.value_stack_mut().pop_as()?; context.module() .memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX)) @@ -556,14 +558,14 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_const<'a>(context: &mut FunctionContext, val: RuntimeValue) -> Result, Error> { + fn run_const<'a>(context: &mut FunctionContext, val: RuntimeValue) -> Result, Error> { context .value_stack_mut() .push(val) .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_eqz<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_eqz<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: TryInto, T: PartialEq + Default { context .value_stack_mut() @@ -573,7 +575,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_eq<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_eq<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: TryInto, T: PartialEq { context .value_stack_mut() @@ -583,7 +585,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_ne<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_ne<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: TryInto, T: PartialEq { context .value_stack_mut() @@ -593,7 +595,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_lt<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_lt<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: TryInto, T: PartialOrd + Display { context .value_stack_mut() @@ -603,7 +605,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_gt<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_gt<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: TryInto, T: PartialOrd { context .value_stack_mut() @@ -613,7 +615,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_lte<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_lte<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: TryInto, T: PartialOrd { context .value_stack_mut() @@ -623,7 +625,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_gte<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_gte<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: TryInto, T: PartialOrd { context .value_stack_mut() @@ -633,7 +635,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_clz<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_clz<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Integer { context .value_stack_mut() @@ -643,7 +645,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_ctz<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_ctz<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Integer { context .value_stack_mut() @@ -653,7 +655,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_popcnt<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_popcnt<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Integer { context .value_stack_mut() @@ -663,7 +665,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_add<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_add<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: ArithmeticOps { context .value_stack_mut() @@ -673,7 +675,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_sub<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_sub<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: ArithmeticOps { context .value_stack_mut() @@ -683,7 +685,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_mul<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_mul<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: ArithmeticOps { context .value_stack_mut() @@ -693,7 +695,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_div<'a, T, U>(context: &mut FunctionContext) -> Result, Error> + fn run_div<'a, T, U>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: TransmuteInto + Display, U: ArithmeticOps + TransmuteInto { context .value_stack_mut() @@ -705,7 +707,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_rem<'a, T, U>(context: &mut FunctionContext) -> Result, Error> + fn run_rem<'a, T, U>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: TransmuteInto, U: Integer + TransmuteInto { context .value_stack_mut() @@ -717,7 +719,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_and<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_and<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From<::Output> + TryInto, T: ops::BitAnd { context .value_stack_mut() @@ -727,7 +729,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_or<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_or<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From<::Output> + TryInto, T: ops::BitOr { context .value_stack_mut() @@ -737,7 +739,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_xor<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_xor<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From<::Output> + TryInto, T: ops::BitXor { context .value_stack_mut() @@ -747,7 +749,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_shl<'a, T>(context: &mut FunctionContext, mask: T) -> Result, Error> + fn run_shl<'a, T>(context: &mut FunctionContext, mask: T) -> Result, Error> where RuntimeValue: From<>::Output> + TryInto, T: ops::Shl + ops::BitAnd { context .value_stack_mut() @@ -757,7 +759,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_shr<'a, T, U>(context: &mut FunctionContext, mask: U) -> Result, Error> + fn run_shr<'a, T, U>(context: &mut FunctionContext, mask: U) -> Result, Error> where RuntimeValue: From + TryInto, T: TransmuteInto, U: ops::Shr + ops::BitAnd, >::Output: TransmuteInto { context .value_stack_mut() @@ -769,7 +771,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_rotl<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_rotl<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Integer { context .value_stack_mut() @@ -779,7 +781,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_rotr<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_rotr<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Integer { context .value_stack_mut() @@ -789,7 +791,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_abs<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_abs<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -799,7 +801,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_neg<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_neg<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From<::Output> + TryInto, T: ops::Neg { context .value_stack_mut() @@ -809,7 +811,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_ceil<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_ceil<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -819,7 +821,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_floor<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_floor<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -829,7 +831,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_trunc<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_trunc<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -839,7 +841,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_nearest<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_nearest<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -849,7 +851,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_sqrt<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_sqrt<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -859,7 +861,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_min<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_min<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -869,7 +871,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_max<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_max<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -879,7 +881,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_copysign<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_copysign<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -889,7 +891,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_wrap<'a, T, U>(context: &mut FunctionContext) -> Result, Error> + fn run_wrap<'a, T, U>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: WrapInto { context .value_stack_mut() @@ -899,7 +901,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_trunc_to_int<'a, T, U, V>(context: &mut FunctionContext) -> Result, Error> + fn run_trunc_to_int<'a, T, U, V>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: TryTruncateInto, U: TransmuteInto, { context .value_stack_mut() @@ -910,7 +912,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_extend<'a, T, U, V>(context: &mut FunctionContext) -> Result, Error> + fn run_extend<'a, T, U, V>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: ExtendInto, U: TransmuteInto { context .value_stack_mut() @@ -921,7 +923,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_reinterpret<'a, T, U>(context: &mut FunctionContext) -> Result, Error> + fn run_reinterpret<'a, T, U>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From, RuntimeValue: TryInto, T: TransmuteInto { context .value_stack_mut() @@ -932,8 +934,8 @@ impl Interpreter { } } -impl<'a> FunctionContext<'a> { - pub fn new(function: InternalFunctionReference<'a>, externals: &'a HashMap>, value_stack_limit: usize, frame_stack_limit: usize, function_type: &FunctionSignature, args: Vec) -> Self { +impl<'a, E> FunctionContext<'a, E> where E: CustomUserError { + pub fn new(function: InternalFunctionReference<'a, E>, externals: &'a HashMap + 'a>>, value_stack_limit: usize, frame_stack_limit: usize, function_type: &FunctionSignature, args: Vec) -> Self { FunctionContext { is_initialized: false, function: function, @@ -946,7 +948,7 @@ impl<'a> FunctionContext<'a> { } } - pub fn nested(&mut self, function: InternalFunctionReference<'a>) -> Result { + pub fn nested(&mut self, function: InternalFunctionReference<'a, E>) -> Result { let (function_locals, function_return_type) = { let function_type = function.module.function_type(ItemIndex::Internal(function.internal_index))?; let function_return_type = function_type.return_type().map(|vt| BlockType::Value(vt)).unwrap_or(BlockType::NoResult); @@ -982,15 +984,15 @@ impl<'a> FunctionContext<'a> { Ok(()) } - pub fn module(&self) -> &Arc { + pub fn module(&self) -> &Arc + 'a> { &self.function.module } - pub fn externals(&self) -> &HashMap> { + pub fn externals(&self) -> &HashMap + 'a>> { &self.externals } - pub fn set_local(&mut self, index: usize, value: RuntimeValue) -> Result, Error> { + pub fn set_local(&mut self, index: usize, value: RuntimeValue) -> Result, Error> { self.locals.get_mut(index) .ok_or(Error::Local(format!("expected to have local with index {}", index))) .and_then(|l| l.set(value)) @@ -1072,7 +1074,7 @@ impl<'a> FunctionContext<'a> { } } -impl<'a> fmt::Debug for FunctionContext<'a> { +impl<'a, E> fmt::Debug for FunctionContext<'a, E> where E: CustomUserError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "FunctionContext") } diff --git a/src/interpreter/tests/basics.rs b/src/interpreter/tests/basics.rs index 30f79c4..b474ea2 100644 --- a/src/interpreter/tests/basics.rs +++ b/src/interpreter/tests/basics.rs @@ -5,11 +5,10 @@ use std::collections::HashMap; use builder::module; use elements::{ExportEntry, Internal, ImportEntry, External, GlobalEntry, GlobalType, InitExpr, ValueType, BlockType, Opcodes, Opcode, FunctionType}; -use interpreter::Error; +use interpreter::{Error, CustomUserError, DummyCustomUserError, InterpreterError, ProgramInstance, ModuleInstance, CustomProgramInstance}; use interpreter::env_native::{env_native_module, UserDefinedElements, UserFunctionExecutor, UserFunctionDescriptor}; use interpreter::memory::MemoryInstance; -use interpreter::module::{ModuleInstance, ModuleInstanceInterface, CallerContext, ItemIndex, ExecutionParams, ExportEntryType, FunctionSignature}; -use interpreter::program::ProgramInstance; +use interpreter::module::{ModuleInstanceInterface, CallerContext, ItemIndex, ExecutionParams, ExportEntryType, FunctionSignature}; use interpreter::validator::{FunctionValidationContext, Validator}; use interpreter::value::{RuntimeValue, TryInto}; use interpreter::variable::{VariableInstance, ExternalVariableValue, VariableType}; @@ -115,6 +114,11 @@ const SIGNATURES: &'static [UserFunctionDescriptor] = &[ SIGNATURE_I32_I32, Some(ValueType::I32), ), + UserFunctionDescriptor::Static( + "err", + SIGNATURE_I32_I32, + Some(ValueType::I32), + ), ]; const NO_SIGNATURES: &'static [UserFunctionDescriptor] = &[]; @@ -135,14 +139,28 @@ impl ExternalVariableValue for MeasuredVariable { } } +// custom user error +#[derive(Debug, Clone, PartialEq)] +struct UserError { + error_code: i32, +} + +impl ::std::fmt::Display for UserError { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + write!(f, "{}", self.error_code) + } +} + +impl CustomUserError for UserError {} + // user function executor struct FunctionExecutor { pub memory: Arc, pub values: Vec, } -impl UserFunctionExecutor for FunctionExecutor { - fn execute(&mut self, name: &str, context: CallerContext) -> Result, Error> { +impl UserFunctionExecutor for FunctionExecutor { + fn execute(&mut self, name: &str, context: CallerContext) -> Result, InterpreterError> { match name { "add" => { let memory_value = self.memory.get(0, 1).unwrap()[0]; @@ -166,7 +184,10 @@ impl UserFunctionExecutor for FunctionExecutor { self.values.push(diff as i32); Ok(Some(RuntimeValue::I32(diff as i32))) }, - _ => Err(Error::Trap("not implemented".into())), + "err" => { + Err(InterpreterError::User(UserError { error_code: 777 })) + }, + _ => Err(Error::Trap("not implemented".into()).into()), } } } @@ -174,7 +195,7 @@ impl UserFunctionExecutor for FunctionExecutor { #[test] fn native_env_function() { // create new program - let program = ProgramInstance::new().unwrap(); + let program = CustomProgramInstance::new().unwrap(); // => env module is created let env_instance = program.module("env").unwrap(); // => linear memory is created @@ -186,7 +207,7 @@ fn native_env_function() { values: Vec::new(), }; { - let functions: UserDefinedElements = UserDefinedElements { + let functions = UserDefinedElements { executor: Some(&mut executor), globals: HashMap::new(), functions: ::std::borrow::Cow::from(SIGNATURES), @@ -282,6 +303,40 @@ fn native_env_global() { } } +#[test] +fn native_custom_error() { + let program = CustomProgramInstance::new().unwrap(); + let env_instance = program.module("env").unwrap(); + let env_memory = env_instance.memory(ItemIndex::Internal(0)).unwrap(); + let mut executor = FunctionExecutor { memory: env_memory.clone(), values: Vec::new() }; + let functions = UserDefinedElements { + executor: Some(&mut executor), + globals: HashMap::new(), + functions: ::std::borrow::Cow::from(SIGNATURES), + }; + let native_env_instance = Arc::new(env_native_module(env_instance, functions).unwrap()); + let params = ExecutionParams::with_external("env".into(), native_env_instance); + + let module = module() + .with_import(ImportEntry::new("env".into(), "err".into(), External::Function(0))) + .function() + .signature().param().i32().param().i32().return_type().i32().build() + .body().with_opcodes(Opcodes::new(vec![ + Opcode::GetLocal(0), + Opcode::GetLocal(1), + Opcode::Call(0), + Opcode::End, + ])).build() + .build() + .build(); + + let module_instance = program.add_module("main", module, Some(¶ms.externals)).unwrap(); + assert_eq!(module_instance.execute_index(0, params.clone().add_argument(RuntimeValue::I32(7)).add_argument(RuntimeValue::I32(0))), + Err(InterpreterError::User(UserError { error_code: 777 }))); + assert_eq!(module_instance.execute_index(1, params.clone().add_argument(RuntimeValue::I32(7)).add_argument(RuntimeValue::I32(0))), + Err(InterpreterError::User(UserError { error_code: 777 }))); +} + #[test] fn import_env_mutable_global() { let program = ProgramInstance::new().unwrap(); @@ -295,7 +350,7 @@ fn import_env_mutable_global() { #[test] fn env_native_export_entry_type_check() { - let program = ProgramInstance::new().unwrap(); + let program = CustomProgramInstance::new().unwrap(); let mut function_executor = FunctionExecutor { memory: program.module("env").unwrap().memory(ItemIndex::Internal(0)).unwrap(), values: Vec::new(), diff --git a/src/interpreter/tests/wabt.rs b/src/interpreter/tests/wabt.rs index 1244c74..576f49c 100644 --- a/src/interpreter/tests/wabt.rs +++ b/src/interpreter/tests/wabt.rs @@ -3,9 +3,7 @@ use std::sync::Arc; use builder::module; use elements::{ValueType, Opcodes, Opcode, BlockType, Local}; -use interpreter::Error; -use interpreter::module::{ModuleInstanceInterface, ItemIndex}; -use interpreter::program::ProgramInstance; +use interpreter::{Error, InterpreterError, ProgramInstance, ModuleInstanceInterface, CustomModuleInstanceInterface, ItemIndex}; use interpreter::value::{RuntimeValue, TryInto}; fn make_function_i32(body: Opcodes) -> (ProgramInstance, Arc) { @@ -28,6 +26,10 @@ fn run_function_i32(module: &Arc, arg: i32) -> Result e, + _ => unreachable!(), + }) } /// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/unreachable.txt @@ -733,9 +735,9 @@ fn callindirect_2() { assert_eq!(module.execute_index(3, vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(0)].into()).unwrap().unwrap(), RuntimeValue::I32(14)); assert_eq!(module.execute_index(3, vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(1)].into()).unwrap().unwrap(), RuntimeValue::I32(6)); assert_eq!(module.execute_index(3, vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(2)].into()).unwrap_err(), - Error::Function("expected indirect function with signature ([I32, I32]) -> Some(I32) when got with ([I32]) -> Some(I32)".into())); + InterpreterError::Internal(Error::Function("expected indirect function with signature ([I32, I32]) -> Some(I32) when got with ([I32]) -> Some(I32)".into()))); assert_eq!(module.execute_index(3, vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(3)].into()).unwrap_err(), - Error::Table("trying to read table item with index 3 when there are only 3 items".into())); + InterpreterError::Internal(Error::Table("trying to read table item with index 3 when there are only 3 items".into()))); } /// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/select.txt diff --git a/src/interpreter/tests/wasm.rs b/src/interpreter/tests/wasm.rs index a005726..a5f9219 100644 --- a/src/interpreter/tests/wasm.rs +++ b/src/interpreter/tests/wasm.rs @@ -1,9 +1,7 @@ use elements::deserialize_file; use elements::Module; -use interpreter::EnvParams; -use interpreter::ExecutionParams; +use interpreter::{EnvParams, ExecutionParams, ProgramInstance}; use interpreter::module::ModuleInstanceInterface; -use interpreter::program::ProgramInstance; use interpreter::value::RuntimeValue; // Name of function contained in WASM file (note the leading underline) diff --git a/src/interpreter/validator.rs b/src/interpreter/validator.rs index 43f411b..bef362d 100644 --- a/src/interpreter/validator.rs +++ b/src/interpreter/validator.rs @@ -2,7 +2,7 @@ use std::u32; use std::sync::Arc; use std::collections::HashMap; use elements::{Opcode, BlockType, ValueType}; -use interpreter::Error; +use interpreter::{Error, CustomUserError}; use interpreter::runner::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; use interpreter::module::{ModuleInstance, ModuleInstanceInterface, ItemIndex, FunctionSignature}; use interpreter::stack::StackWithLimit; @@ -12,11 +12,11 @@ use interpreter::variable::VariableType; const NATURAL_ALIGNMENT: u32 = 0xFFFFFFFF; /// Function validation context. -pub struct FunctionValidationContext<'a> { +pub struct FunctionValidationContext<'a, E: 'a + CustomUserError> { /// Wasm module instance (in process of instantiation). - module_instance: &'a ModuleInstance, + module_instance: &'a ModuleInstance, /// Native externals. - externals: Option<&'a HashMap>>, + externals: Option<&'a HashMap + 'a>>>, /// Current instruction position. position: usize, /// Local variables. @@ -75,7 +75,9 @@ pub enum BlockFrameType { } /// Function validator. -pub struct Validator; +pub struct Validator { + _dummy: ::std::marker::PhantomData, +} /// Instruction outcome. #[derive(Debug, Clone)] @@ -86,8 +88,8 @@ pub enum InstructionOutcome { Unreachable, } -impl Validator { - pub fn validate_function(context: &mut FunctionValidationContext, block_type: BlockType, body: &[Opcode]) -> Result<(), Error> { +impl Validator where E: CustomUserError { + pub fn validate_function(context: &mut FunctionValidationContext, block_type: BlockType, body: &[Opcode]) -> Result<(), Error> { context.push_label(BlockFrameType::Function, block_type)?; Validator::validate_function_block(context, body)?; while !context.frame_stack.is_empty() { @@ -97,7 +99,7 @@ impl Validator { Ok(()) } - fn validate_function_block(context: &mut FunctionValidationContext, body: &[Opcode]) -> Result<(), Error> { + fn validate_function_block(context: &mut FunctionValidationContext, body: &[Opcode]) -> Result<(), Error> { let body_len = body.len(); if body_len == 0 { return Err(Error::Validation("Non-empty function body expected".into())); @@ -117,7 +119,7 @@ impl Validator { } } - fn validate_instruction(context: &mut FunctionValidationContext, opcode: &Opcode) -> Result { + fn validate_instruction(context: &mut FunctionValidationContext, opcode: &Opcode) -> Result { debug!(target: "validator", "validating {:?}", opcode); match opcode { &Opcode::Unreachable => Ok(InstructionOutcome::Unreachable), @@ -312,49 +314,49 @@ impl Validator { } } - fn validate_const(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { + fn validate_const(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { context.push_value(value_type)?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_unop(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { + fn validate_unop(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { context.pop_value(value_type)?; context.push_value(value_type)?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_binop(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { + fn validate_binop(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { context.pop_value(value_type)?; context.pop_value(value_type)?; context.push_value(value_type)?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_testop(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { + fn validate_testop(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { context.pop_value(value_type)?; context.push_value(ValueType::I32.into())?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_relop(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { + fn validate_relop(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { context.pop_value(value_type)?; context.pop_value(value_type)?; context.push_value(ValueType::I32.into())?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_cvtop(context: &mut FunctionValidationContext, value_type1: StackValueType, value_type2: StackValueType) -> Result { + fn validate_cvtop(context: &mut FunctionValidationContext, value_type1: StackValueType, value_type2: StackValueType) -> Result { context.pop_value(value_type1)?; context.push_value(value_type2)?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_drop(context: &mut FunctionValidationContext) -> Result { + fn validate_drop(context: &mut FunctionValidationContext) -> Result { context.pop_any_value().map(|_| ())?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_select(context: &mut FunctionValidationContext) -> Result { + fn validate_select(context: &mut FunctionValidationContext) -> Result { context.pop_value(ValueType::I32.into())?; let select_type = context.pop_any_value()?; context.pop_value(select_type)?; @@ -362,13 +364,13 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_get_local(context: &mut FunctionValidationContext, index: u32) -> Result { + fn validate_get_local(context: &mut FunctionValidationContext, index: u32) -> Result { let local_type = context.require_local(index)?; context.push_value(local_type)?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_set_local(context: &mut FunctionValidationContext, index: u32) -> Result { + fn validate_set_local(context: &mut FunctionValidationContext, index: u32) -> Result { let local_type = context.require_local(index)?; let value_type = context.pop_any_value()?; if local_type != value_type { @@ -377,7 +379,7 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_tee_local(context: &mut FunctionValidationContext, index: u32) -> Result { + fn validate_tee_local(context: &mut FunctionValidationContext, index: u32) -> Result { let local_type = context.require_local(index)?; let value_type = context.tee_any_value()?; if local_type != value_type { @@ -386,13 +388,13 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_get_global(context: &mut FunctionValidationContext, index: u32) -> Result { + fn validate_get_global(context: &mut FunctionValidationContext, index: u32) -> Result { let global_type = context.require_global(index, None)?; context.push_value(global_type)?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_set_global(context: &mut FunctionValidationContext, index: u32) -> Result { + fn validate_set_global(context: &mut FunctionValidationContext, index: u32) -> Result { let global_type = context.require_global(index, Some(true))?; let value_type = context.pop_any_value()?; if global_type != value_type { @@ -401,7 +403,7 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_load(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: StackValueType) -> Result { + fn validate_load(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: StackValueType) -> Result { if align != NATURAL_ALIGNMENT { if 1u32.checked_shl(align).unwrap_or(u32::MAX) > max_align { return Err(Error::Validation(format!("Too large memory alignment 2^{} (expected at most {})", align, max_align))); @@ -414,7 +416,7 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_store(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: StackValueType) -> Result { + fn validate_store(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: StackValueType) -> Result { if align != NATURAL_ALIGNMENT { if 1u32.checked_shl(align).unwrap_or(u32::MAX) > max_align { return Err(Error::Validation(format!("Too large memory alignment 2^{} (expected at most {})", align, max_align))); @@ -427,20 +429,20 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_block(context: &mut FunctionValidationContext, block_type: BlockType) -> Result { + fn validate_block(context: &mut FunctionValidationContext, block_type: BlockType) -> Result { context.push_label(BlockFrameType::Block, block_type).map(|_| InstructionOutcome::ValidateNextInstruction) } - fn validate_loop(context: &mut FunctionValidationContext, block_type: BlockType) -> Result { + fn validate_loop(context: &mut FunctionValidationContext, block_type: BlockType) -> Result { context.push_label(BlockFrameType::Loop, block_type).map(|_| InstructionOutcome::ValidateNextInstruction) } - fn validate_if(context: &mut FunctionValidationContext, block_type: BlockType) -> Result { + fn validate_if(context: &mut FunctionValidationContext, block_type: BlockType) -> Result { context.pop_value(ValueType::I32.into())?; context.push_label(BlockFrameType::IfTrue, block_type).map(|_| InstructionOutcome::ValidateNextInstruction) } - fn validate_else(context: &mut FunctionValidationContext) -> Result { + fn validate_else(context: &mut FunctionValidationContext) -> Result { let block_type = { let top_frame = context.top_label()?; if top_frame.frame_type != BlockFrameType::IfTrue { @@ -456,7 +458,7 @@ impl Validator { context.push_label(BlockFrameType::IfFalse, block_type).map(|_| InstructionOutcome::ValidateNextInstruction) } - fn validate_end(context: &mut FunctionValidationContext) -> Result { + fn validate_end(context: &mut FunctionValidationContext) -> Result { { let top_frame = context.top_label()?; if top_frame.frame_type == BlockFrameType::IfTrue { @@ -469,7 +471,7 @@ impl Validator { context.pop_label().map(|_| InstructionOutcome::ValidateNextInstruction) } - fn validate_br(context: &mut FunctionValidationContext, idx: u32) -> Result { + fn validate_br(context: &mut FunctionValidationContext, idx: u32) -> Result { let (frame_type, frame_block_type) = { let frame = context.require_label(idx)?; (frame.frame_type, frame.block_type) @@ -483,7 +485,7 @@ impl Validator { Ok(InstructionOutcome::Unreachable) } - fn validate_br_if(context: &mut FunctionValidationContext, idx: u32) -> Result { + fn validate_br_if(context: &mut FunctionValidationContext, idx: u32) -> Result { context.pop_value(ValueType::I32.into())?; if let BlockType::Value(value_type) = context.require_label(idx)?.block_type { context.tee_value(value_type.into())?; @@ -491,7 +493,7 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_br_table(context: &mut FunctionValidationContext, table: &Vec, default: u32) -> Result { + fn validate_br_table(context: &mut FunctionValidationContext, table: &Vec, default: u32) -> Result { let mut required_block_type = None; { @@ -523,14 +525,14 @@ impl Validator { Ok(InstructionOutcome::Unreachable) } - fn validate_return(context: &mut FunctionValidationContext) -> Result { + fn validate_return(context: &mut FunctionValidationContext) -> Result { if let BlockType::Value(value_type) = context.return_type()? { context.tee_value(value_type.into())?; } Ok(InstructionOutcome::Unreachable) } - fn validate_call(context: &mut FunctionValidationContext, idx: u32) -> Result { + fn validate_call(context: &mut FunctionValidationContext, idx: u32) -> Result { let (argument_types, return_type) = context.require_function(idx)?; for argument_type in argument_types.iter().rev() { context.pop_value((*argument_type).into())?; @@ -541,7 +543,7 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_call_indirect(context: &mut FunctionValidationContext, idx: u32) -> Result { + fn validate_call_indirect(context: &mut FunctionValidationContext, idx: u32) -> Result { context.require_table(DEFAULT_TABLE_INDEX, VariableType::AnyFunc)?; context.pop_value(ValueType::I32.into())?; @@ -555,13 +557,13 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_current_memory(context: &mut FunctionValidationContext) -> Result { + fn validate_current_memory(context: &mut FunctionValidationContext) -> Result { context.require_memory(DEFAULT_MEMORY_INDEX)?; context.push_value(ValueType::I32.into())?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_grow_memory(context: &mut FunctionValidationContext) -> Result { + fn validate_grow_memory(context: &mut FunctionValidationContext) -> Result { context.require_memory(DEFAULT_MEMORY_INDEX)?; context.pop_value(ValueType::I32.into())?; context.push_value(ValueType::I32.into())?; @@ -569,10 +571,10 @@ impl Validator { } } -impl<'a> FunctionValidationContext<'a> { +impl<'a, E> FunctionValidationContext<'a, E> where E: CustomUserError { pub fn new( - module_instance: &'a ModuleInstance, - externals: Option<&'a HashMap>>, + module_instance: &'a ModuleInstance, + externals: Option<&'a HashMap + 'a>>>, locals: &'a [ValueType], value_stack_limit: usize, frame_stack_limit: usize, diff --git a/src/lib.rs b/src/lib.rs index 680de78..b6f5751 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,10 @@ pub use elements::{ pub use interpreter::{ ProgramInstance, + CustomProgramInstance, ModuleInstance, + CustomModuleInstance, ModuleInstanceInterface, + CustomModuleInstanceInterface, RuntimeValue, };