diff --git a/examples/interpret.rs b/examples/interpret.rs index fad4c51e3..b90e4d343 100644 --- a/examples/interpret.rs +++ b/examples/interpret.rs @@ -12,7 +12,7 @@ fn main() { return; } - let program = parity_wasm::ProgramInstance::with_env_params( + let program = parity_wasm::DefaultProgramInstance::with_env_params( interpreter::EnvParams { total_stack: 128*1024, total_memory: 2*1024*1024, diff --git a/examples/invoke.rs b/examples/invoke.rs index 22a47e1b4..b13dd4e5c 100644 --- a/examples/invoke.rs +++ b/examples/invoke.rs @@ -15,7 +15,7 @@ fn main() { let func_name = &args[2]; let (_, program_args) = args.split_at(3); - let program = parity_wasm::ProgramInstance::with_env_params( + let program = parity_wasm::DefaultProgramInstance::with_env_params( interpreter::EnvParams { total_stack: 128*1024, total_memory: 2*1024*1024, diff --git a/spec/src/run.rs b/spec/src/run.rs index f212bdb5f..73cdde9ae 100644 --- a/spec/src/run.rs +++ b/spec/src/run.rs @@ -11,9 +11,10 @@ use test; use parity_wasm::{self, elements, builder}; use parity_wasm::interpreter::{ RuntimeValue, - ProgramInstance, ModuleInstance, + DefaultProgramInstance, DefaultModuleInstance, ItemIndex, ExportEntryType, Error as InterpreterError, + DummyError as DummyInterpreterError, }; fn spec_test_module() -> elements::Module { @@ -41,7 +42,7 @@ fn spec_test_module() -> elements::Module { .build() } -fn load_module(base_dir: &str, path: &str, name: &Option, program: &ProgramInstance) -> Arc { +fn load_module(base_dir: &str, path: &str, name: &Option, program: &DefaultProgramInstance) -> Arc { let module = try_deserialize(base_dir, path).expect(&format!("Wasm file {} failed to load", path)); program.add_module("spectest", spec_test_module(), None).expect("Failed adding 'spectest' module"); @@ -57,9 +58,9 @@ fn try_deserialize(base_dir: &str, module_path: &str) -> Result Result<(), parity_wasm::interpreter::Error> { +fn try_load(base_dir: &str, module_path: &str) -> Result<(), DummyInterpreterError> { 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"); + let program = DefaultProgramInstance::new().expect("Failed creating program"); program.add_module("try_load", module, None).map(|_| ()) } @@ -89,8 +90,8 @@ fn runtime_values(test_vals: &[test::RuntimeValue]) -> Vec>() } -fn run_action(program: &ProgramInstance, action: &test::Action) - -> Result, InterpreterError> +fn run_action(program: &DefaultProgramInstance, action: &test::Action) + -> Result, DummyInterpreterError> { match *action { test::Action::Invoke { ref module, ref field, ref args } => { @@ -172,7 +173,7 @@ pub fn spec(name: &str) { .expect(&format!("Failed to load json file {}", &fixture.json)); let spec: test::Spec = serde_json::from_reader(&mut f).expect("Failed to deserialize JSON file"); - let program = ProgramInstance::new().expect("Failed creating program"); + let program = DefaultProgramInstance::new().expect("Failed creating program"); let mut last_module = None; for command in &spec.commands { println!("command {:?}", command); diff --git a/src/interpreter/env.rs b/src/interpreter/env.rs index 6748f2bb7..ce5906dfa 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, UserError}; use interpreter::env_native::NATIVE_INDEX_FUNC_MIN; use interpreter::module::{ModuleInstanceInterface, ModuleInstance, ExecutionParams, ItemIndex, CallerContext, ExportEntryType, InternalFunctionReference, InternalFunction, FunctionSignature}; @@ -78,13 +78,13 @@ pub struct EnvParams { pub allow_memory_growth: bool, } -pub struct EnvModuleInstance { +pub struct EnvModuleInstance { _params: EnvParams, - instance: ModuleInstance, + instance: ModuleInstance, } -impl EnvModuleInstance { - pub fn new(params: EnvParams, module: Module) -> Result { +impl EnvModuleInstance where E: UserError { + pub fn new(params: EnvParams, module: Module) -> Result> { let mut instance = ModuleInstance::new(Weak::default(), "env".into(), module)?; instance.instantiate(None)?; @@ -95,57 +95,58 @@ impl EnvModuleInstance { } } -impl ModuleInstanceInterface for EnvModuleInstance { - fn execute_index(&self, index: u32, params: ExecutionParams) -> Result, Error> { +impl ModuleInstanceInterface for EnvModuleInstance where E: UserError { + fn execute_index(&self, index: u32, params: ExecutionParams) -> Result, Error> { 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, Error> { self.instance.execute_export(name, params) } - fn export_entry<'a>(&self, name: &str, required_type: &ExportEntryType) -> Result { + fn export_entry<'a>(&self, name: &str, required_type: &ExportEntryType) -> Result> { self.instance.export_entry(name, required_type) } - fn table(&self, index: ItemIndex) -> Result, Error> { + fn table(&self, index: ItemIndex) -> Result>, Error> { self.instance.table(index) } - fn memory(&self, index: ItemIndex) -> Result, Error> { + fn memory(&self, index: ItemIndex) -> Result>, Error> { 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) } - fn function_type(&self, function_index: ItemIndex) -> Result { + fn function_type(&self, function_index: ItemIndex) -> Result> { self.instance.function_type(function_index) } - fn function_type_by_index(&self, type_index: u32) -> Result { + fn function_type_by_index(&self, type_index: u32) -> Result> { 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) } - fn function_body<'a>(&'a self, _internal_index: u32) -> Result>, Error> { + fn function_body<'a>(&'a self, _internal_index: u32) -> Result>, Error> { Ok(None) } - fn call_internal_function(&self, outer: CallerContext, index: u32) -> Result, Error> { + fn call_internal_function(&self, outer: CallerContext, index: u32) -> Result, Error> { // 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 921067fd4..ecde8c3b8 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, UserError}; 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, Error>; } /// 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 + UserError> { /// User globals list. - pub globals: HashMap>, + 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 + UserError> { /// 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. @@ -90,12 +90,12 @@ pub struct NativeModuleInstance<'a> { /// By-name functions index. globals_by_name: HashMap, /// User globals list. - globals: Vec>, + globals: Vec>>, } -impl<'a> NativeModuleInstance<'a> { +impl<'a, E> NativeModuleInstance<'a, E> where E: UserError { /// 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,16 +111,16 @@ 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: UserError { + fn execute_index(&self, index: u32, params: ExecutionParams) -> Result, Error> { 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, Error> { self.env.execute_export(name, params) } - fn export_entry<'b>(&self, name: &str, required_type: &ExportEntryType) -> Result { + fn export_entry<'b>(&self, name: &str, required_type: &ExportEntryType) -> Result> { if let Some(index) = self.functions_by_name.get(name) { let composite_index = NATIVE_INDEX_FUNC_MIN + *index; match required_type { @@ -147,15 +147,15 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { self.env.export_entry(name, required_type) } - fn table(&self, index: ItemIndex) -> Result, Error> { + fn table(&self, index: ItemIndex) -> Result>, Error> { self.env.table(index) } - fn memory(&self, index: ItemIndex) -> Result, Error> { + fn memory(&self, index: ItemIndex) -> Result>, Error> { 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"), @@ -171,7 +171,7 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { .ok_or(Error::Native(format!("trying to get native global with index {}", index))) } - fn function_type(&self, function_index: ItemIndex) -> Result { + fn function_type(&self, function_index: ItemIndex) -> Result> { let index = match function_index { ItemIndex::IndexSpace(index) | ItemIndex::Internal(index) => index, ItemIndex::External(_) => unreachable!("trying to call function, exported by native env module"), @@ -186,30 +186,30 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { .ok_or(Error::Native(format!("missing native env function with index {}", index)))?)) } - fn function_type_by_index(&self, type_index: u32) -> Result { + fn function_type_by_index(&self, type_index: u32) -> Result> { 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) } - fn function_body<'b>(&'b self, _internal_index: u32) -> Result>, Error> { + fn function_body<'b>(&'b self, _internal_index: u32) -> Result>, Error> { Ok(None) } - fn call_internal_function(&self, outer: CallerContext, index: u32) -> Result, Error> { + fn call_internal_function(&self, outer: CallerContext, index: u32) -> Result, Error> { 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: UserError>(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 7243e279e..b68c86fa9 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, UserError}; 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: UserError { /// 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/memory.rs b/src/interpreter/memory.rs index c6a9a0d5c..4934ac1e1 100644 --- a/src/interpreter/memory.rs +++ b/src/interpreter/memory.rs @@ -2,7 +2,7 @@ use std::u32; use std::sync::Arc; use parking_lot::RwLock; use elements::MemoryType; -use interpreter::Error; +use interpreter::{Error, UserError}; use interpreter::module::check_limits; /// Linear memory page size. @@ -11,11 +11,13 @@ pub const LINEAR_MEMORY_PAGE_SIZE: u32 = 65536; const LINEAR_MEMORY_MAX_PAGES: u32 = 65536; /// Linear memory instance. -pub struct MemoryInstance { +pub struct MemoryInstance { /// Linear memory buffer. buffer: RwLock>, /// Maximum buffer size. maximum_size: u32, + /// Dummy to avoid compilation error. + _dummy: ::std::marker::PhantomData, } struct CheckedRegion<'a, B: 'a> where B: ::std::ops::Deref> { @@ -34,9 +36,9 @@ impl<'a, B: 'a> CheckedRegion<'a, B> where B: ::std::ops::Deref> } } -impl MemoryInstance { +impl MemoryInstance where E: UserError { /// Create new linear memory instance. - pub fn new(memory_type: &MemoryType) -> Result, Error> { + pub fn new(memory_type: &MemoryType) -> Result, Error> { check_limits(memory_type.limits())?; let maximum_size = match memory_type.limits().maximum() { @@ -51,6 +53,7 @@ impl MemoryInstance { let memory = MemoryInstance { buffer: RwLock::new(vec![0; initial_size as usize]), maximum_size: maximum_size, + _dummy: Default::default(), }; Ok(Arc::new(memory)) @@ -62,7 +65,7 @@ impl MemoryInstance { } /// Get data at given offset. - pub fn get(&self, offset: u32, size: usize) -> Result, Error> { + pub fn get(&self, offset: u32, size: usize) -> Result, Error> { let buffer = self.buffer.read(); let region = self.checked_region(&buffer, offset as usize, size)?; @@ -70,7 +73,7 @@ impl MemoryInstance { } /// Set data at given offset. - pub fn set(&self, offset: u32, value: &[u8]) -> Result<(), Error> { + pub fn set(&self, offset: u32, value: &[u8]) -> Result<(), Error> { let mut buffer = self.buffer.write(); let range = self.checked_region(&buffer, offset as usize, value.len())?.range(); @@ -81,7 +84,7 @@ impl MemoryInstance { /// Increases the size of the linear memory by given number of pages. /// Returns -1 if allocation fails or previous memory size, if succeeds. - pub fn grow(&self, pages: u32) -> Result { + pub fn grow(&self, pages: u32) -> Result> { let mut buffer = self.buffer.write(); let old_size = buffer.len() as u32; match calculate_memory_size(old_size, pages, self.maximum_size) { @@ -93,7 +96,7 @@ impl MemoryInstance { } } - fn checked_region<'a, B>(&self, buffer: &'a B, offset: usize, size: usize) -> Result, Error> + fn checked_region<'a, B>(&self, buffer: &'a B, offset: usize, size: usize) -> Result, Error> where B: ::std::ops::Deref> { let end = offset.checked_add(size) @@ -111,7 +114,7 @@ impl MemoryInstance { } /// Copy memory region - pub fn copy(&self, src_offset: usize, dst_offset: usize, len: usize) -> Result<(), Error> { + pub fn copy(&self, src_offset: usize, dst_offset: usize, len: usize) -> Result<(), Error> { let buffer = self.buffer.write(); let read_region = self.checked_region(&buffer, src_offset, len)?; @@ -127,7 +130,7 @@ impl MemoryInstance { } /// Zero memory region - pub fn zero(&self, offset: usize, len: usize) -> Result<(), Error> { + pub fn zero(&self, offset: usize, len: usize) -> Result<(), Error> { let mut buffer = self.buffer.write(); let range = self.checked_region(&buffer, offset, len)?.range(); diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 3ebeccdc5..a4bf7e2bc 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -1,8 +1,12 @@ //! WebAssembly interpreter module. -/// Interpreter error. +/// Custom user error. +pub trait UserError: 'static + ::std::fmt::Display + ::std::fmt::Debug + Clone + PartialEq { +} + +/// Internal interpreter error. #[derive(Debug, Clone, PartialEq)] -pub enum Error { +pub enum Error where E: UserError { /// Program-level error. Program(String), /// Validation error. @@ -33,9 +37,11 @@ pub enum Error { Native(String), /// Trap. Trap(String), + /// Custom user error. + User(E), } -impl Into for Error { +impl Into for Error where E: UserError { fn into(self) -> String { match self { Error::Program(s) => s, @@ -53,10 +59,21 @@ impl Into for Error { Error::Env(s) => s, Error::Native(s) => s, Error::Trap(s) => format!("trap: {}", s), + Error::User(e) => format!("user: {}", e), } } } +/// Dummy user error. +#[derive(Debug, Clone, PartialEq)] +pub struct DummyUserError; + +impl UserError for DummyUserError {} + +impl ::std::fmt::Display for DummyUserError { + fn fmt(&self, _f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { Ok(()) } +} + mod env; mod env_native; mod imports; @@ -74,10 +91,26 @@ 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, ModuleInstanceInterface, + ItemIndex, ExportEntryType, CallerContext, ExecutionParams, FunctionSignature}; pub use self::table::TableInstance; pub use self::program::ProgramInstance; 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 Error if you do not need any custom user errors. +pub type DummyError = Error; + +/// 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 DefaultProgramInstance = 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 DefaultModuleInstance = 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 DefaultModuleInstanceInterface = self::module::ModuleInstanceInterface; diff --git a/src/interpreter/module.rs b/src/interpreter/module.rs index 9327154c8..9f0f04456 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, UserError}; 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: UserError> { /// Arguments. pub args: Vec, /// Execution-local external modules. - pub externals: HashMap>, + pub externals: HashMap + 'a>>, } /// Export type. @@ -50,31 +50,31 @@ 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, Error>; /// 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, Error>; /// Get export entry. - fn export_entry<'a>(&self, name: &str, required_type: &ExportEntryType) -> Result; + fn export_entry<'a>(&self, name: &str, required_type: &ExportEntryType) -> Result>; /// Get table reference. - fn table(&self, index: ItemIndex) -> Result, Error>; + fn table(&self, index: ItemIndex) -> Result>, Error>; /// Get memory reference. - fn memory(&self, index: ItemIndex) -> Result, Error>; + 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; + 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; + 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>; + 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, Error>; } /// 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,39 +97,39 @@ pub struct ModuleInstance { /// Function labels. functions_labels: HashMap>, /// Module imports. - imports: ModuleImports, + imports: ModuleImports, /// Module exports. exports: HashMap>, /// Tables. - tables: Vec>, + tables: Vec>>, /// Linear memory regions. - memory: Vec>, + memory: Vec>>, /// Globals. - globals: Vec>, + globals: Vec>>, } /// Caller context. -pub struct CallerContext<'a> { +pub struct CallerContext<'a, E: 'a + UserError> { /// Value stack limit pub value_stack_limit: usize, /// Frame stack limit pub frame_stack_limit: usize, /// Stack of the input parameters - pub value_stack: &'a mut StackWithLimit, + 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: UserError> { /// 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: UserError { 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: UserError { /// 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: UserError { + fn default() -> Self { + ExecutionParams { + args: Vec::default(), + externals: HashMap::default(), + } + } +} + +impl<'a, E> From> for ExecutionParams<'a, E> where E: UserError { + 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: UserError { /// 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<(), Error> { // execute start function (if any) if let Some(start_function) = self.module.start_section() { self.execute_index(start_function, ExecutionParams::default())?; @@ -396,11 +405,11 @@ 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) } - fn require_function(&self, index: ItemIndex) -> Result { + fn require_function(&self, index: ItemIndex) -> Result> { match self.imports.parse_function_index(index) { ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"), ItemIndex::Internal(index) => self.module.function_section() @@ -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: UserError { + fn execute_index(&self, index: u32, params: ExecutionParams) -> Result, Error> { 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, Error> { let index = self.exports.get(name) .ok_or(Error::Function(format!("missing executable export with name {}", name))) .and_then(|l| l.iter() @@ -446,7 +455,7 @@ impl ModuleInstanceInterface for ModuleInstance { self.execute_index(index, params) } - fn export_entry<'a>(&self, name: &str, required_type: &ExportEntryType) -> Result { + fn export_entry<'a>(&self, name: &str, required_type: &ExportEntryType) -> Result> { self.exports.get(name) .ok_or(Error::Function(format!("missing export entry with name {}", name))) .and_then(|l| l.iter() @@ -468,7 +477,7 @@ impl ModuleInstanceInterface for ModuleInstance { .ok_or(Error::Program(format!("unresolved import {}", name)))) } - fn table(&self, index: ItemIndex) -> Result, Error> { + fn table(&self, index: ItemIndex) -> Result>, Error> { match self.imports.parse_table_index(index) { ItemIndex::IndexSpace(_) => unreachable!("parse_table_index resolves IndexSpace option"), ItemIndex::Internal(index) => self.tables.get(index as usize).cloned() @@ -481,7 +490,7 @@ impl ModuleInstanceInterface for ModuleInstance { } } - fn memory(&self, index: ItemIndex) -> Result, Error> { + fn memory(&self, index: ItemIndex) -> Result>, Error> { match self.imports.parse_memory_index(index) { ItemIndex::IndexSpace(_) => unreachable!("parse_memory_index resolves IndexSpace option"), ItemIndex::Internal(index) => self.memory.get(index as usize).cloned() @@ -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() @@ -507,7 +516,7 @@ impl ModuleInstanceInterface for ModuleInstance { } } - fn function_type(&self, function_index: ItemIndex) -> Result { + fn function_type(&self, function_index: ItemIndex) -> Result> { match self.imports.parse_function_index(function_index) { ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"), ItemIndex::Internal(index) => self.require_function(ItemIndex::Internal(index)) @@ -523,7 +532,7 @@ impl ModuleInstanceInterface for ModuleInstance { } } - fn function_type_by_index(&self, type_index: u32) -> Result { + fn function_type_by_index(&self, type_index: u32) -> Result> { self.module.type_section() .ok_or(Error::Validation(format!("type reference {} exists in module without type section", type_index))) .and_then(|s| match s.types().get(type_index as usize) { @@ -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), @@ -574,7 +583,7 @@ impl ModuleInstanceInterface for ModuleInstance { module.function_reference(ItemIndex::IndexSpace(index), externals) } - fn function_body<'a>(&'a self, internal_index: u32) -> Result>, Error> { + fn function_body<'a>(&'a self, internal_index: u32) -> Result>, Error> { let function_body = self.module .code_section() .ok_or(Error::Function(format!("trying to call function with index {} in module without code section", internal_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, Error> { 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: UserError { /// 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(), @@ -622,7 +631,7 @@ impl<'a> CallerContext<'a> { } } -pub fn check_limits(limits: &ResizableLimits) -> Result<(), Error> { +pub fn check_limits(limits: &ResizableLimits) -> Result<(), Error> { if let Some(maximum) = limits.maximum() { if maximum < limits.initial() { return Err(Error::Validation(format!("maximum limit {} is lesser than minimum {}", maximum, limits.initial()))); @@ -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 42b89dba8..1040cb994 100644 --- a/src/interpreter/program.rs +++ b/src/interpreter/program.rs @@ -2,37 +2,37 @@ use std::sync::Arc; use std::collections::HashMap; use parking_lot::RwLock; use elements::Module; -use interpreter::Error; +use interpreter::{Error, UserError}; 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: UserError { /// Create new program instance. - pub fn new() -> Result { + pub fn new() -> Result> { ProgramInstance::with_env_params(env::EnvParams::default()) } /// Create new program instance with custom env module params (mostly memory) - pub fn with_env_params(params: env::EnvParams) -> Result { + pub fn with_env_params(params: env::EnvParams) -> Result> { Ok(ProgramInstance { essence: Arc::new(ProgramInstanceEssence::with_env_params(params)?), }) } /// 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>, Error> { let mut module_instance = ModuleInstance::new(Arc::downgrade(&self.essence), name.into(), module)?; module_instance.instantiate(externals)?; @@ -43,27 +43,27 @@ 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: UserError { /// Create new program essence. - pub fn new() -> Result { + pub fn new() -> Result> { ProgramInstanceEssence::with_env_params(env::EnvParams::default()) } - pub fn with_env_params(env_params: env::EnvParams) -> Result { + 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 906e48fec..4f2f8ed14 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, UserError}; use interpreter::module::{ModuleInstanceInterface, CallerContext, ItemIndex, InternalFunctionReference, FunctionSignature}; use interpreter::stack::StackWithLimit; use interpreter::value::{ @@ -22,37 +22,39 @@ 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 + UserError> { /// 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. - pub locals: Vec, + pub locals: Vec>, /// Values stack. - pub value_stack: StackWithLimit, + pub value_stack: StackWithLimit, /// Blocks frames stack. - pub frame_stack: StackWithLimit, + pub frame_stack: StackWithLimit, /// Current instruction position. pub position: usize, } /// Interpreter action to execute after executing instruction. #[derive(Debug)] -pub enum InstructionOutcome<'a> { +pub enum InstructionOutcome<'a, E: UserError> { /// 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 + UserError> { /// 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: UserError { + pub fn run_function(function_context: FunctionContext) -> Result, Error> { 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,54 +437,55 @@ 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() - .and_then(|(left, mid, right)| - match (left, mid, right.try_into()) { + .and_then(|(left, mid, right)| { + let right: Result<_, Error> = right.try_into(); + match (left, mid, right) { (left, mid, Ok(condition)) => Ok((left, mid, condition)), _ => Err(Error::Stack("expected to get int value from stack".into())) } - ) + }) .map(|(left, mid, condition)| if condition { left } else { mid }) .map(|val| context.value_stack_mut().push(val)) .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,8 +493,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_load<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result, Error> - where RuntimeValue: From, T: LittleEndianConvert { + 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() .memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX)) @@ -501,8 +504,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_load_extend<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result, Error> - where T: ExtendInto, RuntimeValue: From, T: LittleEndianConvert { + 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() .memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX)) @@ -515,8 +518,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_store<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result, Error> - where RuntimeValue: TryInto, T: LittleEndianConvert { + 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() .pop_as::() @@ -528,8 +531,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_store_wrap<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result, Error> - where RuntimeValue: TryInto, T: WrapInto, U: LittleEndianConvert { + 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(); let address = effective_address(offset, context.value_stack_mut().pop_as::()?)?; @@ -539,7 +542,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 +550,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,15 +559,15 @@ 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> - where RuntimeValue: TryInto, T: PartialEq + Default { + fn run_eqz<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: TryInto>, T: PartialEq + Default { context .value_stack_mut() .pop_as::() @@ -573,8 +576,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_eq<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: TryInto, T: PartialEq { + fn run_eq<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: TryInto>, T: PartialEq { context .value_stack_mut() .pop_pair_as::() @@ -583,8 +586,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_ne<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: TryInto, T: PartialEq { + fn run_ne<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: TryInto>, T: PartialEq { context .value_stack_mut() .pop_pair_as::() @@ -593,8 +596,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_lt<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: TryInto, T: PartialOrd + Display { + fn run_lt<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: TryInto>, T: PartialOrd + Display { context .value_stack_mut() .pop_pair_as::() @@ -603,8 +606,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_gt<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: TryInto, T: PartialOrd { + fn run_gt<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: TryInto>, T: PartialOrd { context .value_stack_mut() .pop_pair_as::() @@ -613,8 +616,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_lte<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: TryInto, T: PartialOrd { + fn run_lte<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: TryInto>, T: PartialOrd { context .value_stack_mut() .pop_pair_as::() @@ -623,8 +626,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_gte<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: TryInto, T: PartialOrd { + fn run_gte<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: TryInto>, T: PartialOrd { context .value_stack_mut() .pop_pair_as::() @@ -633,8 +636,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_clz<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From + TryInto, T: Integer { + fn run_clz<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: From + TryInto>, T: Integer { context .value_stack_mut() .pop_as::() @@ -643,8 +646,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_ctz<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From + TryInto, T: Integer { + fn run_ctz<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: From + TryInto>, T: Integer { context .value_stack_mut() .pop_as::() @@ -653,8 +656,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_popcnt<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From + TryInto, T: Integer { + fn run_popcnt<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: From + TryInto>, T: Integer { context .value_stack_mut() .pop_as::() @@ -663,8 +666,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_add<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From + TryInto, T: ArithmeticOps { + fn run_add<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: From + TryInto>, T: ArithmeticOps { context .value_stack_mut() .pop_pair_as::() @@ -673,8 +676,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_sub<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From + TryInto, T: ArithmeticOps { + fn run_sub<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: From + TryInto>, T: ArithmeticOps { context .value_stack_mut() .pop_pair_as::() @@ -683,8 +686,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_mul<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From + TryInto, T: ArithmeticOps { + fn run_mul<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: From + TryInto>, T: ArithmeticOps { context .value_stack_mut() .pop_pair_as::() @@ -693,8 +696,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_div<'a, T, U>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From + TryInto, T: TransmuteInto + Display, U: ArithmeticOps + TransmuteInto { + 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() .pop_pair_as::() @@ -705,8 +708,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_rem<'a, T, U>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From + TryInto, T: TransmuteInto, U: Integer + TransmuteInto { + fn run_rem<'a, T, U>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: From + TryInto>, T: TransmuteInto, U: Integer + TransmuteInto { context .value_stack_mut() .pop_pair_as::() @@ -717,8 +720,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_and<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From<::Output> + TryInto, T: ops::BitAnd { + fn run_and<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: From<::Output> + TryInto>, T: ops::BitAnd { context .value_stack_mut() .pop_pair_as::() @@ -727,8 +730,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_or<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From<::Output> + TryInto, T: ops::BitOr { + fn run_or<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: From<::Output> + TryInto>, T: ops::BitOr { context .value_stack_mut() .pop_pair_as::() @@ -737,8 +740,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_xor<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From<::Output> + TryInto, T: ops::BitXor { + fn run_xor<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: From<::Output> + TryInto>, T: ops::BitXor { context .value_stack_mut() .pop_pair_as::() @@ -747,8 +750,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_shl<'a, T>(context: &mut FunctionContext, mask: T) -> Result, Error> - where RuntimeValue: From<>::Output> + TryInto, T: ops::Shl + ops::BitAnd { + 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() .pop_pair_as::() @@ -757,8 +760,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - 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 { + 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() .pop_pair_as::() @@ -769,8 +772,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_rotl<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From + TryInto, T: Integer { + fn run_rotl<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: From + TryInto>, T: Integer { context .value_stack_mut() .pop_pair_as::() @@ -779,8 +782,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_rotr<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From + TryInto, T: Integer { + fn run_rotr<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: From + TryInto>, T: Integer { context .value_stack_mut() .pop_pair_as::() @@ -789,8 +792,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_abs<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From + TryInto, T: Float { + fn run_abs<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: From + TryInto>, T: Float { context .value_stack_mut() .pop_as::() @@ -799,8 +802,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_neg<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From<::Output> + TryInto, T: ops::Neg { + fn run_neg<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: From<::Output> + TryInto>, T: ops::Neg { context .value_stack_mut() .pop_as::() @@ -809,8 +812,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_ceil<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From + TryInto, T: Float { + fn run_ceil<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: From + TryInto>, T: Float { context .value_stack_mut() .pop_as::() @@ -819,8 +822,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_floor<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From + TryInto, T: Float { + fn run_floor<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: From + TryInto>, T: Float { context .value_stack_mut() .pop_as::() @@ -829,8 +832,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_trunc<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From + TryInto, T: Float { + fn run_trunc<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: From + TryInto>, T: Float { context .value_stack_mut() .pop_as::() @@ -839,8 +842,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_nearest<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From + TryInto, T: Float { + fn run_nearest<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: From + TryInto>, T: Float { context .value_stack_mut() .pop_as::() @@ -849,8 +852,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_sqrt<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From + TryInto, T: Float { + fn run_sqrt<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: From + TryInto>, T: Float { context .value_stack_mut() .pop_as::() @@ -859,8 +862,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_min<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From + TryInto, T: Float { + fn run_min<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: From + TryInto>, T: Float { context .value_stack_mut() .pop_pair_as::() @@ -869,8 +872,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_max<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From + TryInto, T: Float { + fn run_max<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: From + TryInto>, T: Float { context .value_stack_mut() .pop_pair_as::() @@ -879,8 +882,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_copysign<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From + TryInto, T: Float { + fn run_copysign<'a, T>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: From + TryInto>, T: Float { context .value_stack_mut() .pop_pair_as::() @@ -889,8 +892,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_wrap<'a, T, U>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From + TryInto, T: WrapInto { + fn run_wrap<'a, T, U>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: From + TryInto>, T: WrapInto { context .value_stack_mut() .pop_as::() @@ -899,8 +902,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_trunc_to_int<'a, T, U, V>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From + TryInto, T: TryTruncateInto, U: TransmuteInto, { + 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() .pop_as::() @@ -910,8 +913,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_extend<'a, T, U, V>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From + TryInto, T: ExtendInto, U: TransmuteInto { + fn run_extend<'a, T, U, V>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: From + TryInto>, T: ExtendInto, U: TransmuteInto { context .value_stack_mut() .pop_as::() @@ -921,8 +924,8 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_reinterpret<'a, T, U>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From, RuntimeValue: TryInto, T: TransmuteInto { + fn run_reinterpret<'a, T, U>(context: &mut FunctionContext) -> Result, Error> + where RuntimeValue: From, RuntimeValue: TryInto>, T: TransmuteInto { context .value_stack_mut() .pop_as::() @@ -932,8 +935,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: UserError { + 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 +949,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); @@ -970,7 +973,7 @@ impl<'a> FunctionContext<'a> { self.is_initialized } - pub fn initialize(&mut self, locals: &[Local]) -> Result<(), Error> { + pub fn initialize(&mut self, locals: &[Local]) -> Result<(), Error> { debug_assert!(!self.is_initialized); self.is_initialized = true; @@ -982,44 +985,44 @@ 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)) .map(|_| InstructionOutcome::RunNextInstruction) } - pub fn get_local(&mut self, index: usize) -> Result { + pub fn get_local(&mut self, index: usize) -> Result> { self.locals.get(index) .ok_or(Error::Local(format!("expected to have local with index {}", index))) .map(|l| l.get()) } - pub fn value_stack(&self) -> &StackWithLimit { + pub fn value_stack(&self) -> &StackWithLimit { &self.value_stack } - pub fn value_stack_mut(&mut self) -> &mut StackWithLimit { + pub fn value_stack_mut(&mut self) -> &mut StackWithLimit { &mut self.value_stack } - pub fn frame_stack(&self) -> &StackWithLimit { + pub fn frame_stack(&self) -> &StackWithLimit { &self.frame_stack } - pub fn frame_stack_mut(&mut self) -> &mut StackWithLimit { + pub fn frame_stack_mut(&mut self) -> &mut StackWithLimit { &mut self.frame_stack } - pub fn push_frame(&mut self, labels: &HashMap, frame_type: BlockFrameType, block_type: BlockType) -> Result<(), Error> { + pub fn push_frame(&mut self, labels: &HashMap, frame_type: BlockFrameType, block_type: BlockType) -> Result<(), Error> { let begin_position = self.position; let branch_position = match frame_type { BlockFrameType::Function => usize::MAX, @@ -1047,12 +1050,12 @@ impl<'a> FunctionContext<'a> { }) } - pub fn discard_frame(&mut self) -> Result<(), Error> { + pub fn discard_frame(&mut self) -> Result<(), Error> { self.frame_stack.pop() .map(|_| ()) } - pub fn pop_frame(&mut self, is_branch: bool) -> Result<(), Error> { + pub fn pop_frame(&mut self, is_branch: bool) -> Result<(), Error> { let frame = self.frame_stack.pop()?; if frame.value_stack_len > self.value_stack.len() { return Err(Error::Stack("invalid stack len".into())); @@ -1072,20 +1075,20 @@ impl<'a> FunctionContext<'a> { } } -impl<'a> fmt::Debug for FunctionContext<'a> { +impl<'a, E> fmt::Debug for FunctionContext<'a, E> where E: UserError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "FunctionContext") } } -fn effective_address(address: u32, offset: u32) -> Result { +fn effective_address(address: u32, offset: u32) -> Result> { match offset.checked_add(address) { None => Err(Error::Memory(format!("invalid memory access: {} + {}", offset, address))), Some(address) => Ok(address), } } -pub fn prepare_function_args(function_type: &FunctionSignature, caller_stack: &mut StackWithLimit) -> Result, Error> { +pub fn prepare_function_args(function_type: &FunctionSignature, caller_stack: &mut StackWithLimit) -> Result>, Error> { let mut args = function_type.params().iter().rev().map(|param_type| { let param_value = caller_stack.pop()?; let actual_type = param_value.variable_type(); diff --git a/src/interpreter/stack.rs b/src/interpreter/stack.rs index 78d10935a..6f1b565e2 100644 --- a/src/interpreter/stack.rs +++ b/src/interpreter/stack.rs @@ -1,21 +1,24 @@ use std::collections::VecDeque; -use interpreter::Error; +use interpreter::{Error, UserError}; use interpreter::value::{RuntimeValue, TryInto}; /// Stack with limit. #[derive(Debug)] -pub struct StackWithLimit where T: Clone { +pub struct StackWithLimit where T: Clone, E: UserError { /// Stack values. values: VecDeque, /// Stack limit (maximal stack len). limit: usize, + /// Dummy to avoid compilation error. + _dummy: ::std::marker::PhantomData, } -impl StackWithLimit where T: Clone { +impl StackWithLimit where T: Clone, E: UserError { pub fn with_data(data: Vec, limit: usize) -> Self { StackWithLimit { values: data.into_iter().collect(), limit: limit, + _dummy: Default::default(), } } @@ -23,6 +26,7 @@ impl StackWithLimit where T: Clone { StackWithLimit { values: VecDeque::new(), limit: limit, + _dummy: Default::default(), } } @@ -42,19 +46,19 @@ impl StackWithLimit where T: Clone { &self.values } - pub fn top(&self) -> Result<&T, Error> { + pub fn top(&self) -> Result<&T, Error> { self.values .back() .ok_or(Error::Stack("non-empty stack expected".into())) } - pub fn top_mut(&mut self) -> Result<&mut T, Error> { + pub fn top_mut(&mut self) -> Result<&mut T, Error> { self.values .back_mut() .ok_or(Error::Stack("non-empty stack expected".into())) } - pub fn get(&self, index: usize) -> Result<&T, Error> { + pub fn get(&self, index: usize) -> Result<&T, Error> { if index >= self.values.len() { return Err(Error::Stack(format!("trying to get value at position {} on stack of size {}", index, self.values.len()))); } @@ -62,7 +66,7 @@ impl StackWithLimit where T: Clone { Ok(self.values.get(self.values.len() - 1 - index).expect("checked couple of lines above")) } - pub fn push(&mut self, value: T) -> Result<(), Error> { + pub fn push(&mut self, value: T) -> Result<(), Error> { if self.values.len() >= self.limit { return Err(Error::Stack(format!("exceeded stack limit {}", self.limit))); } @@ -71,7 +75,7 @@ impl StackWithLimit where T: Clone { Ok(()) } - pub fn push_penultimate(&mut self, value: T) -> Result<(), Error> { + pub fn push_penultimate(&mut self, value: T) -> Result<(), Error> { if self.values.is_empty() { return Err(Error::Stack("trying to insert penultimate element into empty stack".into())); } @@ -84,7 +88,7 @@ impl StackWithLimit where T: Clone { Ok(()) } - pub fn pop(&mut self) -> Result { + pub fn pop(&mut self) -> Result> { self.values .pop_back() .ok_or(Error::Stack("non-empty stack expected".into())) @@ -96,26 +100,26 @@ impl StackWithLimit where T: Clone { } } -impl StackWithLimit { - pub fn pop_as(&mut self) -> Result - where RuntimeValue: TryInto { +impl StackWithLimit where E: UserError { + pub fn pop_as(&mut self) -> Result> + where RuntimeValue: TryInto> { self.pop().and_then(TryInto::try_into) } - pub fn pop_pair(&mut self) -> Result<(RuntimeValue, RuntimeValue), Error> { + pub fn pop_pair(&mut self) -> Result<(RuntimeValue, RuntimeValue), Error> { let right = self.pop()?; let left = self.pop()?; Ok((left, right)) } - pub fn pop_pair_as(&mut self) -> Result<(T, T), Error> - where RuntimeValue: TryInto { + pub fn pop_pair_as(&mut self) -> Result<(T, T), Error> + where RuntimeValue: TryInto> { let right = self.pop_as()?; let left = self.pop_as()?; Ok((left, right)) } - pub fn pop_triple(&mut self) -> Result<(RuntimeValue, RuntimeValue, RuntimeValue), Error> { + pub fn pop_triple(&mut self) -> Result<(RuntimeValue, RuntimeValue, RuntimeValue), Error> { let right = self.pop()?; let mid = self.pop()?; let left = self.pop()?; diff --git a/src/interpreter/table.rs b/src/interpreter/table.rs index 37b025505..681a74ded 100644 --- a/src/interpreter/table.rs +++ b/src/interpreter/table.rs @@ -2,27 +2,27 @@ use std::u32; use std::sync::Arc; use parking_lot::RwLock; use elements::TableType; -use interpreter::Error; +use interpreter::{Error, UserError}; use interpreter::module::check_limits; use interpreter::variable::{VariableInstance, VariableType}; use interpreter::value::RuntimeValue; /// Table instance. -pub struct TableInstance { +pub struct TableInstance { /// Table variables type. variable_type: VariableType, /// Table memory buffer. - buffer: RwLock>, + buffer: RwLock>>, } /// Table element. Cloneable wrapper around VariableInstance. -struct TableElement { - pub var: VariableInstance, +struct TableElement { + pub var: VariableInstance, } -impl TableInstance { +impl TableInstance where E: UserError { /// New instance of the table - pub fn new(table_type: &TableType) -> Result, Error> { + pub fn new(table_type: &TableType) -> Result, Error> { check_limits(table_type.limits())?; let variable_type = table_type.elem_type().into(); @@ -40,7 +40,7 @@ impl TableInstance { } /// Get the specific value in the table - pub fn get(&self, offset: u32) -> Result { + pub fn get(&self, offset: u32) -> Result> { let buffer = self.buffer.read(); let buffer_len = buffer.len(); buffer.get(offset as usize) @@ -49,7 +49,7 @@ impl TableInstance { } /// Set the table value from raw slice - pub fn set_raw(&self, mut offset: u32, module_name: String, value: &[u32]) -> Result<(), Error> { + pub fn set_raw(&self, mut offset: u32, module_name: String, value: &[u32]) -> Result<(), Error> { for val in value { match self.variable_type { VariableType::AnyFunc => self.set(offset, RuntimeValue::AnyFunc(module_name.clone(), *val))?, @@ -61,7 +61,7 @@ impl TableInstance { } /// Set the table from runtime variable value - pub fn set(&self, offset: u32, value: RuntimeValue) -> Result<(), Error> { + pub fn set(&self, offset: u32, value: RuntimeValue) -> Result<(), Error> { let mut buffer = self.buffer.write(); let buffer_len = buffer.len(); buffer.get_mut(offset as usize) @@ -70,15 +70,15 @@ impl TableInstance { } } -impl TableElement { - pub fn new(var: VariableInstance) -> Self { +impl TableElement where E: UserError { + pub fn new(var: VariableInstance) -> Self { TableElement { var: var, } } } -impl Clone for TableElement { +impl Clone for TableElement where E: UserError { fn clone(&self) -> Self { TableElement::new(VariableInstance::new(self.var.is_mutable(), self.var.variable_type(), self.var.get()) .expect("it only fails when variable_type() != passed variable value; both are read from already constructed var; qed")) diff --git a/src/interpreter/tests/basics.rs b/src/interpreter/tests/basics.rs index 30f79c4d0..6389c1495 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, UserError, ProgramInstance, DefaultProgramInstance, DefaultModuleInstance}; 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}; @@ -40,7 +39,7 @@ fn import_function() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let external_module = program.add_module("external_module", module1, None).unwrap(); let main_module = program.add_module("main", module2, None).unwrap(); @@ -74,7 +73,7 @@ fn wrong_import() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let _side_module_instance = program.add_module("side_module", side_module, None).unwrap(); assert!(program.add_module("main", module, None).is_err()); } @@ -96,7 +95,7 @@ fn global_get_set() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(50)); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(58)); @@ -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] = &[]; @@ -124,25 +128,39 @@ struct MeasuredVariable { pub val: i32, } -impl ExternalVariableValue for MeasuredVariable { +impl ExternalVariableValue for MeasuredVariable { fn get(&self) -> RuntimeValue { RuntimeValue::I32(self.val) } - fn set(&mut self, val: RuntimeValue) -> Result<(), Error> { + fn set(&mut self, val: RuntimeValue) -> Result<(), Error> { self.val = val.try_into()?; Ok(()) } } +// custom user error +#[derive(Debug, Clone, PartialEq)] +struct UserErrorWithCode { + error_code: i32, +} + +impl ::std::fmt::Display for UserErrorWithCode { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + write!(f, "{}", self.error_code) + } +} + +impl UserError for UserErrorWithCode {} + // user function executor struct FunctionExecutor { - pub memory: Arc, + 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, Error> { 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(Error::User(UserErrorWithCode { error_code: 777 })) + }, + _ => Err(Error::Trap("not implemented".into()).into()), } } } @@ -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), @@ -283,8 +304,42 @@ fn native_env_global() { } #[test] -fn import_env_mutable_global() { +fn native_custom_error() { let program = ProgramInstance::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(Error::User(UserErrorWithCode { error_code: 777 }))); + assert_eq!(module_instance.execute_index(1, params.clone().add_argument(RuntimeValue::I32(7)).add_argument(RuntimeValue::I32(0))), + Err(Error::User(UserErrorWithCode { error_code: 777 }))); +} + +#[test] +fn import_env_mutable_global() { + let program = DefaultProgramInstance::new().unwrap(); let module = module() .with_import(ImportEntry::new("env".into(), "STACKTOP".into(), External::Global(GlobalType::new(ValueType::I32, false)))) @@ -314,7 +369,7 @@ fn env_native_export_entry_type_check() { #[test] fn if_else_with_return_type_validation() { - let module_instance = ModuleInstance::new(Weak::default(), "test".into(), module().build()).unwrap(); + let module_instance = DefaultModuleInstance::new(Weak::default(), "test".into(), module().build()).unwrap(); let mut context = FunctionValidationContext::new(&module_instance, None, &[], 1024, 1024, FunctionSignature::Module(&FunctionType::default())); Validator::validate_function(&mut context, BlockType::NoResult, &[ diff --git a/src/interpreter/tests/wabt.rs b/src/interpreter/tests/wabt.rs index 1244c7485..636a7d57b 100644 --- a/src/interpreter/tests/wabt.rs +++ b/src/interpreter/tests/wabt.rs @@ -3,12 +3,10 @@ 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, DummyError, DefaultProgramInstance, DefaultModuleInstanceInterface, ModuleInstanceInterface, ItemIndex}; use interpreter::value::{RuntimeValue, TryInto}; -fn make_function_i32(body: Opcodes) -> (ProgramInstance, Arc) { +fn make_function_i32(body: Opcodes) -> (DefaultProgramInstance, Arc) { let module = module() .function() .signature().param().i32().return_type().i32().build() @@ -19,15 +17,15 @@ fn make_function_i32(body: Opcodes) -> (ProgramInstance, Arc, arg: i32) -> Result { +fn run_function_i32(module: &Arc, arg: i32) -> Result { module .execute_index(0, vec![RuntimeValue::I32(arg)].into()) - .map(|r| r.unwrap().try_into().unwrap()) + .and_then(|r| r.unwrap().try_into()) } /// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/unreachable.txt @@ -458,7 +456,7 @@ fn return_void() { .body().with_opcodes(body).build() .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); module.execute_index(0, vec![RuntimeValue::I32(0)].into()).unwrap(); @@ -517,7 +515,7 @@ fn call_1() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(10)); } @@ -564,7 +562,7 @@ fn call_2() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(3628800)); } @@ -609,7 +607,7 @@ fn call_zero_args() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(2, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(43)); } @@ -655,7 +653,7 @@ fn callindirect_1() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(2, vec![RuntimeValue::I32(0)].into()).unwrap().unwrap(), RuntimeValue::I32(0)); assert_eq!(module.execute_index(2, vec![RuntimeValue::I32(1)].into()).unwrap().unwrap(), RuntimeValue::I32(1)); @@ -728,7 +726,7 @@ fn callindirect_2() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); 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)); @@ -796,7 +794,7 @@ fn select() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![RuntimeValue::I32(0)].into()).unwrap().unwrap(), RuntimeValue::I32(2)); assert_eq!(module.execute_index(0, vec![RuntimeValue::I32(1)].into()).unwrap().unwrap(), RuntimeValue::I32(1)); @@ -949,7 +947,7 @@ fn binary_i32() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(3)); assert_eq!(module.execute_index(1, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(16)); @@ -1109,7 +1107,7 @@ fn binary_i64() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::I64(3)); assert_eq!(module.execute_index(1, vec![].into()).unwrap().unwrap(), RuntimeValue::I64(16)); @@ -1199,7 +1197,7 @@ fn binary_f32() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::F32(5.000000)); assert_eq!(module.execute_index(1, vec![].into()).unwrap().unwrap(), RuntimeValue::F32(-9995.500000)); @@ -1281,7 +1279,7 @@ fn binary_f64() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::F64(1111111110.000000)); assert_eq!(module.execute_index(1, vec![].into()).unwrap().unwrap(), RuntimeValue::F64(123400000000000007812762268812638756607430593436581896388608.000000)); @@ -1334,7 +1332,7 @@ fn cast() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::F32(4.5)); assert_eq!(module.execute_index(1, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(-1067450368)); // 3227516928 @@ -1600,7 +1598,7 @@ fn compare_i32() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(1)); assert_eq!(module.execute_index(1, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(0)); @@ -1890,7 +1888,7 @@ fn compare_i64() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(1)); assert_eq!(module.execute_index(1, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(0)); @@ -2074,7 +2072,7 @@ fn compare_f32() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(1)); assert_eq!(module.execute_index(1, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(0)); @@ -2246,7 +2244,7 @@ fn compare_f64() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(1)); assert_eq!(module.execute_index(1, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(0)); @@ -2314,7 +2312,7 @@ fn convert_i32() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(-1)); // 4294967295 assert_eq!(module.execute_index(1, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(-100)); // 4294967196 @@ -2387,7 +2385,7 @@ fn convert_i64() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::I64(4294967295)); assert_eq!(module.execute_index(1, vec![].into()).unwrap().unwrap(), RuntimeValue::I64(-1)); // 18446744073709551615 @@ -2445,7 +2443,7 @@ fn convert_f32() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::F32(-1.000000)); assert_eq!(module.execute_index(1, vec![].into()).unwrap().unwrap(), RuntimeValue::F32(4294967296.000000)); @@ -2502,7 +2500,7 @@ fn convert_f64() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::F64(-1.000000)); assert_eq!(module.execute_index(1, vec![].into()).unwrap().unwrap(), RuntimeValue::F64(4294967295.000000)); @@ -2562,7 +2560,7 @@ fn load_i32() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(-1)); assert_eq!(module.execute_index(1, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(-1)); @@ -2638,7 +2636,7 @@ fn load_i64() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::I64(-1)); assert_eq!(module.execute_index(1, vec![].into()).unwrap().unwrap(), RuntimeValue::I64(-1)); @@ -2668,7 +2666,7 @@ fn load_f32() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::F32(25.750000)); } @@ -2692,7 +2690,7 @@ fn load_f64() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::F64(1023.875000)); } @@ -2749,7 +2747,7 @@ fn store_i32() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(-16909061)); assert_eq!(module.execute_index(1, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(-859059511)); @@ -2819,7 +2817,7 @@ fn store_i64() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::I64(4278058235)); assert_eq!(module.execute_index(1, vec![].into()).unwrap().unwrap(), RuntimeValue::I64(3435907785)); @@ -2847,7 +2845,7 @@ fn store_f32() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(1069547520)); } @@ -2872,7 +2870,7 @@ fn store_f64() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(-1064352256)); } @@ -2923,7 +2921,7 @@ fn unary_i32() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(0)); assert_eq!(module.execute_index(1, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(1)); @@ -2978,7 +2976,7 @@ fn unary_i64() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(0)); assert_eq!(module.execute_index(1, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(1)); @@ -3077,7 +3075,7 @@ fn unary_f32() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(1, vec![].into()).unwrap().unwrap(), RuntimeValue::F32(-100.000000)); assert_eq!(module.execute_index(2, vec![].into()).unwrap().unwrap(), RuntimeValue::F32(100.000000)); @@ -3180,7 +3178,7 @@ fn unary_f64() { .build() .build(); - let program = ProgramInstance::new().unwrap(); + let program = DefaultProgramInstance::new().unwrap(); let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(1, vec![].into()).unwrap().unwrap(), RuntimeValue::F64(-100.000000)); assert_eq!(module.execute_index(2, vec![].into()).unwrap().unwrap(), RuntimeValue::F64(100.000000)); diff --git a/src/interpreter/tests/wasm.rs b/src/interpreter/tests/wasm.rs index a005726fc..6fe9a31c0 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, DefaultProgramInstance}; use interpreter::module::ModuleInstanceInterface; -use interpreter::program::ProgramInstance; use interpreter::value::RuntimeValue; // Name of function contained in WASM file (note the leading underline) @@ -14,7 +12,7 @@ const WASM_FILE: &str = &"res/cases/v1/inc_i32.wasm"; #[test] fn interpreter_inc_i32() { - let program = ProgramInstance::with_env_params(EnvParams { + let program = DefaultProgramInstance::with_env_params(EnvParams { total_stack: 128 * 1024, total_memory: 2 * 1024 * 1024, allow_memory_growth: false, diff --git a/src/interpreter/validator.rs b/src/interpreter/validator.rs index 43f411b4c..fdbfe7f10 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, UserError}; use interpreter::runner::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; use interpreter::module::{ModuleInstance, ModuleInstanceInterface, ItemIndex, FunctionSignature}; use interpreter::stack::StackWithLimit; @@ -12,19 +12,19 @@ use interpreter::variable::VariableType; const NATURAL_ALIGNMENT: u32 = 0xFFFFFFFF; /// Function validation context. -pub struct FunctionValidationContext<'a> { +pub struct FunctionValidationContext<'a, E: 'a + UserError> { /// 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. locals: &'a [ValueType], /// Value stack. - value_stack: StackWithLimit, + value_stack: StackWithLimit, /// Frame stack. - frame_stack: StackWithLimit, + frame_stack: StackWithLimit, /// Function return type. None if validating expression. return_type: Option, /// Labels positions. @@ -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: UserError { + 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: UserError { 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, @@ -590,11 +592,11 @@ impl<'a> FunctionValidationContext<'a> { } } - pub fn push_value(&mut self, value_type: StackValueType) -> Result<(), Error> { + pub fn push_value(&mut self, value_type: StackValueType) -> Result<(), Error> { self.value_stack.push(value_type.into()) } - pub fn pop_value(&mut self, value_type: StackValueType) -> Result<(), Error> { + pub fn pop_value(&mut self, value_type: StackValueType) -> Result<(), Error> { self.check_stack_access()?; match self.value_stack.pop()? { StackValueType::Specific(stack_value_type) if stack_value_type == value_type => Ok(()), @@ -607,7 +609,7 @@ impl<'a> FunctionValidationContext<'a> { } } - pub fn tee_value(&mut self, value_type: StackValueType) -> Result<(), Error> { + pub fn tee_value(&mut self, value_type: StackValueType) -> Result<(), Error> { self.check_stack_access()?; match *self.value_stack.top()? { StackValueType::Specific(stack_value_type) if stack_value_type == value_type => Ok(()), @@ -616,7 +618,7 @@ impl<'a> FunctionValidationContext<'a> { } } - pub fn pop_any_value(&mut self) -> Result { + pub fn pop_any_value(&mut self) -> Result> { self.check_stack_access()?; match self.value_stack.pop()? { StackValueType::Specific(stack_value_type) => Ok(StackValueType::Specific(stack_value_type)), @@ -628,20 +630,20 @@ impl<'a> FunctionValidationContext<'a> { } } - pub fn tee_any_value(&mut self) -> Result { + pub fn tee_any_value(&mut self) -> Result> { self.check_stack_access()?; self.value_stack.top().map(Clone::clone) } - pub fn unreachable(&mut self) -> Result<(), Error> { + pub fn unreachable(&mut self) -> Result<(), Error> { self.value_stack.push(StackValueType::AnyUnlimited) } - pub fn top_label(&self) -> Result<&BlockFrame, Error> { + pub fn top_label(&self) -> Result<&BlockFrame, Error> { self.frame_stack.top() } - pub fn push_label(&mut self, frame_type: BlockFrameType, block_type: BlockType) -> Result<(), Error> { + pub fn push_label(&mut self, frame_type: BlockFrameType, block_type: BlockType) -> Result<(), Error> { self.frame_stack.push(BlockFrame { frame_type: frame_type, block_type: block_type, @@ -652,7 +654,7 @@ impl<'a> FunctionValidationContext<'a> { }) } - pub fn pop_label(&mut self) -> Result { + pub fn pop_label(&mut self) -> Result> { let frame = self.frame_stack.pop()?; let actual_value_type = if self.value_stack.len() > frame.value_stack_len { Some(self.value_stack.pop()?) @@ -676,22 +678,22 @@ impl<'a> FunctionValidationContext<'a> { Ok(InstructionOutcome::ValidateNextInstruction) } - pub fn require_label(&self, idx: u32) -> Result<&BlockFrame, Error> { + pub fn require_label(&self, idx: u32) -> Result<&BlockFrame, Error> { self.frame_stack.get(idx as usize) } - pub fn return_type(&self) -> Result { + pub fn return_type(&self) -> Result> { self.return_type.ok_or(Error::Validation("Trying to return from expression".into())) } - pub fn require_local(&self, idx: u32) -> Result { + pub fn require_local(&self, idx: u32) -> Result> { self.locals.get(idx as usize) .cloned() .map(Into::into) .ok_or(Error::Validation(format!("Trying to access local with index {} when there are only {} locals", idx, self.locals.len()))) } - pub fn require_global(&self, idx: u32, mutability: Option) -> Result { + pub fn require_global(&self, idx: u32, mutability: Option) -> Result> { self.module_instance .global(ItemIndex::IndexSpace(idx), None, self.externals.clone()) .and_then(|g| match mutability { @@ -707,13 +709,13 @@ impl<'a> FunctionValidationContext<'a> { }) } - pub fn require_memory(&self, idx: u32) -> Result<(), Error> { + pub fn require_memory(&self, idx: u32) -> Result<(), Error> { self.module_instance .memory(ItemIndex::IndexSpace(idx)) .map(|_| ()) } - pub fn require_table(&self, idx: u32, variable_type: VariableType) -> Result<(), Error> { + pub fn require_table(&self, idx: u32, variable_type: VariableType) -> Result<(), Error> { self.module_instance .table(ItemIndex::IndexSpace(idx)) .and_then(|t| if t.variable_type() == variable_type { @@ -723,12 +725,12 @@ impl<'a> FunctionValidationContext<'a> { }) } - pub fn require_function(&self, idx: u32) -> Result<(Vec, BlockType), Error> { + pub fn require_function(&self, idx: u32) -> Result<(Vec, BlockType), Error> { self.module_instance.function_type(ItemIndex::IndexSpace(idx)) .map(|ft| (ft.params().to_vec(), ft.return_type().map(BlockType::Value).unwrap_or(BlockType::NoResult))) } - pub fn require_function_type(&self, idx: u32) -> Result<(Vec, BlockType), Error> { + pub fn require_function_type(&self, idx: u32) -> Result<(Vec, BlockType), Error> { self.module_instance.function_type_by_index(idx) .map(|ft| (ft.params().to_vec(), ft.return_type().map(BlockType::Value).unwrap_or(BlockType::NoResult))) } @@ -737,7 +739,7 @@ impl<'a> FunctionValidationContext<'a> { self.labels } - fn check_stack_access(&self) -> Result<(), Error> { + fn check_stack_access(&self) -> Result<(), Error> { let value_stack_min = self.frame_stack.top().expect("at least 1 topmost block").value_stack_len; if self.value_stack.len() > value_stack_min { Ok(()) diff --git a/src/interpreter/value.rs b/src/interpreter/value.rs index aa91d379d..28e7bc156 100644 --- a/src/interpreter/value.rs +++ b/src/interpreter/value.rs @@ -1,7 +1,7 @@ use std::{i32, i64, u32, u64, f32}; use std::io; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use interpreter::Error; +use interpreter::{Error, UserError}; use interpreter::variable::VariableType; /// Runtime value. @@ -52,15 +52,15 @@ pub trait TransmuteInto { } /// Convert from and to little endian. -pub trait LittleEndianConvert where Self: Sized { +pub trait LittleEndianConvert where Self: Sized { /// Convert to little endian buffer. fn into_little_endian(self) -> Vec; /// Convert from little endian buffer. - fn from_little_endian(buffer: Vec) -> Result; + fn from_little_endian(buffer: Vec) -> Result>; } /// Arithmetic operations. -pub trait ArithmeticOps { +pub trait ArithmeticOps { /// Add two values. fn add(self, other: T) -> T; /// Subtract two values. @@ -68,11 +68,11 @@ pub trait ArithmeticOps { /// Multiply two values. fn mul(self, other: T) -> T; /// Divide two values. - fn div(self, other: T) -> Result; + fn div(self, other: T) -> Result>; } /// Integer value. -pub trait Integer: ArithmeticOps { +pub trait Integer: ArithmeticOps { /// Counts leading zeros in the bitwise representation of the value. fn leading_zeros(self) -> T; /// Counts trailing zeros in the bitwise representation of the value. @@ -84,11 +84,11 @@ pub trait Integer: ArithmeticOps { /// Get right bit rotation result. fn rotr(self, other: T) -> T; /// Get division remainder. - fn rem(self, other: T) -> Result; + fn rem(self, other: T) -> Result>; } /// Float-point value. -pub trait Float: ArithmeticOps { +pub trait Float: ArithmeticOps { /// Get absolute value. fn abs(self) -> T; /// Returns the largest integer less than or equal to a number. @@ -178,8 +178,8 @@ impl From for RuntimeValue { } } -impl TryInto for RuntimeValue { - fn try_into(self) -> Result { +impl TryInto> for RuntimeValue where E: UserError { + fn try_into(self) -> Result> { match self { RuntimeValue::I32(val) => Ok(val != 0), _ => Err(Error::Value(format!("32-bit int value expected"))), @@ -187,8 +187,8 @@ impl TryInto for RuntimeValue { } } -impl TryInto for RuntimeValue { - fn try_into(self) -> Result { +impl TryInto> for RuntimeValue where E: UserError { + fn try_into(self) -> Result> { match self { RuntimeValue::I32(val) => Ok(val), _ => Err(Error::Value(format!("32-bit int value expected"))), @@ -196,8 +196,8 @@ impl TryInto for RuntimeValue { } } -impl TryInto for RuntimeValue { - fn try_into(self) -> Result { +impl TryInto> for RuntimeValue where E: UserError { + fn try_into(self) -> Result> { match self { RuntimeValue::I64(val) => Ok(val), _ => Err(Error::Value(format!("64-bit int value expected"))), @@ -205,8 +205,8 @@ impl TryInto for RuntimeValue { } } -impl TryInto for RuntimeValue { - fn try_into(self) -> Result { +impl TryInto> for RuntimeValue where E: UserError { + fn try_into(self) -> Result> { match self { RuntimeValue::F32(val) => Ok(val), _ => Err(Error::Value(format!("32-bit float value expected"))), @@ -214,8 +214,8 @@ impl TryInto for RuntimeValue { } } -impl TryInto for RuntimeValue { - fn try_into(self) -> Result { +impl TryInto> for RuntimeValue where E: UserError { + fn try_into(self) -> Result> { match self { RuntimeValue::F64(val) => Ok(val), _ => Err(Error::Value(format!("64-bit float value expected"))), @@ -223,8 +223,8 @@ impl TryInto for RuntimeValue { } } -impl TryInto for RuntimeValue { - fn try_into(self) -> Result { +impl TryInto> for RuntimeValue where E: UserError { + fn try_into(self) -> Result> { match self { RuntimeValue::I32(val) => Ok(val as u32), _ => Err(Error::Value(format!("32-bit int value expected"))), @@ -232,8 +232,8 @@ impl TryInto for RuntimeValue { } } -impl TryInto for RuntimeValue { - fn try_into(self) -> Result { +impl TryInto> for RuntimeValue where E: UserError { + fn try_into(self) -> Result> { match self { RuntimeValue::I64(val) => Ok(val as u64), _ => Err(Error::Value(format!("64-bit int value expected"))), @@ -265,8 +265,8 @@ impl_wrap_into!(f64, f32); macro_rules! impl_try_truncate_into { ($from: ident, $into: ident) => { - impl TryTruncateInto<$into, Error> for $from { - fn try_truncate_into(self) -> Result<$into, Error> { + impl TryTruncateInto<$into, Error> for $from where E: UserError { + fn try_truncate_into(self) -> Result<$into, Error> { // Casting from a float to an integer will round the float towards zero // NOTE: currently this will cause Undefined Behavior if the rounded value cannot be represented by the // target integer type. This includes Inf and NaN. This is a bug and will be fixed. @@ -373,31 +373,31 @@ impl TransmuteInto for i64 { fn transmute_into(self) -> f64 { f64_from_bits(self as _) } } -impl LittleEndianConvert for i8 { +impl LittleEndianConvert for i8 where E: UserError { fn into_little_endian(self) -> Vec { vec![self as u8] } - fn from_little_endian(buffer: Vec) -> Result { + fn from_little_endian(buffer: Vec) -> Result> { buffer.get(0) .map(|v| *v as i8) .ok_or(Error::Value("invalid little endian buffer".into())) } } -impl LittleEndianConvert for u8 { +impl LittleEndianConvert for u8 where E: UserError { fn into_little_endian(self) -> Vec { vec![self] } - fn from_little_endian(buffer: Vec) -> Result { + fn from_little_endian(buffer: Vec) -> Result> { buffer.get(0) .cloned() .ok_or(Error::Value("invalid little endian buffer".into())) } } -impl LittleEndianConvert for i16 { +impl LittleEndianConvert for i16 where E: UserError { fn into_little_endian(self) -> Vec { let mut vec = Vec::with_capacity(2); vec.write_i16::(self) @@ -405,13 +405,13 @@ impl LittleEndianConvert for i16 { vec } - fn from_little_endian(buffer: Vec) -> Result { + fn from_little_endian(buffer: Vec) -> Result> { io::Cursor::new(buffer).read_i16::() .map_err(|e| Error::Value(e.to_string())) } } -impl LittleEndianConvert for u16 { +impl LittleEndianConvert for u16 where E: UserError { fn into_little_endian(self) -> Vec { let mut vec = Vec::with_capacity(2); vec.write_u16::(self) @@ -419,13 +419,13 @@ impl LittleEndianConvert for u16 { vec } - fn from_little_endian(buffer: Vec) -> Result { + fn from_little_endian(buffer: Vec) -> Result> { io::Cursor::new(buffer).read_u16::() .map_err(|e| Error::Value(e.to_string())) } } -impl LittleEndianConvert for i32 { +impl LittleEndianConvert for i32 where E: UserError { fn into_little_endian(self) -> Vec { let mut vec = Vec::with_capacity(4); vec.write_i32::(self) @@ -433,13 +433,13 @@ impl LittleEndianConvert for i32 { vec } - fn from_little_endian(buffer: Vec) -> Result { + fn from_little_endian(buffer: Vec) -> Result> { io::Cursor::new(buffer).read_i32::() .map_err(|e| Error::Value(e.to_string())) } } -impl LittleEndianConvert for u32 { +impl LittleEndianConvert for u32 where E: UserError { fn into_little_endian(self) -> Vec { let mut vec = Vec::with_capacity(4); vec.write_u32::(self) @@ -447,13 +447,13 @@ impl LittleEndianConvert for u32 { vec } - fn from_little_endian(buffer: Vec) -> Result { + fn from_little_endian(buffer: Vec) -> Result> { io::Cursor::new(buffer).read_u32::() .map_err(|e| Error::Value(e.to_string())) } } -impl LittleEndianConvert for i64 { +impl LittleEndianConvert for i64 where E: UserError { fn into_little_endian(self) -> Vec { let mut vec = Vec::with_capacity(8); vec.write_i64::(self) @@ -461,13 +461,13 @@ impl LittleEndianConvert for i64 { vec } - fn from_little_endian(buffer: Vec) -> Result { + fn from_little_endian(buffer: Vec) -> Result> { io::Cursor::new(buffer).read_i64::() .map_err(|e| Error::Value(e.to_string())) } } -impl LittleEndianConvert for f32 { +impl LittleEndianConvert for f32 where E: UserError { fn into_little_endian(self) -> Vec { let mut vec = Vec::with_capacity(4); vec.write_f32::(self) @@ -475,14 +475,14 @@ impl LittleEndianConvert for f32 { vec } - fn from_little_endian(buffer: Vec) -> Result { + fn from_little_endian(buffer: Vec) -> Result> { io::Cursor::new(buffer).read_u32::() .map(f32_from_bits) .map_err(|e| Error::Value(e.to_string())) } } -impl LittleEndianConvert for f64 { +impl LittleEndianConvert for f64 where E: UserError { fn into_little_endian(self) -> Vec { let mut vec = Vec::with_capacity(8); vec.write_f64::(self) @@ -490,7 +490,7 @@ impl LittleEndianConvert for f64 { vec } - fn from_little_endian(buffer: Vec) -> Result { + fn from_little_endian(buffer: Vec) -> Result> { io::Cursor::new(buffer).read_u64::() .map(f64_from_bits) .map_err(|e| Error::Value(e.to_string())) @@ -535,11 +535,11 @@ fn f64_from_bits(mut v: u64) -> f64 { macro_rules! impl_integer_arithmetic_ops { ($type: ident) => { - impl ArithmeticOps<$type> for $type { + impl ArithmeticOps<$type, E> for $type where E: UserError { fn add(self, other: $type) -> $type { self.wrapping_add(other) } fn sub(self, other: $type) -> $type { self.wrapping_sub(other) } fn mul(self, other: $type) -> $type { self.wrapping_mul(other) } - fn div(self, other: $type) -> Result<$type, Error> { + fn div(self, other: $type) -> Result<$type, Error> { if other == 0 { Err(Error::Value("Division by zero".to_owned())) } else { let (result, overflow) = self.overflowing_div(other); @@ -561,11 +561,11 @@ impl_integer_arithmetic_ops!(u64); macro_rules! impl_float_arithmetic_ops { ($type: ident) => { - impl ArithmeticOps<$type> for $type { + impl ArithmeticOps<$type, E> for $type where E: UserError { fn add(self, other: $type) -> $type { self + other } fn sub(self, other: $type) -> $type { self - other } fn mul(self, other: $type) -> $type { self * other } - fn div(self, other: $type) -> Result<$type, Error> { Ok(self / other) } + fn div(self, other: $type) -> Result<$type, Error> { Ok(self / other) } } } } @@ -575,13 +575,13 @@ impl_float_arithmetic_ops!(f64); macro_rules! impl_integer { ($type: ident) => { - impl Integer<$type> for $type { + impl Integer<$type, E> for $type where E: UserError { fn leading_zeros(self) -> $type { self.leading_zeros() as $type } fn trailing_zeros(self) -> $type { self.trailing_zeros() as $type } fn count_ones(self) -> $type { self.count_ones() as $type } fn rotl(self, other: $type) -> $type { self.rotate_left(other as u32) } fn rotr(self, other: $type) -> $type { self.rotate_right(other as u32) } - fn rem(self, other: $type) -> Result<$type, Error> { + fn rem(self, other: $type) -> Result<$type, Error> { if other == 0 { Err(Error::Value("Division by zero".to_owned())) } else { Ok(self.wrapping_rem(other)) } } @@ -596,7 +596,7 @@ impl_integer!(u64); macro_rules! impl_float { ($type: ident, $int_type: ident) => { - impl Float<$type> for $type { + impl Float<$type, E> for $type where E: UserError { fn abs(self) -> $type { self.abs() } fn floor(self) -> $type { self.floor() } fn ceil(self) -> $type { self.ceil() } diff --git a/src/interpreter/variable.rs b/src/interpreter/variable.rs index 50767ba70..30a088677 100644 --- a/src/interpreter/variable.rs +++ b/src/interpreter/variable.rs @@ -1,7 +1,7 @@ use std::fmt; use parking_lot::RwLock; use elements::{GlobalType, ValueType, TableElementType}; -use interpreter::Error; +use interpreter::{Error, UserError}; use interpreter::value::RuntimeValue; /// Variable type. @@ -20,35 +20,35 @@ pub enum VariableType { } /// Externally stored variable value. -pub trait ExternalVariableValue { +pub trait ExternalVariableValue { /// Get variable value. fn get(&self) -> RuntimeValue; /// Set variable value. - fn set(&mut self, value: RuntimeValue) -> Result<(), Error>; + fn set(&mut self, value: RuntimeValue) -> Result<(), Error>; } /// Variable instance. #[derive(Debug)] -pub struct VariableInstance { +pub struct VariableInstance { /// Is mutable? is_mutable: bool, /// Variable type. variable_type: VariableType, /// Global value. - value: RwLock, + value: RwLock>, } /// Enum variable value. -enum VariableValue { +enum VariableValue { /// Internal value. Internal(RuntimeValue), /// External value. - External(Box), + External(Box>), } -impl VariableInstance { +impl VariableInstance where E: UserError { /// New variable instance - pub fn new(is_mutable: bool, variable_type: VariableType, value: RuntimeValue) -> Result { + pub fn new(is_mutable: bool, variable_type: VariableType, value: RuntimeValue) -> Result> { // TODO: there is nothing about null value in specification + there is nothing about initializing missing table elements? => runtime check for nulls if !value.is_null() && value.variable_type() != Some(variable_type) { return Err(Error::Variable(format!("trying to initialize variable of type {:?} with value of type {:?}", variable_type, value.variable_type()))); @@ -62,12 +62,12 @@ impl VariableInstance { } /// New global variable - pub fn new_global(global_type: &GlobalType, value: RuntimeValue) -> Result { + pub fn new_global(global_type: &GlobalType, value: RuntimeValue) -> Result> { Self::new(global_type.is_mutable(), global_type.content_type().into(), value) } /// New global with externally stored value. - pub fn new_external_global(is_mutable: bool, variable_type: VariableType, value: Box) -> Result { + pub fn new_external_global(is_mutable: bool, variable_type: VariableType, value: Box>) -> Result> { // TODO: there is nothing about null value in specification + there is nothing about initializing missing table elements? => runtime check for nulls let current_value = value.get(); if !current_value.is_null() && current_value.variable_type() != Some(variable_type) { @@ -97,7 +97,7 @@ impl VariableInstance { } /// Set the value of the variable instance - pub fn set(&self, value: RuntimeValue) -> Result<(), Error> { + pub fn set(&self, value: RuntimeValue) -> Result<(), Error> { if !self.is_mutable { return Err(Error::Variable("trying to update immutable variable".into())); } @@ -109,7 +109,7 @@ impl VariableInstance { } } -impl VariableValue { +impl VariableValue where E: UserError { fn get(&self) -> RuntimeValue { match *self { VariableValue::Internal(ref value) => value.clone(), @@ -117,7 +117,7 @@ impl VariableValue { } } - fn set(&mut self, new_value: RuntimeValue) -> Result<(), Error> { + fn set(&mut self, new_value: RuntimeValue) -> Result<(), Error> { match *self { VariableValue::Internal(ref mut value) => { *value = new_value; @@ -147,7 +147,7 @@ impl From for VariableType { } } -impl fmt::Debug for VariableValue { +impl fmt::Debug for VariableValue where E: UserError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { VariableValue::Internal(ref value) => write!(f, "Variable.Internal({:?})", value), diff --git a/src/lib.rs b/src/lib.rs index 680de780d..8cc8e89e2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,10 @@ pub use elements::{ pub use interpreter::{ ProgramInstance, + DefaultProgramInstance, ModuleInstance, + DefaultModuleInstance, ModuleInstanceInterface, + DefaultModuleInstanceInterface, RuntimeValue, };