return custom user errors from native functions

This commit is contained in:
Svyatoslav Nikolsky
2017-08-01 13:16:25 +03:00
parent f9bfb53e33
commit a02fdf5836
15 changed files with 373 additions and 246 deletions

View File

@ -2,7 +2,7 @@ extern crate parity_wasm;
use std::env::args; use std::env::args;
use parity_wasm::{interpreter, ModuleInstanceInterface}; use parity_wasm::{interpreter, CustomModuleInstanceInterface};
fn main() { fn main() {
let args: Vec<_> = args().collect(); let args: Vec<_> = args().collect();

View File

@ -2,7 +2,7 @@ extern crate parity_wasm;
use std::env::args; use std::env::args;
use parity_wasm::{interpreter, ModuleInstanceInterface, RuntimeValue}; use parity_wasm::{interpreter, CustomModuleInstanceInterface, RuntimeValue};
use parity_wasm::elements::{Internal, External, Type, FunctionType, ValueType}; use parity_wasm::elements::{Internal, External, Type, FunctionType, ValueType};

View File

@ -13,7 +13,8 @@ use parity_wasm::interpreter::{
RuntimeValue, RuntimeValue,
ProgramInstance, ModuleInstance, ProgramInstance, ModuleInstance,
ItemIndex, ExportEntryType, ItemIndex, ExportEntryType,
Error as InterpreterError, Error as InternalInterpreterError,
InterpreterError
}; };
fn spec_test_module() -> elements::Module { fn spec_test_module() -> elements::Module {
@ -60,7 +61,12 @@ fn try_deserialize(base_dir: &str, module_path: &str) -> Result<elements::Module
fn try_load(base_dir: &str, module_path: &str) -> Result<(), parity_wasm::interpreter::Error> { fn try_load(base_dir: &str, module_path: &str) -> Result<(), parity_wasm::interpreter::Error> {
let module = try_deserialize(base_dir, module_path).map_err(|e| parity_wasm::interpreter::Error::Program(format!("{:?}", e)))?; 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 = ProgramInstance::new().expect("Failed creating program");
program.add_module("try_load", module, None).map(|_| ()) program.add_module("try_load", module, None)
.map(|_| ())
.map_err(|e| match e {
InterpreterError::Internal(e) => e,
_ => unreachable!(),
})
} }
fn runtime_value(test_val: &test::RuntimeValue) -> parity_wasm::RuntimeValue { fn runtime_value(test_val: &test::RuntimeValue) -> parity_wasm::RuntimeValue {
@ -90,7 +96,7 @@ fn runtime_values(test_vals: &[test::RuntimeValue]) -> Vec<parity_wasm::RuntimeV
} }
fn run_action(program: &ProgramInstance, action: &test::Action) fn run_action(program: &ProgramInstance, action: &test::Action)
-> Result<Option<parity_wasm::RuntimeValue>, InterpreterError> -> Result<Option<parity_wasm::RuntimeValue>, InternalInterpreterError>
{ {
match *action { match *action {
test::Action::Invoke { ref module, ref field, ref args } => { test::Action::Invoke { ref module, ref field, ref args } => {
@ -98,6 +104,10 @@ fn run_action(program: &ProgramInstance, action: &test::Action)
let module = module.trim_left_matches('$'); let module = module.trim_left_matches('$');
let module = program.module(&module).expect(&format!("Expected program to have loaded module {}", module)); let module = program.module(&module).expect(&format!("Expected program to have loaded module {}", module));
module.execute_export(&jstring_to_rstring(field), runtime_values(args).into()) module.execute_export(&jstring_to_rstring(field), runtime_values(args).into())
.map_err(|e| match e {
InterpreterError::Internal(e) => e,
_ => unreachable!(),
})
}, },
test::Action::Get { ref module, ref field, .. } => { test::Action::Get { ref module, ref field, .. } => {
let module = module.clone().unwrap_or("wasm_test".into()); let module = module.clone().unwrap_or("wasm_test".into());
@ -108,7 +118,7 @@ fn run_action(program: &ProgramInstance, action: &test::Action)
module.export_entry(field.as_ref(), &ExportEntryType::Any) module.export_entry(field.as_ref(), &ExportEntryType::Any)
.and_then(|i| match i { .and_then(|i| match i {
elements::Internal::Global(global_index) => Ok(ItemIndex::IndexSpace(global_index)), elements::Internal::Global(global_index) => Ok(ItemIndex::IndexSpace(global_index)),
_ => Err(InterpreterError::Global(format!("Expected to have exported global with name {}", field))), _ => Err(InternalInterpreterError::Global(format!("Expected to have exported global with name {}", field))),
}) })
.and_then(|g| module.global(g, None, None).map(|g| Some(g.get()))) .and_then(|g| module.global(g, None, None).map(|g| Some(g.get())))
} }

View File

@ -3,7 +3,7 @@ use std::collections::HashMap;
use builder::module; use builder::module;
use elements::{Module, ExportEntry, Internal, GlobalEntry, GlobalType, use elements::{Module, ExportEntry, Internal, GlobalEntry, GlobalType,
ValueType, InitExpr, Opcode, Opcodes}; ValueType, InitExpr, Opcode, Opcodes};
use interpreter::Error; use interpreter::{Error, CustomUserError, InterpreterError};
use interpreter::env_native::NATIVE_INDEX_FUNC_MIN; use interpreter::env_native::NATIVE_INDEX_FUNC_MIN;
use interpreter::module::{ModuleInstanceInterface, ModuleInstance, ExecutionParams, use interpreter::module::{ModuleInstanceInterface, ModuleInstance, ExecutionParams,
ItemIndex, CallerContext, ExportEntryType, InternalFunctionReference, InternalFunction, FunctionSignature}; ItemIndex, CallerContext, ExportEntryType, InternalFunctionReference, InternalFunction, FunctionSignature};
@ -78,12 +78,12 @@ pub struct EnvParams {
pub allow_memory_growth: bool, pub allow_memory_growth: bool,
} }
pub struct EnvModuleInstance { pub struct EnvModuleInstance<E: CustomUserError> {
_params: EnvParams, _params: EnvParams,
instance: ModuleInstance, instance: ModuleInstance<E>,
} }
impl EnvModuleInstance { impl<E> EnvModuleInstance<E> where E: CustomUserError {
pub fn new(params: EnvParams, module: Module) -> Result<Self, Error> { pub fn new(params: EnvParams, module: Module) -> Result<Self, Error> {
let mut instance = ModuleInstance::new(Weak::default(), "env".into(), module)?; let mut instance = ModuleInstance::new(Weak::default(), "env".into(), module)?;
instance.instantiate(None)?; instance.instantiate(None)?;
@ -95,12 +95,12 @@ impl EnvModuleInstance {
} }
} }
impl ModuleInstanceInterface for EnvModuleInstance { impl<E> ModuleInstanceInterface<E> for EnvModuleInstance<E> where E: CustomUserError {
fn execute_index(&self, index: u32, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> { fn execute_index(&self, index: u32, params: ExecutionParams<E>) -> Result<Option<RuntimeValue>, InterpreterError<E>> {
self.instance.execute_index(index, params) self.instance.execute_index(index, params)
} }
fn execute_export(&self, name: &str, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> { fn execute_export(&self, name: &str, params: ExecutionParams<E>) -> Result<Option<RuntimeValue>, InterpreterError<E>> {
self.instance.execute_export(name, params) self.instance.execute_export(name, params)
} }
@ -116,7 +116,7 @@ impl ModuleInstanceInterface for EnvModuleInstance {
self.instance.memory(index) self.instance.memory(index)
} }
fn global<'a>(&self, index: ItemIndex, variable_type: Option<VariableType>, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<Arc<VariableInstance>, Error> { fn global<'a>(&self, index: ItemIndex, variable_type: Option<VariableType>, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>>) -> Result<Arc<VariableInstance>, Error> {
self.instance.global(index, variable_type, externals) self.instance.global(index, variable_type, externals)
} }
@ -128,11 +128,11 @@ impl ModuleInstanceInterface for EnvModuleInstance {
self.instance.function_type_by_index(type_index) self.instance.function_type_by_index(type_index)
} }
fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<InternalFunctionReference<'a>, Error> { fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>>) -> Result<InternalFunctionReference<'a, E>, Error> {
self.instance.function_reference(index, externals) 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<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<InternalFunctionReference<'a>, Error> { fn function_reference_indirect<'a>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>>) -> Result<InternalFunctionReference<'a, E>, Error> {
self.instance.function_reference_indirect(table_idx, type_idx, func_idx, externals) self.instance.function_reference_indirect(table_idx, type_idx, func_idx, externals)
} }
@ -140,12 +140,13 @@ impl ModuleInstanceInterface for EnvModuleInstance {
Ok(None) Ok(None)
} }
fn call_internal_function(&self, outer: CallerContext, index: u32) -> Result<Option<RuntimeValue>, Error> { fn call_internal_function(&self, outer: CallerContext<E>, index: u32) -> Result<Option<RuntimeValue>, InterpreterError<E>> {
// to make interpreter independent of *SCRIPTEN runtime, just make abort/assert = interpreter Error // to make interpreter independent of *SCRIPTEN runtime, just make abort/assert = interpreter Error
match index { match index {
INDEX_FUNC_ABORT => self.global(ItemIndex::IndexSpace(INDEX_GLOBAL_ABORT), Some(VariableType::I32), None) INDEX_FUNC_ABORT => self.global(ItemIndex::IndexSpace(INDEX_GLOBAL_ABORT), Some(VariableType::I32), None)
.and_then(|g| g.set(RuntimeValue::I32(1))) .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::<i32>() INDEX_FUNC_ASSERT => outer.value_stack.pop_as::<i32>()
.and_then(|condition| if condition == 0 { .and_then(|condition| if condition == 0 {
self.global(ItemIndex::IndexSpace(INDEX_GLOBAL_ABORT), Some(VariableType::I32), None) 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()))) .and_then(|_| Err(Error::Trap("assertion failed".into())))
} else { } else {
Ok(None) Ok(None)
}), })
.map_err(Into::into),
INDEX_FUNC_ENLARGE_MEMORY => Ok(Some(RuntimeValue::I32(0))), // TODO: support memory enlarge 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) INDEX_FUNC_GET_TOTAL_MEMORY => self.global(ItemIndex::IndexSpace(INDEX_GLOBAL_TOTAL_MEMORY), Some(VariableType::I32), None)
.map(|g| g.get()) .map(|g| g.get())
.map(Some), .map(Some)
INDEX_FUNC_MIN_NONUSED ... INDEX_FUNC_MAX => Err(Error::Trap("unimplemented".into())), .map_err(Into::into),
_ => Err(Error::Trap(format!("trying to call function with index {} in env module", index))), 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<EnvModuleInstance, Error> { pub fn env_module<E: CustomUserError>(params: EnvParams) -> Result<EnvModuleInstance<E>, Error> {
debug_assert!(params.total_stack < params.total_memory); debug_assert!(params.total_stack < params.total_memory);
debug_assert!((params.total_stack % LINEAR_MEMORY_PAGE_SIZE) == 0); debug_assert!((params.total_stack % LINEAR_MEMORY_PAGE_SIZE) == 0);
debug_assert!((params.total_memory % LINEAR_MEMORY_PAGE_SIZE) == 0); debug_assert!((params.total_memory % LINEAR_MEMORY_PAGE_SIZE) == 0);

View File

@ -3,7 +3,7 @@ use std::collections::HashMap;
use std::borrow::Cow; use std::borrow::Cow;
use parking_lot::RwLock; use parking_lot::RwLock;
use elements::{Internal, ValueType}; use elements::{Internal, ValueType};
use interpreter::Error; use interpreter::{Error, CustomUserError, InterpreterError};
use interpreter::module::{ModuleInstanceInterface, ExecutionParams, ItemIndex, use interpreter::module::{ModuleInstanceInterface, ExecutionParams, ItemIndex,
CallerContext, ExportEntryType, InternalFunctionReference, InternalFunction, FunctionSignature}; CallerContext, ExportEntryType, InternalFunctionReference, InternalFunction, FunctionSignature};
use interpreter::memory::MemoryInstance; use interpreter::memory::MemoryInstance;
@ -17,9 +17,9 @@ pub const NATIVE_INDEX_FUNC_MIN: u32 = 10001;
pub const NATIVE_INDEX_GLOBAL_MIN: u32 = 20001; pub const NATIVE_INDEX_GLOBAL_MIN: u32 = 20001;
/// User functions executor. /// User functions executor.
pub trait UserFunctionExecutor { pub trait UserFunctionExecutor<E: CustomUserError> {
/// Execute function with given name. /// Execute function with given name.
fn execute(&mut self, name: &str, context: CallerContext) -> Result<Option<RuntimeValue>, Error>; fn execute(&mut self, name: &str, context: CallerContext<E>) -> Result<Option<RuntimeValue>, InterpreterError<E>>;
} }
/// User function descriptor /// User function descriptor
@ -68,21 +68,21 @@ impl UserFunctionDescriptor {
} }
/// Set of user-defined module elements. /// Set of user-defined module elements.
pub struct UserDefinedElements<'a> { pub struct UserDefinedElements<'a, E: 'a + CustomUserError> {
/// User globals list. /// User globals list.
pub globals: HashMap<String, Arc<VariableInstance>>, pub globals: HashMap<String, Arc<VariableInstance>>,
/// User functions list. /// User functions list.
pub functions: Cow<'static, [UserFunctionDescriptor]>, pub functions: Cow<'static, [UserFunctionDescriptor]>,
/// Functions executor. /// Functions executor.
pub executor: Option<&'a mut UserFunctionExecutor>, pub executor: Option<&'a mut UserFunctionExecutor<E>>,
} }
/// Native module instance. /// Native module instance.
pub struct NativeModuleInstance<'a> { pub struct NativeModuleInstance<'a, E: 'a + CustomUserError> {
/// Underllying module reference. /// Underllying module reference.
env: Arc<ModuleInstanceInterface>, env: Arc<ModuleInstanceInterface<E>>,
/// User function executor. /// User function executor.
executor: RwLock<Option<&'a mut UserFunctionExecutor>>, executor: RwLock<Option<&'a mut UserFunctionExecutor<E>>>,
/// By-name functions index. /// By-name functions index.
functions_by_name: HashMap<String, u32>, functions_by_name: HashMap<String, u32>,
/// User functions list. /// User functions list.
@ -93,9 +93,9 @@ pub struct NativeModuleInstance<'a> {
globals: Vec<Arc<VariableInstance>>, globals: Vec<Arc<VariableInstance>>,
} }
impl<'a> NativeModuleInstance<'a> { impl<'a, E> NativeModuleInstance<'a, E> where E: CustomUserError {
/// Create new native module /// Create new native module
pub fn new(env: Arc<ModuleInstanceInterface>, elements: UserDefinedElements<'a>) -> Result<Self, Error> { pub fn new(env: Arc<ModuleInstanceInterface<E>>, elements: UserDefinedElements<'a, E>) -> Result<Self, Error> {
if !elements.functions.is_empty() && elements.executor.is_none() { 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())); return Err(Error::Function("trying to construct native env module with functions, but without executor".into()));
} }
@ -111,12 +111,12 @@ impl<'a> NativeModuleInstance<'a> {
} }
} }
impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { impl<'a, E> ModuleInstanceInterface<E> for NativeModuleInstance<'a, E> where E: CustomUserError {
fn execute_index(&self, index: u32, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> { fn execute_index(&self, index: u32, params: ExecutionParams<E>) -> Result<Option<RuntimeValue>, InterpreterError<E>> {
self.env.execute_index(index, params) self.env.execute_index(index, params)
} }
fn execute_export(&self, name: &str, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> { fn execute_export(&self, name: &str, params: ExecutionParams<E>) -> Result<Option<RuntimeValue>, InterpreterError<E>> {
self.env.execute_export(name, params) self.env.execute_export(name, params)
} }
@ -155,7 +155,7 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> {
self.env.memory(index) self.env.memory(index)
} }
fn global<'b>(&self, global_index: ItemIndex, variable_type: Option<VariableType>, externals: Option<&'b HashMap<String, Arc<ModuleInstanceInterface + 'b>>>) -> Result<Arc<VariableInstance>, Error> { fn global<'b>(&self, global_index: ItemIndex, variable_type: Option<VariableType>, externals: Option<&'b HashMap<String, Arc<ModuleInstanceInterface<E> + 'b>>>) -> Result<Arc<VariableInstance>, Error> {
let index = match global_index { let index = match global_index {
ItemIndex::IndexSpace(index) | ItemIndex::Internal(index) => index, ItemIndex::IndexSpace(index) | ItemIndex::Internal(index) => index,
ItemIndex::External(_) => unreachable!("trying to get global, exported by native env module"), ItemIndex::External(_) => unreachable!("trying to get global, exported by native env module"),
@ -190,11 +190,11 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> {
self.function_type(ItemIndex::Internal(type_index)) self.function_type(ItemIndex::Internal(type_index))
} }
fn function_reference<'b>(&self, index: ItemIndex, externals: Option<&'b HashMap<String, Arc<ModuleInstanceInterface + 'b>>>) -> Result<InternalFunctionReference<'b>, Error> { fn function_reference<'b>(&self, index: ItemIndex, externals: Option<&'b HashMap<String, Arc<ModuleInstanceInterface<E> + 'b>>>) -> Result<InternalFunctionReference<'b, E>, Error> {
self.env.function_reference(index, externals) 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<String, Arc<ModuleInstanceInterface + 'b>>>) -> Result<InternalFunctionReference<'b>, Error> { fn function_reference_indirect<'b>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'b HashMap<String, Arc<ModuleInstanceInterface<E> + 'b>>>) -> Result<InternalFunctionReference<'b, E>, Error> {
self.env.function_reference_indirect(table_idx, type_idx, func_idx, externals) self.env.function_reference_indirect(table_idx, type_idx, func_idx, externals)
} }
@ -202,14 +202,14 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> {
Ok(None) Ok(None)
} }
fn call_internal_function(&self, outer: CallerContext, index: u32) -> Result<Option<RuntimeValue>, Error> { fn call_internal_function(&self, outer: CallerContext<E>, index: u32) -> Result<Option<RuntimeValue>, InterpreterError<E>> {
if index < NATIVE_INDEX_FUNC_MIN || index >= NATIVE_INDEX_GLOBAL_MIN { if index < NATIVE_INDEX_FUNC_MIN || index >= NATIVE_INDEX_GLOBAL_MIN {
return self.env.call_internal_function(outer, index); return self.env.call_internal_function(outer, index);
} }
self.functions self.functions
.get((index - NATIVE_INDEX_FUNC_MIN) as usize) .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() .and_then(|f| self.executor.write()
.as_mut() .as_mut()
.expect("function existss; if function exists, executor must also exists [checked in constructor]; qed") .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. /// Create wrapper for env module with given native user functions.
pub fn env_native_module<'a>(env: Arc<ModuleInstanceInterface>, user_elements: UserDefinedElements<'a>) -> Result<NativeModuleInstance, Error> { pub fn env_native_module<'a, E: CustomUserError>(env: Arc<ModuleInstanceInterface<E>>, user_elements: UserDefinedElements<'a, E>) -> Result<NativeModuleInstance<E>, Error> {
NativeModuleInstance::new(env, user_elements) NativeModuleInstance::new(env, user_elements)
} }

View File

@ -1,7 +1,7 @@
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use std::collections::HashMap; use std::collections::HashMap;
use elements::{ImportSection, ImportEntry, External, Internal}; use elements::{ImportSection, ImportEntry, External, Internal};
use interpreter::Error; use interpreter::{Error, CustomUserError};
use interpreter::memory::MemoryInstance; use interpreter::memory::MemoryInstance;
use interpreter::module::{ModuleInstanceInterface, ItemIndex, ExportEntryType, FunctionSignature}; use interpreter::module::{ModuleInstanceInterface, ItemIndex, ExportEntryType, FunctionSignature};
use interpreter::program::ProgramInstanceEssence; use interpreter::program::ProgramInstanceEssence;
@ -9,9 +9,9 @@ use interpreter::table::TableInstance;
use interpreter::variable::{VariableInstance, VariableType}; use interpreter::variable::{VariableInstance, VariableType};
/// Module imports. /// Module imports.
pub struct ModuleImports { pub struct ModuleImports<E: CustomUserError> {
/// Program instance. /// Program instance.
program: Weak<ProgramInstanceEssence>, program: Weak<ProgramInstanceEssence<E>>,
/// External functions. /// External functions.
functions: Vec<usize>, functions: Vec<usize>,
/// External tables. /// External tables.
@ -22,9 +22,9 @@ pub struct ModuleImports {
globals: Vec<usize>, globals: Vec<usize>,
} }
impl ModuleImports { impl<E> ModuleImports<E> where E: CustomUserError {
/// Create new imports for given import section. /// Create new imports for given import section.
pub fn new(program: Weak<ProgramInstanceEssence>, import_section: Option<&ImportSection>) -> Self { pub fn new(program: Weak<ProgramInstanceEssence<E>>, import_section: Option<&ImportSection>) -> Self {
let mut functions = Vec::new(); let mut functions = Vec::new();
let mut tables = Vec::new(); let mut tables = Vec::new();
let mut memory = Vec::new(); let mut memory = Vec::new();
@ -104,7 +104,7 @@ impl ModuleImports {
} }
/// Get module reference. /// Get module reference.
pub fn module<'a>(&self, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>, name: &str) -> Result<Arc<ModuleInstanceInterface + 'a>, Error> { pub fn module<'a>(&self, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>>, name: &str) -> Result<Arc<ModuleInstanceInterface<E> + 'a>, Error> {
if let Some(externals) = externals { if let Some(externals) = externals {
if let Some(module) = externals.get(name).cloned() { if let Some(module) = externals.get(name).cloned() {
return Ok(module); return Ok(module);
@ -118,7 +118,7 @@ impl ModuleImports {
} }
/// Get function index. /// Get function index.
pub fn function<'a>(&self, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>, import: &ImportEntry, required_type: Option<FunctionSignature>) -> Result<u32, Error> { pub fn function<'a>(&self, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>>, import: &ImportEntry, required_type: Option<FunctionSignature>) -> Result<u32, Error> {
let (_, export) = self.external_export(externals, import, &required_type.map(|ft| ExportEntryType::Function(ft)).unwrap_or(ExportEntryType::Any))?; 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 { if let Internal::Function(external_index) = export {
return Ok(external_index); return Ok(external_index);
@ -128,7 +128,7 @@ impl ModuleImports {
} }
/// Get table reference. /// Get table reference.
pub fn table<'a>(&self, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>, import: &ImportEntry) -> Result<Arc<TableInstance>, Error> { pub fn table<'a>(&self, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>>, import: &ImportEntry) -> Result<Arc<TableInstance>, Error> {
let (module, export) = self.external_export(externals, import, &ExportEntryType::Any)?; let (module, export) = self.external_export(externals, import, &ExportEntryType::Any)?;
if let Internal::Table(external_index) = export { if let Internal::Table(external_index) = export {
return module.table(ItemIndex::Internal(external_index)); return module.table(ItemIndex::Internal(external_index));
@ -138,7 +138,7 @@ impl ModuleImports {
} }
/// Get memory reference. /// Get memory reference.
pub fn memory<'a>(&self, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>, import: &ImportEntry) -> Result<Arc<MemoryInstance>, Error> { pub fn memory<'a>(&self, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>>, import: &ImportEntry) -> Result<Arc<MemoryInstance>, Error> {
let (module, export) = self.external_export(externals, import, &ExportEntryType::Any)?; let (module, export) = self.external_export(externals, import, &ExportEntryType::Any)?;
if let Internal::Memory(external_index) = export { if let Internal::Memory(external_index) = export {
return module.memory(ItemIndex::Internal(external_index)); return module.memory(ItemIndex::Internal(external_index));
@ -148,7 +148,7 @@ impl ModuleImports {
} }
/// Get global reference. /// Get global reference.
pub fn global<'a>(&self, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>, import: &ImportEntry, required_type: Option<VariableType>) -> Result<Arc<VariableInstance>, Error> { pub fn global<'a>(&self, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>>, import: &ImportEntry, required_type: Option<VariableType>) -> Result<Arc<VariableInstance>, Error> {
let (module, export) = self.external_export(externals, import, &required_type.clone().map(|rt| ExportEntryType::Global(rt)).unwrap_or(ExportEntryType::Any))?; 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 { if let Internal::Global(external_index) = export {
return module.global(ItemIndex::Internal(external_index), required_type, externals); 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()))) Err(Error::Program(format!("wrong import {} from module {} (expecting global)", import.field(), import.module())))
} }
fn external_export<'a>(&self, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>, import: &ImportEntry, required_type: &ExportEntryType) -> Result<(Arc<ModuleInstanceInterface + 'a>, Internal), Error> { fn external_export<'a>(&self, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>>, import: &ImportEntry, required_type: &ExportEntryType) -> Result<(Arc<ModuleInstanceInterface<E> + 'a>, Internal), Error> {
self.module(externals, import.module()) self.module(externals, import.module())
.and_then(|m| .and_then(|m|
m.export_entry(import.field(), required_type) m.export_entry(import.field(), required_type)

View File

@ -2,6 +2,19 @@
/// Interpreter error. /// Interpreter error.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum InterpreterError<E: CustomUserError> {
/// Internal error.
Internal(Error),
/// Custom user error.
User(E),
}
/// Custom user error.
pub trait CustomUserError: 'static + ::std::fmt::Display + ::std::fmt::Debug + Clone + PartialEq {
}
/// Internal interpreter error.
#[derive(Debug, Clone, PartialEq)]
pub enum Error { pub enum Error {
/// Program-level error. /// Program-level error.
Program(String), Program(String),
@ -35,6 +48,12 @@ pub enum Error {
Trap(String), Trap(String),
} }
impl<E> From<Error> for InterpreterError<E> where E: CustomUserError {
fn from(other: Error) -> Self {
InterpreterError::Internal(other)
}
}
impl Into<String> for Error { impl Into<String> for Error {
fn into(self) -> String { fn into(self) -> String {
match self { match self {
@ -57,6 +76,16 @@ impl Into<String> for Error {
} }
} }
/// Dummy user error.
#[derive(Debug, Clone, PartialEq)]
pub struct DummyCustomUserError;
impl CustomUserError for DummyCustomUserError {}
impl ::std::fmt::Display for DummyCustomUserError {
fn fmt(&self, _f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { Ok(()) }
}
mod env; mod env;
mod env_native; mod env_native;
mod imports; mod imports;
@ -74,10 +103,24 @@ mod variable;
mod tests; mod tests;
pub use self::memory::MemoryInstance; pub use self::memory::MemoryInstance;
pub use self::module::{ModuleInstance, ModuleInstanceInterface, ItemIndex, ExportEntryType, CallerContext, ExecutionParams, FunctionSignature}; pub use self::module::{ModuleInstance as CustomModuleInstance,
ModuleInstanceInterface as CustomModuleInstanceInterface,
ItemIndex, ExportEntryType, CallerContext, ExecutionParams, FunctionSignature};
pub use self::table::TableInstance; pub use self::table::TableInstance;
pub use self::program::ProgramInstance; pub use self::program::ProgramInstance as CustomProgramInstance;
pub use self::value::RuntimeValue; pub use self::value::RuntimeValue;
pub use self::variable::{VariableInstance, VariableType, ExternalVariableValue}; pub use self::variable::{VariableInstance, VariableType, ExternalVariableValue};
pub use self::env_native::{env_native_module, UserDefinedElements, UserFunctionExecutor, UserFunctionDescriptor}; pub use self::env_native::{env_native_module, UserDefinedElements, UserFunctionExecutor, UserFunctionDescriptor};
pub use self::env::EnvParams; pub use self::env::EnvParams;
/// Default type of ProgramInstance if you do not need any custom user errors.
/// To work with custom user errors or interpreter internals, use CustomProgramInstance.
pub type ProgramInstance = self::program::ProgramInstance<DummyCustomUserError>;
/// Default type of ModuleInstance if you do not need any custom user errors.
/// To work with custom user errors or interpreter internals, use CustomModuleInstance.
pub type ModuleInstance = self::module::ModuleInstance<DummyCustomUserError>;
/// Default type of ModuleInstanceInterface if you do not need any custom user errors.
/// To work with custom user errors or interpreter internals, use CustomModuleInstanceInterface.
pub type ModuleInstanceInterface = self::module::ModuleInstanceInterface<DummyCustomUserError>;

View File

@ -3,7 +3,7 @@ use std::iter::repeat;
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use std::fmt; use std::fmt;
use elements::{Module, InitExpr, Opcode, Type, FunctionType, Internal, External, BlockType, ResizableLimits, Local, ValueType}; use elements::{Module, InitExpr, Opcode, Type, FunctionType, Internal, External, BlockType, ResizableLimits, Local, ValueType};
use interpreter::Error; use interpreter::{Error, CustomUserError, InterpreterError};
use interpreter::env_native::UserFunctionDescriptor; use interpreter::env_native::UserFunctionDescriptor;
use interpreter::imports::ModuleImports; use interpreter::imports::ModuleImports;
use interpreter::memory::MemoryInstance; use interpreter::memory::MemoryInstance;
@ -21,12 +21,12 @@ const DEFAULT_VALUE_STACK_LIMIT: usize = 16384;
const DEFAULT_FRAME_STACK_LIMIT: usize = 1024; const DEFAULT_FRAME_STACK_LIMIT: usize = 1024;
/// Execution context. /// Execution context.
#[derive(Default, Clone)] #[derive(Clone)]
pub struct ExecutionParams<'a> { pub struct ExecutionParams<'a, E: CustomUserError> {
/// Arguments. /// Arguments.
pub args: Vec<RuntimeValue>, pub args: Vec<RuntimeValue>,
/// Execution-local external modules. /// Execution-local external modules.
pub externals: HashMap<String, Arc<ModuleInstanceInterface + 'a>>, pub externals: HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>,
} }
/// Export type. /// Export type.
@ -50,11 +50,11 @@ pub enum FunctionSignature<'a> {
} }
/// Module instance API. /// Module instance API.
pub trait ModuleInstanceInterface { pub trait ModuleInstanceInterface<E: CustomUserError> {
/// Execute function with the given index. /// Execute function with the given index.
fn execute_index(&self, index: u32, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error>; fn execute_index(&self, index: u32, params: ExecutionParams<E>) -> Result<Option<RuntimeValue>, InterpreterError<E>>;
/// Execute function with the given export name. /// Execute function with the given export name.
fn execute_export(&self, name: &str, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error>; fn execute_export(&self, name: &str, params: ExecutionParams<E>) -> Result<Option<RuntimeValue>, InterpreterError<E>>;
/// Get export entry. /// Get export entry.
fn export_entry<'a>(&self, name: &str, required_type: &ExportEntryType) -> Result<Internal, Error>; fn export_entry<'a>(&self, name: &str, required_type: &ExportEntryType) -> Result<Internal, Error>;
/// Get table reference. /// Get table reference.
@ -62,19 +62,19 @@ pub trait ModuleInstanceInterface {
/// Get memory reference. /// Get memory reference.
fn memory(&self, index: ItemIndex) -> Result<Arc<MemoryInstance>, Error>; fn memory(&self, index: ItemIndex) -> Result<Arc<MemoryInstance>, Error>;
/// Get global reference. /// Get global reference.
fn global<'a>(&self, index: ItemIndex, variable_type: Option<VariableType>, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<Arc<VariableInstance>, Error>; fn global<'a>(&self, index: ItemIndex, variable_type: Option<VariableType>, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>>) -> Result<Arc<VariableInstance>, Error>;
/// Get function type for given function index. /// Get function type for given function index.
fn function_type(&self, function_index: ItemIndex) -> Result<FunctionSignature, Error>; fn function_type(&self, function_index: ItemIndex) -> Result<FunctionSignature, Error>;
/// Get function type for given function index. /// Get function type for given function index.
fn function_type_by_index(&self, type_index: u32) -> Result<FunctionSignature, Error>; fn function_type_by_index(&self, type_index: u32) -> Result<FunctionSignature, Error>;
/// Get function reference. /// Get function reference.
fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<InternalFunctionReference<'a>, Error>; fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>>) -> Result<InternalFunctionReference<'a, E>, Error>;
/// Get function indirect reference. /// Get function indirect reference.
fn function_reference_indirect<'a>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<InternalFunctionReference<'a>, Error>; fn function_reference_indirect<'a>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>>) -> Result<InternalFunctionReference<'a, E>, Error>;
/// Get internal function for interpretation. /// Get internal function for interpretation.
fn function_body<'a>(&'a self, internal_index: u32) -> Result<Option<InternalFunction<'a>>, Error>; fn function_body<'a>(&'a self, internal_index: u32) -> Result<Option<InternalFunction<'a>>, Error>;
/// Call function with given internal index. /// Call function with given internal index.
fn call_internal_function(&self, outer: CallerContext, index: u32) -> Result<Option<RuntimeValue>, Error>; fn call_internal_function(&self, outer: CallerContext<E>, index: u32) -> Result<Option<RuntimeValue>, InterpreterError<E>>;
} }
/// Item index in items index space. /// Item index in items index space.
@ -89,7 +89,7 @@ pub enum ItemIndex {
} }
/// Module instance. /// Module instance.
pub struct ModuleInstance { pub struct ModuleInstance<E: CustomUserError> {
/// Module name. /// Module name.
name: String, name: String,
/// Module. /// Module.
@ -97,7 +97,7 @@ pub struct ModuleInstance {
/// Function labels. /// Function labels.
functions_labels: HashMap<u32, HashMap<usize, usize>>, functions_labels: HashMap<u32, HashMap<usize, usize>>,
/// Module imports. /// Module imports.
imports: ModuleImports, imports: ModuleImports<E>,
/// Module exports. /// Module exports.
exports: HashMap<String, Vec<Internal>>, exports: HashMap<String, Vec<Internal>>,
/// Tables. /// Tables.
@ -109,7 +109,7 @@ pub struct ModuleInstance {
} }
/// Caller context. /// Caller context.
pub struct CallerContext<'a> { pub struct CallerContext<'a, E: 'a + CustomUserError> {
/// Value stack limit /// Value stack limit
pub value_stack_limit: usize, pub value_stack_limit: usize,
/// Frame stack limit /// Frame stack limit
@ -117,19 +117,19 @@ pub struct CallerContext<'a> {
/// Stack of the input parameters /// Stack of the input parameters
pub value_stack: &'a mut StackWithLimit<RuntimeValue>, pub value_stack: &'a mut StackWithLimit<RuntimeValue>,
/// Execution-local external modules. /// Execution-local external modules.
pub externals: &'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>, pub externals: &'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>,
} }
/// Internal function reference. /// Internal function reference.
#[derive(Clone)] #[derive(Clone)]
pub struct InternalFunctionReference<'a> { pub struct InternalFunctionReference<'a, E: CustomUserError> {
/// Module reference. /// Module reference.
pub module: Arc<ModuleInstanceInterface + 'a>, pub module: Arc<ModuleInstanceInterface<E> + 'a>,
/// Internal function index. /// Internal function index.
pub internal_index: u32, pub internal_index: u32,
} }
impl<'a> fmt::Debug for InternalFunctionReference<'a> { impl<'a, E> fmt::Debug for InternalFunctionReference<'a, E> where E: CustomUserError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "InternalFunctionReference") write!(f, "InternalFunctionReference")
} }
@ -145,9 +145,9 @@ pub struct InternalFunction<'a> {
pub labels: &'a HashMap<usize, usize>, pub labels: &'a HashMap<usize, usize>,
} }
impl<'a> ExecutionParams<'a> { impl<'a, E> ExecutionParams<'a, E> where E: CustomUserError {
/// Create new execution params with given externa; module override. /// Create new execution params with given externa; module override.
pub fn with_external(name: String, module: Arc<ModuleInstanceInterface + 'a>) -> Self { pub fn with_external(name: String, module: Arc<ModuleInstanceInterface<E> + 'a>) -> Self {
let mut externals = HashMap::new(); let mut externals = HashMap::new();
externals.insert(name, module); externals.insert(name, module);
ExecutionParams { ExecutionParams {
@ -163,8 +163,17 @@ impl<'a> ExecutionParams<'a> {
} }
} }
impl<'a> From<Vec<RuntimeValue>> for ExecutionParams<'a> { impl<'a, E> Default for ExecutionParams<'a, E> where E: CustomUserError {
fn from(args: Vec<RuntimeValue>) -> ExecutionParams<'a> { fn default() -> Self {
ExecutionParams {
args: Vec::default(),
externals: HashMap::default(),
}
}
}
impl<'a, E> From<Vec<RuntimeValue>> for ExecutionParams<'a, E> where E: CustomUserError {
fn from(args: Vec<RuntimeValue>) -> ExecutionParams<'a, E> {
ExecutionParams { ExecutionParams {
args: args, args: args,
externals: HashMap::new(), externals: HashMap::new(),
@ -172,9 +181,9 @@ impl<'a> From<Vec<RuntimeValue>> for ExecutionParams<'a> {
} }
} }
impl ModuleInstance { impl<E> ModuleInstance<E> where E: CustomUserError {
/// Instantiate given module within program context. /// Instantiate given module within program context.
pub fn new<'a>(program: Weak<ProgramInstanceEssence>, name: String, module: Module) -> Result<Self, Error> { pub fn new<'a>(program: Weak<ProgramInstanceEssence<E>>, name: String, module: Module) -> Result<Self, Error> {
// load entries from import section // load entries from import section
let imports = ModuleImports::new(program, module.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. /// Run instantiation-time procedures (validation). Module is not completely validated until this call.
pub fn instantiate<'a>(&mut self, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<(), Error> { pub fn instantiate<'a>(&mut self, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>>) -> Result<(), Error> {
// validate start section // validate start section
if let Some(start_function) = self.module.start_section() { if let Some(start_function) = self.module.start_section() {
let func_type_index = self.require_function(ItemIndex::IndexSpace(start_function))?; let func_type_index = self.require_function(ItemIndex::IndexSpace(start_function))?;
@ -388,7 +397,7 @@ impl ModuleInstance {
} }
/// Run start function [if any]. /// Run start function [if any].
pub fn run_start_function(&self) -> Result<(), Error> { pub fn run_start_function(&self) -> Result<(), InterpreterError<E>> {
// execute start function (if any) // execute start function (if any)
if let Some(start_function) = self.module.start_section() { if let Some(start_function) = self.module.start_section() {
self.execute_index(start_function, ExecutionParams::default())?; self.execute_index(start_function, ExecutionParams::default())?;
@ -396,7 +405,7 @@ impl ModuleInstance {
Ok(()) Ok(())
} }
fn self_ref<'a>(&self, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<Arc<ModuleInstanceInterface + 'a>, Error> { fn self_ref<'a>(&self, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>>) -> Result<Arc<ModuleInstanceInterface<E> + 'a>, Error> {
self.imports.module(externals, &self.name) self.imports.module(externals, &self.name)
} }
@ -420,8 +429,8 @@ impl ModuleInstance {
} }
} }
impl ModuleInstanceInterface for ModuleInstance { impl<E> ModuleInstanceInterface<E> for ModuleInstance<E> where E: CustomUserError {
fn execute_index(&self, index: u32, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> { fn execute_index(&self, index: u32, params: ExecutionParams<E>) -> Result<Option<RuntimeValue>, InterpreterError<E>> {
let ExecutionParams { args, externals } = params; let ExecutionParams { args, externals } = params;
let mut args = StackWithLimit::with_data(args, DEFAULT_VALUE_STACK_LIMIT); let mut args = StackWithLimit::with_data(args, DEFAULT_VALUE_STACK_LIMIT);
let function_reference = self.function_reference(ItemIndex::IndexSpace(index), Some(&externals))?; 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) function_reference.module.call_internal_function(function_context, function_reference.internal_index)
} }
fn execute_export(&self, name: &str, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> { fn execute_export(&self, name: &str, params: ExecutionParams<E>) -> Result<Option<RuntimeValue>, InterpreterError<E>> {
let index = self.exports.get(name) let index = self.exports.get(name)
.ok_or(Error::Function(format!("missing executable export with name {}", name))) .ok_or(Error::Function(format!("missing executable export with name {}", name)))
.and_then(|l| l.iter() .and_then(|l| l.iter()
@ -494,7 +503,7 @@ impl ModuleInstanceInterface for ModuleInstance {
} }
} }
fn global<'a>(&self, index: ItemIndex, variable_type: Option<VariableType>, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<Arc<VariableInstance>, Error> { fn global<'a>(&self, index: ItemIndex, variable_type: Option<VariableType>, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>>) -> Result<Arc<VariableInstance>, Error> {
match self.imports.parse_global_index(index) { match self.imports.parse_global_index(index) {
ItemIndex::IndexSpace(_) => unreachable!("parse_global_index resolves IndexSpace option"), ItemIndex::IndexSpace(_) => unreachable!("parse_global_index resolves IndexSpace option"),
ItemIndex::Internal(index) => self.globals.get(index as usize).cloned() ItemIndex::Internal(index) => self.globals.get(index as usize).cloned()
@ -533,7 +542,7 @@ impl ModuleInstanceInterface for ModuleInstance {
.map(FunctionSignature::Module) .map(FunctionSignature::Module)
} }
fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<InternalFunctionReference<'a>, Error> { fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>>) -> Result<InternalFunctionReference<'a, E>, Error> {
match self.imports.parse_function_index(index) { match self.imports.parse_function_index(index) {
ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"), ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"),
ItemIndex::Internal(index) => Ok(InternalFunctionReference { 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<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<InternalFunctionReference<'a>, Error> { fn function_reference_indirect<'a>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>>) -> Result<InternalFunctionReference<'a, E>, Error> {
let table = self.table(ItemIndex::IndexSpace(table_idx))?; let table = self.table(ItemIndex::IndexSpace(table_idx))?;
let (module, index) = match table.get(func_idx)? { let (module, index) = match table.get(func_idx)? {
RuntimeValue::AnyFunc(module, index) => (module.clone(), index), RuntimeValue::AnyFunc(module, index) => (module.clone(), index),
@ -591,7 +600,7 @@ impl ModuleInstanceInterface for ModuleInstance {
})) }))
} }
fn call_internal_function(&self, mut outer: CallerContext, index: u32) -> Result<Option<RuntimeValue>, Error> { fn call_internal_function(&self, mut outer: CallerContext<E>, index: u32) -> Result<Option<RuntimeValue>, InterpreterError<E>> {
let function_type = self.function_type(ItemIndex::Internal(index))?; let function_type = self.function_type(ItemIndex::Internal(index))?;
let args = prepare_function_args(&function_type, outer.value_stack)?; let args = prepare_function_args(&function_type, outer.value_stack)?;
let function_ref = InternalFunctionReference { module: self.self_ref(Some(outer.externals))?, internal_index: index }; let function_ref = InternalFunctionReference { module: self.self_ref(Some(outer.externals))?, internal_index: index };
@ -600,9 +609,9 @@ impl ModuleInstanceInterface for ModuleInstance {
} }
} }
impl<'a> CallerContext<'a> { impl<'a, E> CallerContext<'a, E> where E: CustomUserError {
/// Top most args /// Top most args
pub fn topmost(args: &'a mut StackWithLimit<RuntimeValue>, externals: &'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>) -> Self { pub fn topmost(args: &'a mut StackWithLimit<RuntimeValue>, externals: &'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>) -> Self {
CallerContext { CallerContext {
value_stack_limit: DEFAULT_VALUE_STACK_LIMIT, value_stack_limit: DEFAULT_VALUE_STACK_LIMIT,
frame_stack_limit: DEFAULT_FRAME_STACK_LIMIT, frame_stack_limit: DEFAULT_FRAME_STACK_LIMIT,
@ -612,7 +621,7 @@ impl<'a> CallerContext<'a> {
} }
/// Nested context /// Nested context
pub fn nested(outer: &'a mut FunctionContext) -> Self { pub fn nested(outer: &'a mut FunctionContext<E>) -> Self {
CallerContext { CallerContext {
value_stack_limit: outer.value_stack().limit() - outer.value_stack().len(), value_stack_limit: outer.value_stack().limit() - outer.value_stack().len(),
frame_stack_limit: outer.frame_stack().limit() - outer.frame_stack().len(), frame_stack_limit: outer.frame_stack().limit() - outer.frame_stack().len(),
@ -632,7 +641,7 @@ pub fn check_limits(limits: &ResizableLimits) -> Result<(), Error> {
Ok(()) Ok(())
} }
fn get_initializer(expr: &InitExpr, module: &Module, imports: &ModuleImports, expected_type: VariableType) -> Result<RuntimeValue, Error> { fn get_initializer<E: CustomUserError>(expr: &InitExpr, module: &Module, imports: &ModuleImports<E>, expected_type: VariableType) -> Result<RuntimeValue, Error> {
let first_opcode = match expr.code().len() { let first_opcode = match expr.code().len() {
1 => &expr.code()[0], 1 => &expr.code()[0],
2 if expr.code().len() == 2 && expr.code()[1] == Opcode::End => &expr.code()[0], 2 if expr.code().len() == 2 && expr.code()[1] == Opcode::End => &expr.code()[0],

View File

@ -2,23 +2,23 @@ use std::sync::Arc;
use std::collections::HashMap; use std::collections::HashMap;
use parking_lot::RwLock; use parking_lot::RwLock;
use elements::Module; use elements::Module;
use interpreter::Error; use interpreter::{Error, CustomUserError, InterpreterError};
use interpreter::env::{self, env_module}; use interpreter::env::{self, env_module};
use interpreter::module::{ModuleInstance, ModuleInstanceInterface}; use interpreter::module::{ModuleInstance, ModuleInstanceInterface};
/// Program instance. Program is a set of instantiated modules. /// Program instance. Program is a set of instantiated modules.
pub struct ProgramInstance { pub struct ProgramInstance<E: CustomUserError> {
/// Shared data reference. /// Shared data reference.
essence: Arc<ProgramInstanceEssence>, essence: Arc<ProgramInstanceEssence<E>>,
} }
/// Program instance essence. /// Program instance essence.
pub struct ProgramInstanceEssence { pub struct ProgramInstanceEssence<E: CustomUserError> {
/// Loaded modules. /// Loaded modules.
modules: RwLock<HashMap<String, Arc<ModuleInstanceInterface>>>, modules: RwLock<HashMap<String, Arc<ModuleInstanceInterface<E>>>>,
} }
impl ProgramInstance { impl<E> ProgramInstance<E> where E: CustomUserError {
/// Create new program instance. /// Create new program instance.
pub fn new() -> Result<Self, Error> { pub fn new() -> Result<Self, Error> {
ProgramInstance::with_env_params(env::EnvParams::default()) ProgramInstance::with_env_params(env::EnvParams::default())
@ -32,7 +32,7 @@ impl ProgramInstance {
} }
/// Instantiate module with validation. /// Instantiate module with validation.
pub fn add_module<'a>(&self, name: &str, module: Module, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<Arc<ModuleInstance>, Error> { pub fn add_module<'a>(&self, name: &str, module: Module, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>>) -> Result<Arc<ModuleInstance<E>>, InterpreterError<E>> {
let mut module_instance = ModuleInstance::new(Arc::downgrade(&self.essence), name.into(), module)?; let mut module_instance = ModuleInstance::new(Arc::downgrade(&self.essence), name.into(), module)?;
module_instance.instantiate(externals)?; module_instance.instantiate(externals)?;
@ -43,19 +43,19 @@ impl ProgramInstance {
} }
/// Insert instantiated module. /// Insert instantiated module.
pub fn insert_loaded_module(&self, name: &str, module_instance: Arc<ModuleInstance>) -> Result<Arc<ModuleInstance>, Error> { pub fn insert_loaded_module(&self, name: &str, module_instance: Arc<ModuleInstance<E>>) -> Result<Arc<ModuleInstance<E>>, Error> {
// replace existing module with the same name with new one // replace existing module with the same name with new one
self.essence.modules.write().insert(name.into(), module_instance.clone()); self.essence.modules.write().insert(name.into(), module_instance.clone());
Ok(module_instance) Ok(module_instance)
} }
/// Get one of the modules by name /// Get one of the modules by name
pub fn module(&self, name: &str) -> Option<Arc<ModuleInstanceInterface>> { pub fn module(&self, name: &str) -> Option<Arc<ModuleInstanceInterface<E>>> {
self.essence.module(name) self.essence.module(name)
} }
} }
impl ProgramInstanceEssence { impl<E> ProgramInstanceEssence<E> where E: CustomUserError {
/// Create new program essence. /// Create new program essence.
pub fn new() -> Result<Self, Error> { pub fn new() -> Result<Self, Error> {
ProgramInstanceEssence::with_env_params(env::EnvParams::default()) ProgramInstanceEssence::with_env_params(env::EnvParams::default())
@ -63,7 +63,7 @@ impl ProgramInstanceEssence {
pub fn with_env_params(env_params: env::EnvParams) -> Result<Self, Error> { pub fn with_env_params(env_params: env::EnvParams) -> Result<Self, Error> {
let mut modules = HashMap::new(); let mut modules = HashMap::new();
let env_module: Arc<ModuleInstanceInterface> = Arc::new(env_module(env_params)?); let env_module: Arc<ModuleInstanceInterface<E>> = Arc::new(env_module(env_params)?);
modules.insert("env".into(), env_module); modules.insert("env".into(), env_module);
Ok(ProgramInstanceEssence { Ok(ProgramInstanceEssence {
modules: RwLock::new(modules), modules: RwLock::new(modules),
@ -71,7 +71,7 @@ impl ProgramInstanceEssence {
} }
/// Get module reference. /// Get module reference.
pub fn module(&self, name: &str) -> Option<Arc<ModuleInstanceInterface>> { pub fn module(&self, name: &str) -> Option<Arc<ModuleInstanceInterface<E>>> {
self.modules.read().get(name).cloned() self.modules.read().get(name).cloned()
} }
} }

View File

@ -6,7 +6,7 @@ use std::fmt::{self, Display};
use std::iter::repeat; use std::iter::repeat;
use std::collections::{HashMap, VecDeque}; use std::collections::{HashMap, VecDeque};
use elements::{Opcode, BlockType, Local}; use elements::{Opcode, BlockType, Local};
use interpreter::Error; use interpreter::{Error, CustomUserError, InterpreterError};
use interpreter::module::{ModuleInstanceInterface, CallerContext, ItemIndex, InternalFunctionReference, FunctionSignature}; use interpreter::module::{ModuleInstanceInterface, CallerContext, ItemIndex, InternalFunctionReference, FunctionSignature};
use interpreter::stack::StackWithLimit; use interpreter::stack::StackWithLimit;
use interpreter::value::{ use interpreter::value::{
@ -22,16 +22,18 @@ pub const DEFAULT_MEMORY_INDEX: u32 = 0;
pub const DEFAULT_TABLE_INDEX: u32 = 0; pub const DEFAULT_TABLE_INDEX: u32 = 0;
/// Function interpreter. /// Function interpreter.
pub struct Interpreter; pub struct Interpreter<E: CustomUserError> {
_dummy: ::std::marker::PhantomData<E>,
}
/// Function execution context. /// Function execution context.
pub struct FunctionContext<'a> { pub struct FunctionContext<'a, E: 'a + CustomUserError> {
/// Is context initialized. /// Is context initialized.
pub is_initialized: bool, pub is_initialized: bool,
/// Internal function reference. /// Internal function reference.
pub function: InternalFunctionReference<'a>, pub function: InternalFunctionReference<'a, E>,
/// Execution-local external modules. /// Execution-local external modules.
pub externals: &'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>, pub externals: &'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>,
/// Function return type. /// Function return type.
pub return_type: BlockType, pub return_type: BlockType,
/// Local variables. /// Local variables.
@ -46,13 +48,13 @@ pub struct FunctionContext<'a> {
/// Interpreter action to execute after executing instruction. /// Interpreter action to execute after executing instruction.
#[derive(Debug)] #[derive(Debug)]
pub enum InstructionOutcome<'a> { pub enum InstructionOutcome<'a, E: CustomUserError> {
/// Continue with next instruction. /// Continue with next instruction.
RunNextInstruction, RunNextInstruction,
/// Branch to given frame. /// Branch to given frame.
Branch(usize), Branch(usize),
/// Execute function call. /// Execute function call.
ExecuteCall(InternalFunctionReference<'a>), ExecuteCall(InternalFunctionReference<'a, E>),
/// End current frame. /// End current frame.
End, End,
/// Return from current function block. /// Return from current function block.
@ -60,15 +62,15 @@ pub enum InstructionOutcome<'a> {
} }
/// Function run result. /// Function run result.
enum RunResult<'a> { enum RunResult<'a, E: 'a + CustomUserError> {
/// Function has returned (optional) value. /// Function has returned (optional) value.
Return(Option<RuntimeValue>), Return(Option<RuntimeValue>),
/// Function is calling other function. /// Function is calling other function.
NestedCall(FunctionContext<'a>), NestedCall(FunctionContext<'a, E>),
} }
impl Interpreter { impl<E> Interpreter<E> where E: CustomUserError {
pub fn run_function(function_context: FunctionContext) -> Result<Option<RuntimeValue>, Error> { pub fn run_function(function_context: FunctionContext<E>) -> Result<Option<RuntimeValue>, InterpreterError<E>> {
let mut function_stack = VecDeque::new(); let mut function_stack = VecDeque::new();
function_stack.push_back(function_context); 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<usize, usize>) -> Result<RunResult<'a>, Error> { fn do_run_function<'a>(function_context: &mut FunctionContext<'a, E>, function_body: &[Opcode], function_labels: &HashMap<usize, usize>) -> Result<RunResult<'a, E>, Error> {
loop { loop {
let instruction = &function_body[function_context.position]; let instruction = &function_body[function_context.position];
@ -156,7 +158,7 @@ impl Interpreter {
})) }))
} }
fn run_instruction<'a>(context: &mut FunctionContext<'a>, labels: &HashMap<usize, usize>, opcode: &Opcode) -> Result<InstructionOutcome<'a>, Error> { fn run_instruction<'a>(context: &mut FunctionContext<'a, E>, labels: &HashMap<usize, usize>, opcode: &Opcode) -> Result<InstructionOutcome<'a, E>, Error> {
match opcode { match opcode {
&Opcode::Unreachable => Interpreter::run_unreachable(context), &Opcode::Unreachable => Interpreter::run_unreachable(context),
&Opcode::Nop => Interpreter::run_nop(context), &Opcode::Nop => Interpreter::run_nop(context),
@ -350,25 +352,25 @@ impl Interpreter {
} }
} }
fn run_unreachable<'a>(_context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> { fn run_unreachable<'a>(_context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error> {
Err(Error::Trap("programmatic".into())) Err(Error::Trap("programmatic".into()))
} }
fn run_nop<'a>(_context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> { fn run_nop<'a>(_context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_block<'a>(context: &mut FunctionContext<'a>, labels: &HashMap<usize, usize>, block_type: BlockType) -> Result<InstructionOutcome<'a>, Error> { fn run_block<'a>(context: &mut FunctionContext<'a, E>, labels: &HashMap<usize, usize>, block_type: BlockType) -> Result<InstructionOutcome<'a, E>, Error> {
context.push_frame(labels, BlockFrameType::Block, block_type)?; context.push_frame(labels, BlockFrameType::Block, block_type)?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_loop<'a>(context: &mut FunctionContext<'a>, labels: &HashMap<usize, usize>, block_type: BlockType) -> Result<InstructionOutcome<'a>, Error> { fn run_loop<'a>(context: &mut FunctionContext<'a, E>, labels: &HashMap<usize, usize>, block_type: BlockType) -> Result<InstructionOutcome<'a, E>, Error> {
context.push_frame(labels, BlockFrameType::Loop, block_type)?; context.push_frame(labels, BlockFrameType::Loop, block_type)?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_if<'a>(context: &mut FunctionContext<'a>, labels: &HashMap<usize, usize>, block_type: BlockType) -> Result<InstructionOutcome<'a>, Error> { fn run_if<'a>(context: &mut FunctionContext<'a, E>, labels: &HashMap<usize, usize>, block_type: BlockType) -> Result<InstructionOutcome<'a, E>, Error> {
let branch = context.value_stack_mut().pop_as()?; let branch = context.value_stack_mut().pop_as()?;
let block_frame_type = if branch { BlockFrameType::IfTrue } else { let block_frame_type = if branch { BlockFrameType::IfTrue } else {
let else_pos = labels[&context.position]; let else_pos = labels[&context.position];
@ -383,23 +385,23 @@ impl Interpreter {
context.push_frame(labels, block_frame_type, block_type).map(|_| InstructionOutcome::RunNextInstruction) context.push_frame(labels, block_frame_type, block_type).map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_else<'a>(context: &mut FunctionContext, labels: &HashMap<usize, usize>) -> Result<InstructionOutcome<'a>, Error> { fn run_else<'a>(context: &mut FunctionContext<E>, labels: &HashMap<usize, usize>) -> Result<InstructionOutcome<'a, E>, Error> {
let end_pos = labels[&context.position]; let end_pos = labels[&context.position];
context.pop_frame(false)?; context.pop_frame(false)?;
context.position = end_pos; context.position = end_pos;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_end<'a>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> { fn run_end<'a>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error> {
context.pop_frame(false)?; context.pop_frame(false)?;
Ok(InstructionOutcome::End) Ok(InstructionOutcome::End)
} }
fn run_br<'a>(_context: &mut FunctionContext, label_idx: u32) -> Result<InstructionOutcome<'a>, Error> { fn run_br<'a>(_context: &mut FunctionContext<E>, label_idx: u32) -> Result<InstructionOutcome<'a, E>, Error> {
Ok(InstructionOutcome::Branch(label_idx as usize)) Ok(InstructionOutcome::Branch(label_idx as usize))
} }
fn run_br_if<'a>(context: &mut FunctionContext, label_idx: u32) -> Result<InstructionOutcome<'a>, Error> { fn run_br_if<'a>(context: &mut FunctionContext<E>, label_idx: u32) -> Result<InstructionOutcome<'a, E>, Error> {
if context.value_stack_mut().pop_as()? { if context.value_stack_mut().pop_as()? {
Ok(InstructionOutcome::Branch(label_idx as usize)) Ok(InstructionOutcome::Branch(label_idx as usize))
} else { } else {
@ -407,20 +409,20 @@ impl Interpreter {
} }
} }
fn run_br_table<'a>(context: &mut FunctionContext, table: &Vec<u32>, default: u32) -> Result<InstructionOutcome<'a>, Error> { fn run_br_table<'a>(context: &mut FunctionContext<E>, table: &Vec<u32>, default: u32) -> Result<InstructionOutcome<'a, E>, Error> {
let index: u32 = context.value_stack_mut().pop_as()?; let index: u32 = context.value_stack_mut().pop_as()?;
Ok(InstructionOutcome::Branch(table.get(index as usize).cloned().unwrap_or(default) as usize)) Ok(InstructionOutcome::Branch(table.get(index as usize).cloned().unwrap_or(default) as usize))
} }
fn run_return<'a>(_context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> { fn run_return<'a>(_context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error> {
Ok(InstructionOutcome::Return) Ok(InstructionOutcome::Return)
} }
fn run_call<'a>(context: &mut FunctionContext<'a>, func_idx: u32) -> Result<InstructionOutcome<'a>, Error> { fn run_call<'a>(context: &mut FunctionContext<'a, E>, func_idx: u32) -> Result<InstructionOutcome<'a, E>, Error> {
Ok(InstructionOutcome::ExecuteCall(context.module().function_reference(ItemIndex::IndexSpace(func_idx), Some(context.externals))?)) 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<InstructionOutcome<'a>, Error> { fn run_call_indirect<'a>(context: &mut FunctionContext<'a, E>, type_idx: u32) -> Result<InstructionOutcome<'a, E>, Error> {
let table_func_idx: u32 = context.value_stack_mut().pop_as()?; 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))?; let function_reference = context.module().function_reference_indirect(DEFAULT_TABLE_INDEX, type_idx, table_func_idx, Some(context.externals))?;
{ {
@ -435,14 +437,14 @@ impl Interpreter {
Ok(InstructionOutcome::ExecuteCall(function_reference)) Ok(InstructionOutcome::ExecuteCall(function_reference))
} }
fn run_drop<'a>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> { fn run_drop<'a>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error> {
context context
.value_stack_mut() .value_stack_mut()
.pop() .pop()
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_select<'a>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> { fn run_select<'a>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error> {
context context
.value_stack_mut() .value_stack_mut()
.pop_triple() .pop_triple()
@ -457,32 +459,32 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_get_local<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome<'a>, Error> { fn run_get_local<'a>(context: &mut FunctionContext<E>, index: u32) -> Result<InstructionOutcome<'a, E>, Error> {
context.get_local(index as usize) context.get_local(index as usize)
.map(|value| context.value_stack_mut().push(value)) .map(|value| context.value_stack_mut().push(value))
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_set_local<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome<'a>, Error> { fn run_set_local<'a>(context: &mut FunctionContext<E>, index: u32) -> Result<InstructionOutcome<'a, E>, Error> {
let arg = context.value_stack_mut().pop()?; let arg = context.value_stack_mut().pop()?;
context.set_local(index as usize, arg) context.set_local(index as usize, arg)
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_tee_local<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome<'a>, Error> { fn run_tee_local<'a>(context: &mut FunctionContext<E>, index: u32) -> Result<InstructionOutcome<'a, E>, Error> {
let arg = context.value_stack().top()?.clone(); let arg = context.value_stack().top()?.clone();
context.set_local(index as usize, arg) context.set_local(index as usize, arg)
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_get_global<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome<'a>, Error> { fn run_get_global<'a>(context: &mut FunctionContext<E>, index: u32) -> Result<InstructionOutcome<'a, E>, Error> {
context.module() context.module()
.global(ItemIndex::IndexSpace(index), None, Some(context.externals)) .global(ItemIndex::IndexSpace(index), None, Some(context.externals))
.and_then(|g| context.value_stack_mut().push(g.get())) .and_then(|g| context.value_stack_mut().push(g.get()))
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_set_global<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome<'a>, Error> { fn run_set_global<'a>(context: &mut FunctionContext<E>, index: u32) -> Result<InstructionOutcome<'a, E>, Error> {
context context
.value_stack_mut() .value_stack_mut()
.pop() .pop()
@ -490,7 +492,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_load<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome<'a>, Error> fn run_load<'a, T>(context: &mut FunctionContext<E>, _align: u32, offset: u32) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<T>, T: LittleEndianConvert { where RuntimeValue: From<T>, T: LittleEndianConvert {
let address = effective_address(offset, context.value_stack_mut().pop_as()?)?; let address = effective_address(offset, context.value_stack_mut().pop_as()?)?;
context.module() context.module()
@ -501,7 +503,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_load_extend<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome<'a>, Error> fn run_load_extend<'a, T, U>(context: &mut FunctionContext<E>, _align: u32, offset: u32) -> Result<InstructionOutcome<'a, E>, Error>
where T: ExtendInto<U>, RuntimeValue: From<U>, T: LittleEndianConvert { where T: ExtendInto<U>, RuntimeValue: From<U>, T: LittleEndianConvert {
let address = effective_address(offset, context.value_stack_mut().pop_as()?)?; let address = effective_address(offset, context.value_stack_mut().pop_as()?)?;
let stack_value: U = context.module() let stack_value: U = context.module()
@ -515,7 +517,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_store<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome<'a>, Error> fn run_store<'a, T>(context: &mut FunctionContext<E>, _align: u32, offset: u32) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: TryInto<T, Error>, T: LittleEndianConvert { where RuntimeValue: TryInto<T, Error>, T: LittleEndianConvert {
let stack_value = context let stack_value = context
.value_stack_mut() .value_stack_mut()
@ -528,7 +530,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_store_wrap<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome<'a>, Error> fn run_store_wrap<'a, T, U>(context: &mut FunctionContext<E>, _align: u32, offset: u32) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: TryInto<T, Error>, T: WrapInto<U>, U: LittleEndianConvert { where RuntimeValue: TryInto<T, Error>, T: WrapInto<U>, U: LittleEndianConvert {
let stack_value: T = context.value_stack_mut().pop().and_then(|v| v.try_into())?; 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 stack_value = stack_value.wrap_into().into_little_endian();
@ -539,7 +541,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_current_memory<'a>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> { fn run_current_memory<'a>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error> {
context.module() context.module()
.memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX)) .memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX))
.map(|m| m.size()) .map(|m| m.size())
@ -547,7 +549,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_grow_memory<'a>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> { fn run_grow_memory<'a>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error> {
let pages: u32 = context.value_stack_mut().pop_as()?; let pages: u32 = context.value_stack_mut().pop_as()?;
context.module() context.module()
.memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX)) .memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX))
@ -556,14 +558,14 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_const<'a>(context: &mut FunctionContext, val: RuntimeValue) -> Result<InstructionOutcome<'a>, Error> { fn run_const<'a>(context: &mut FunctionContext<E>, val: RuntimeValue) -> Result<InstructionOutcome<'a, E>, Error> {
context context
.value_stack_mut() .value_stack_mut()
.push(val) .push(val)
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_eqz<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_eqz<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> + Default { where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> + Default {
context context
.value_stack_mut() .value_stack_mut()
@ -573,7 +575,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_eq<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_eq<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> { where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -583,7 +585,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_ne<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_ne<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> { where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -593,7 +595,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_lt<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_lt<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> + Display { where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> + Display {
context context
.value_stack_mut() .value_stack_mut()
@ -603,7 +605,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_gt<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_gt<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> { where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -613,7 +615,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_lte<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_lte<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> { where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -623,7 +625,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_gte<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_gte<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> { where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -633,7 +635,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_clz<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_clz<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -643,7 +645,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_ctz<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_ctz<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -653,7 +655,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_popcnt<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_popcnt<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -663,7 +665,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_add<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_add<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -673,7 +675,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_sub<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_sub<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -683,7 +685,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_mul<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_mul<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -693,7 +695,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_div<'a, T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_div<'a, T, U>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U> + Display, U: ArithmeticOps<U> + TransmuteInto<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U> + Display, U: ArithmeticOps<U> + TransmuteInto<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -705,7 +707,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_rem<'a, T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_rem<'a, T, U>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U>, U: Integer<U> + TransmuteInto<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U>, U: Integer<U> + TransmuteInto<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -717,7 +719,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_and<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_and<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<<T as ops::BitAnd>::Output> + TryInto<T, Error>, T: ops::BitAnd<T> { where RuntimeValue: From<<T as ops::BitAnd>::Output> + TryInto<T, Error>, T: ops::BitAnd<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -727,7 +729,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_or<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_or<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<<T as ops::BitOr>::Output> + TryInto<T, Error>, T: ops::BitOr<T> { where RuntimeValue: From<<T as ops::BitOr>::Output> + TryInto<T, Error>, T: ops::BitOr<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -737,7 +739,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_xor<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_xor<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<<T as ops::BitXor>::Output> + TryInto<T, Error>, T: ops::BitXor<T> { where RuntimeValue: From<<T as ops::BitXor>::Output> + TryInto<T, Error>, T: ops::BitXor<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -747,7 +749,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_shl<'a, T>(context: &mut FunctionContext, mask: T) -> Result<InstructionOutcome<'a>, Error> fn run_shl<'a, T>(context: &mut FunctionContext<E>, mask: T) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<<T as ops::Shl<T>>::Output> + TryInto<T, Error>, T: ops::Shl<T> + ops::BitAnd<T, Output=T> { where RuntimeValue: From<<T as ops::Shl<T>>::Output> + TryInto<T, Error>, T: ops::Shl<T> + ops::BitAnd<T, Output=T> {
context context
.value_stack_mut() .value_stack_mut()
@ -757,7 +759,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_shr<'a, T, U>(context: &mut FunctionContext, mask: U) -> Result<InstructionOutcome<'a>, Error> fn run_shr<'a, T, U>(context: &mut FunctionContext<E>, mask: U) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U>, U: ops::Shr<U> + ops::BitAnd<U, Output=U>, <U as ops::Shr<U>>::Output: TransmuteInto<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U>, U: ops::Shr<U> + ops::BitAnd<U, Output=U>, <U as ops::Shr<U>>::Output: TransmuteInto<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -769,7 +771,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_rotl<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_rotl<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -779,7 +781,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_rotr<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_rotr<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -789,7 +791,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_abs<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_abs<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -799,7 +801,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_neg<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_neg<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<<T as ops::Neg>::Output> + TryInto<T, Error>, T: ops::Neg { where RuntimeValue: From<<T as ops::Neg>::Output> + TryInto<T, Error>, T: ops::Neg {
context context
.value_stack_mut() .value_stack_mut()
@ -809,7 +811,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_ceil<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_ceil<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -819,7 +821,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_floor<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_floor<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -829,7 +831,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_trunc<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_trunc<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -839,7 +841,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_nearest<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_nearest<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -849,7 +851,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_sqrt<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_sqrt<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -859,7 +861,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_min<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_min<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -869,7 +871,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_max<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_max<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -879,7 +881,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_copysign<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_copysign<'a, T>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -889,7 +891,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_wrap<'a, T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_wrap<'a, T, U>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<U> + TryInto<T, Error>, T: WrapInto<U> { where RuntimeValue: From<U> + TryInto<T, Error>, T: WrapInto<U> {
context context
.value_stack_mut() .value_stack_mut()
@ -899,7 +901,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_trunc_to_int<'a, T, U, V>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_trunc_to_int<'a, T, U, V>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<V> + TryInto<T, Error>, T: TryTruncateInto<U, Error>, U: TransmuteInto<V>, { where RuntimeValue: From<V> + TryInto<T, Error>, T: TryTruncateInto<U, Error>, U: TransmuteInto<V>, {
context context
.value_stack_mut() .value_stack_mut()
@ -910,7 +912,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_extend<'a, T, U, V>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_extend<'a, T, U, V>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<V> + TryInto<T, Error>, T: ExtendInto<U>, U: TransmuteInto<V> { where RuntimeValue: From<V> + TryInto<T, Error>, T: ExtendInto<U>, U: TransmuteInto<V> {
context context
.value_stack_mut() .value_stack_mut()
@ -921,7 +923,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_reinterpret<'a, T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> fn run_reinterpret<'a, T, U>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error>
where RuntimeValue: From<U>, RuntimeValue: TryInto<T, Error>, T: TransmuteInto<U> { where RuntimeValue: From<U>, RuntimeValue: TryInto<T, Error>, T: TransmuteInto<U> {
context context
.value_stack_mut() .value_stack_mut()
@ -932,8 +934,8 @@ impl Interpreter {
} }
} }
impl<'a> FunctionContext<'a> { impl<'a, E> FunctionContext<'a, E> where E: CustomUserError {
pub fn new(function: InternalFunctionReference<'a>, externals: &'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>, value_stack_limit: usize, frame_stack_limit: usize, function_type: &FunctionSignature, args: Vec<VariableInstance>) -> Self { pub fn new(function: InternalFunctionReference<'a, E>, externals: &'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>, value_stack_limit: usize, frame_stack_limit: usize, function_type: &FunctionSignature, args: Vec<VariableInstance>) -> Self {
FunctionContext { FunctionContext {
is_initialized: false, is_initialized: false,
function: function, function: function,
@ -946,7 +948,7 @@ impl<'a> FunctionContext<'a> {
} }
} }
pub fn nested(&mut self, function: InternalFunctionReference<'a>) -> Result<Self, Error> { pub fn nested(&mut self, function: InternalFunctionReference<'a, E>) -> Result<Self, Error> {
let (function_locals, function_return_type) = { let (function_locals, function_return_type) = {
let function_type = function.module.function_type(ItemIndex::Internal(function.internal_index))?; 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); let function_return_type = function_type.return_type().map(|vt| BlockType::Value(vt)).unwrap_or(BlockType::NoResult);
@ -982,15 +984,15 @@ impl<'a> FunctionContext<'a> {
Ok(()) Ok(())
} }
pub fn module(&self) -> &Arc<ModuleInstanceInterface + 'a> { pub fn module(&self) -> &Arc<ModuleInstanceInterface<E> + 'a> {
&self.function.module &self.function.module
} }
pub fn externals(&self) -> &HashMap<String, Arc<ModuleInstanceInterface + 'a>> { pub fn externals(&self) -> &HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>> {
&self.externals &self.externals
} }
pub fn set_local(&mut self, index: usize, value: RuntimeValue) -> Result<InstructionOutcome<'a>, Error> { pub fn set_local(&mut self, index: usize, value: RuntimeValue) -> Result<InstructionOutcome<'a, E>, Error> {
self.locals.get_mut(index) self.locals.get_mut(index)
.ok_or(Error::Local(format!("expected to have local with index {}", index))) .ok_or(Error::Local(format!("expected to have local with index {}", index)))
.and_then(|l| l.set(value)) .and_then(|l| l.set(value))
@ -1072,7 +1074,7 @@ impl<'a> FunctionContext<'a> {
} }
} }
impl<'a> fmt::Debug for FunctionContext<'a> { impl<'a, E> fmt::Debug for FunctionContext<'a, E> where E: CustomUserError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "FunctionContext") write!(f, "FunctionContext")
} }

View File

@ -5,11 +5,10 @@ use std::collections::HashMap;
use builder::module; use builder::module;
use elements::{ExportEntry, Internal, ImportEntry, External, GlobalEntry, GlobalType, use elements::{ExportEntry, Internal, ImportEntry, External, GlobalEntry, GlobalType,
InitExpr, ValueType, BlockType, Opcodes, Opcode, FunctionType}; InitExpr, ValueType, BlockType, Opcodes, Opcode, FunctionType};
use interpreter::Error; use interpreter::{Error, CustomUserError, DummyCustomUserError, InterpreterError, ProgramInstance, ModuleInstance, CustomProgramInstance};
use interpreter::env_native::{env_native_module, UserDefinedElements, UserFunctionExecutor, UserFunctionDescriptor}; use interpreter::env_native::{env_native_module, UserDefinedElements, UserFunctionExecutor, UserFunctionDescriptor};
use interpreter::memory::MemoryInstance; use interpreter::memory::MemoryInstance;
use interpreter::module::{ModuleInstance, ModuleInstanceInterface, CallerContext, ItemIndex, ExecutionParams, ExportEntryType, FunctionSignature}; use interpreter::module::{ModuleInstanceInterface, CallerContext, ItemIndex, ExecutionParams, ExportEntryType, FunctionSignature};
use interpreter::program::ProgramInstance;
use interpreter::validator::{FunctionValidationContext, Validator}; use interpreter::validator::{FunctionValidationContext, Validator};
use interpreter::value::{RuntimeValue, TryInto}; use interpreter::value::{RuntimeValue, TryInto};
use interpreter::variable::{VariableInstance, ExternalVariableValue, VariableType}; use interpreter::variable::{VariableInstance, ExternalVariableValue, VariableType};
@ -115,6 +114,11 @@ const SIGNATURES: &'static [UserFunctionDescriptor] = &[
SIGNATURE_I32_I32, SIGNATURE_I32_I32,
Some(ValueType::I32), Some(ValueType::I32),
), ),
UserFunctionDescriptor::Static(
"err",
SIGNATURE_I32_I32,
Some(ValueType::I32),
),
]; ];
const NO_SIGNATURES: &'static [UserFunctionDescriptor] = &[]; const NO_SIGNATURES: &'static [UserFunctionDescriptor] = &[];
@ -135,14 +139,28 @@ impl ExternalVariableValue for MeasuredVariable {
} }
} }
// custom user error
#[derive(Debug, Clone, PartialEq)]
struct UserError {
error_code: i32,
}
impl ::std::fmt::Display for UserError {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
write!(f, "{}", self.error_code)
}
}
impl CustomUserError for UserError {}
// user function executor // user function executor
struct FunctionExecutor { struct FunctionExecutor {
pub memory: Arc<MemoryInstance>, pub memory: Arc<MemoryInstance>,
pub values: Vec<i32>, pub values: Vec<i32>,
} }
impl UserFunctionExecutor for FunctionExecutor { impl UserFunctionExecutor<UserError> for FunctionExecutor {
fn execute(&mut self, name: &str, context: CallerContext) -> Result<Option<RuntimeValue>, Error> { fn execute(&mut self, name: &str, context: CallerContext<UserError>) -> Result<Option<RuntimeValue>, InterpreterError<UserError>> {
match name { match name {
"add" => { "add" => {
let memory_value = self.memory.get(0, 1).unwrap()[0]; let memory_value = self.memory.get(0, 1).unwrap()[0];
@ -166,7 +184,10 @@ impl UserFunctionExecutor for FunctionExecutor {
self.values.push(diff as i32); self.values.push(diff as i32);
Ok(Some(RuntimeValue::I32(diff as i32))) Ok(Some(RuntimeValue::I32(diff as i32)))
}, },
_ => Err(Error::Trap("not implemented".into())), "err" => {
Err(InterpreterError::User(UserError { error_code: 777 }))
},
_ => Err(Error::Trap("not implemented".into()).into()),
} }
} }
} }
@ -174,7 +195,7 @@ impl UserFunctionExecutor for FunctionExecutor {
#[test] #[test]
fn native_env_function() { fn native_env_function() {
// create new program // create new program
let program = ProgramInstance::new().unwrap(); let program = CustomProgramInstance::new().unwrap();
// => env module is created // => env module is created
let env_instance = program.module("env").unwrap(); let env_instance = program.module("env").unwrap();
// => linear memory is created // => linear memory is created
@ -186,7 +207,7 @@ fn native_env_function() {
values: Vec::new(), values: Vec::new(),
}; };
{ {
let functions: UserDefinedElements = UserDefinedElements { let functions = UserDefinedElements {
executor: Some(&mut executor), executor: Some(&mut executor),
globals: HashMap::new(), globals: HashMap::new(),
functions: ::std::borrow::Cow::from(SIGNATURES), functions: ::std::borrow::Cow::from(SIGNATURES),
@ -282,6 +303,40 @@ fn native_env_global() {
} }
} }
#[test]
fn native_custom_error() {
let program = CustomProgramInstance::new().unwrap();
let env_instance = program.module("env").unwrap();
let env_memory = env_instance.memory(ItemIndex::Internal(0)).unwrap();
let mut executor = FunctionExecutor { memory: env_memory.clone(), values: Vec::new() };
let functions = UserDefinedElements {
executor: Some(&mut executor),
globals: HashMap::new(),
functions: ::std::borrow::Cow::from(SIGNATURES),
};
let native_env_instance = Arc::new(env_native_module(env_instance, functions).unwrap());
let params = ExecutionParams::with_external("env".into(), native_env_instance);
let module = module()
.with_import(ImportEntry::new("env".into(), "err".into(), External::Function(0)))
.function()
.signature().param().i32().param().i32().return_type().i32().build()
.body().with_opcodes(Opcodes::new(vec![
Opcode::GetLocal(0),
Opcode::GetLocal(1),
Opcode::Call(0),
Opcode::End,
])).build()
.build()
.build();
let module_instance = program.add_module("main", module, Some(&params.externals)).unwrap();
assert_eq!(module_instance.execute_index(0, params.clone().add_argument(RuntimeValue::I32(7)).add_argument(RuntimeValue::I32(0))),
Err(InterpreterError::User(UserError { error_code: 777 })));
assert_eq!(module_instance.execute_index(1, params.clone().add_argument(RuntimeValue::I32(7)).add_argument(RuntimeValue::I32(0))),
Err(InterpreterError::User(UserError { error_code: 777 })));
}
#[test] #[test]
fn import_env_mutable_global() { fn import_env_mutable_global() {
let program = ProgramInstance::new().unwrap(); let program = ProgramInstance::new().unwrap();
@ -295,7 +350,7 @@ fn import_env_mutable_global() {
#[test] #[test]
fn env_native_export_entry_type_check() { fn env_native_export_entry_type_check() {
let program = ProgramInstance::new().unwrap(); let program = CustomProgramInstance::new().unwrap();
let mut function_executor = FunctionExecutor { let mut function_executor = FunctionExecutor {
memory: program.module("env").unwrap().memory(ItemIndex::Internal(0)).unwrap(), memory: program.module("env").unwrap().memory(ItemIndex::Internal(0)).unwrap(),
values: Vec::new(), values: Vec::new(),

View File

@ -3,9 +3,7 @@
use std::sync::Arc; use std::sync::Arc;
use builder::module; use builder::module;
use elements::{ValueType, Opcodes, Opcode, BlockType, Local}; use elements::{ValueType, Opcodes, Opcode, BlockType, Local};
use interpreter::Error; use interpreter::{Error, InterpreterError, ProgramInstance, ModuleInstanceInterface, CustomModuleInstanceInterface, ItemIndex};
use interpreter::module::{ModuleInstanceInterface, ItemIndex};
use interpreter::program::ProgramInstance;
use interpreter::value::{RuntimeValue, TryInto}; use interpreter::value::{RuntimeValue, TryInto};
fn make_function_i32(body: Opcodes) -> (ProgramInstance, Arc<ModuleInstanceInterface>) { fn make_function_i32(body: Opcodes) -> (ProgramInstance, Arc<ModuleInstanceInterface>) {
@ -28,6 +26,10 @@ fn run_function_i32(module: &Arc<ModuleInstanceInterface>, arg: i32) -> Result<i
module module
.execute_index(0, vec![RuntimeValue::I32(arg)].into()) .execute_index(0, vec![RuntimeValue::I32(arg)].into())
.map(|r| r.unwrap().try_into().unwrap()) .map(|r| r.unwrap().try_into().unwrap())
.map_err(|e| match e {
InterpreterError::Internal(e) => e,
_ => unreachable!(),
})
} }
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/unreachable.txt /// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/unreachable.txt
@ -733,9 +735,9 @@ fn callindirect_2() {
assert_eq!(module.execute_index(3, vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(0)].into()).unwrap().unwrap(), RuntimeValue::I32(14)); assert_eq!(module.execute_index(3, vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(0)].into()).unwrap().unwrap(), RuntimeValue::I32(14));
assert_eq!(module.execute_index(3, vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(1)].into()).unwrap().unwrap(), RuntimeValue::I32(6)); assert_eq!(module.execute_index(3, vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(1)].into()).unwrap().unwrap(), RuntimeValue::I32(6));
assert_eq!(module.execute_index(3, vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(2)].into()).unwrap_err(), assert_eq!(module.execute_index(3, vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(2)].into()).unwrap_err(),
Error::Function("expected indirect function with signature ([I32, I32]) -> Some(I32) when got with ([I32]) -> Some(I32)".into())); InterpreterError::Internal(Error::Function("expected indirect function with signature ([I32, I32]) -> Some(I32) when got with ([I32]) -> Some(I32)".into())));
assert_eq!(module.execute_index(3, vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(3)].into()).unwrap_err(), assert_eq!(module.execute_index(3, vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(3)].into()).unwrap_err(),
Error::Table("trying to read table item with index 3 when there are only 3 items".into())); InterpreterError::Internal(Error::Table("trying to read table item with index 3 when there are only 3 items".into())));
} }
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/select.txt /// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/select.txt

View File

@ -1,9 +1,7 @@
use elements::deserialize_file; use elements::deserialize_file;
use elements::Module; use elements::Module;
use interpreter::EnvParams; use interpreter::{EnvParams, ExecutionParams, ProgramInstance};
use interpreter::ExecutionParams;
use interpreter::module::ModuleInstanceInterface; use interpreter::module::ModuleInstanceInterface;
use interpreter::program::ProgramInstance;
use interpreter::value::RuntimeValue; use interpreter::value::RuntimeValue;
// Name of function contained in WASM file (note the leading underline) // Name of function contained in WASM file (note the leading underline)

View File

@ -2,7 +2,7 @@ use std::u32;
use std::sync::Arc; use std::sync::Arc;
use std::collections::HashMap; use std::collections::HashMap;
use elements::{Opcode, BlockType, ValueType}; use elements::{Opcode, BlockType, ValueType};
use interpreter::Error; use interpreter::{Error, CustomUserError};
use interpreter::runner::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; use interpreter::runner::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX};
use interpreter::module::{ModuleInstance, ModuleInstanceInterface, ItemIndex, FunctionSignature}; use interpreter::module::{ModuleInstance, ModuleInstanceInterface, ItemIndex, FunctionSignature};
use interpreter::stack::StackWithLimit; use interpreter::stack::StackWithLimit;
@ -12,11 +12,11 @@ use interpreter::variable::VariableType;
const NATURAL_ALIGNMENT: u32 = 0xFFFFFFFF; const NATURAL_ALIGNMENT: u32 = 0xFFFFFFFF;
/// Function validation context. /// Function validation context.
pub struct FunctionValidationContext<'a> { pub struct FunctionValidationContext<'a, E: 'a + CustomUserError> {
/// Wasm module instance (in process of instantiation). /// Wasm module instance (in process of instantiation).
module_instance: &'a ModuleInstance, module_instance: &'a ModuleInstance<E>,
/// Native externals. /// Native externals.
externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>>,
/// Current instruction position. /// Current instruction position.
position: usize, position: usize,
/// Local variables. /// Local variables.
@ -75,7 +75,9 @@ pub enum BlockFrameType {
} }
/// Function validator. /// Function validator.
pub struct Validator; pub struct Validator<E: CustomUserError> {
_dummy: ::std::marker::PhantomData<E>,
}
/// Instruction outcome. /// Instruction outcome.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -86,8 +88,8 @@ pub enum InstructionOutcome {
Unreachable, Unreachable,
} }
impl Validator { impl<E> Validator<E> where E: CustomUserError {
pub fn validate_function(context: &mut FunctionValidationContext, block_type: BlockType, body: &[Opcode]) -> Result<(), Error> { pub fn validate_function(context: &mut FunctionValidationContext<E>, block_type: BlockType, body: &[Opcode]) -> Result<(), Error> {
context.push_label(BlockFrameType::Function, block_type)?; context.push_label(BlockFrameType::Function, block_type)?;
Validator::validate_function_block(context, body)?; Validator::validate_function_block(context, body)?;
while !context.frame_stack.is_empty() { while !context.frame_stack.is_empty() {
@ -97,7 +99,7 @@ impl Validator {
Ok(()) Ok(())
} }
fn validate_function_block(context: &mut FunctionValidationContext, body: &[Opcode]) -> Result<(), Error> { fn validate_function_block(context: &mut FunctionValidationContext<E>, body: &[Opcode]) -> Result<(), Error> {
let body_len = body.len(); let body_len = body.len();
if body_len == 0 { if body_len == 0 {
return Err(Error::Validation("Non-empty function body expected".into())); 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<InstructionOutcome, Error> { fn validate_instruction(context: &mut FunctionValidationContext<E>, opcode: &Opcode) -> Result<InstructionOutcome, Error> {
debug!(target: "validator", "validating {:?}", opcode); debug!(target: "validator", "validating {:?}", opcode);
match opcode { match opcode {
&Opcode::Unreachable => Ok(InstructionOutcome::Unreachable), &Opcode::Unreachable => Ok(InstructionOutcome::Unreachable),
@ -312,49 +314,49 @@ impl Validator {
} }
} }
fn validate_const(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result<InstructionOutcome, Error> { fn validate_const(context: &mut FunctionValidationContext<E>, value_type: StackValueType) -> Result<InstructionOutcome, Error> {
context.push_value(value_type)?; context.push_value(value_type)?;
Ok(InstructionOutcome::ValidateNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_unop(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result<InstructionOutcome, Error> { fn validate_unop(context: &mut FunctionValidationContext<E>, value_type: StackValueType) -> Result<InstructionOutcome, Error> {
context.pop_value(value_type)?; context.pop_value(value_type)?;
context.push_value(value_type)?; context.push_value(value_type)?;
Ok(InstructionOutcome::ValidateNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_binop(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result<InstructionOutcome, Error> { fn validate_binop(context: &mut FunctionValidationContext<E>, value_type: StackValueType) -> Result<InstructionOutcome, Error> {
context.pop_value(value_type)?; context.pop_value(value_type)?;
context.pop_value(value_type)?; context.pop_value(value_type)?;
context.push_value(value_type)?; context.push_value(value_type)?;
Ok(InstructionOutcome::ValidateNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_testop(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result<InstructionOutcome, Error> { fn validate_testop(context: &mut FunctionValidationContext<E>, value_type: StackValueType) -> Result<InstructionOutcome, Error> {
context.pop_value(value_type)?; context.pop_value(value_type)?;
context.push_value(ValueType::I32.into())?; context.push_value(ValueType::I32.into())?;
Ok(InstructionOutcome::ValidateNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_relop(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result<InstructionOutcome, Error> { fn validate_relop(context: &mut FunctionValidationContext<E>, value_type: StackValueType) -> Result<InstructionOutcome, Error> {
context.pop_value(value_type)?; context.pop_value(value_type)?;
context.pop_value(value_type)?; context.pop_value(value_type)?;
context.push_value(ValueType::I32.into())?; context.push_value(ValueType::I32.into())?;
Ok(InstructionOutcome::ValidateNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_cvtop(context: &mut FunctionValidationContext, value_type1: StackValueType, value_type2: StackValueType) -> Result<InstructionOutcome, Error> { fn validate_cvtop(context: &mut FunctionValidationContext<E>, value_type1: StackValueType, value_type2: StackValueType) -> Result<InstructionOutcome, Error> {
context.pop_value(value_type1)?; context.pop_value(value_type1)?;
context.push_value(value_type2)?; context.push_value(value_type2)?;
Ok(InstructionOutcome::ValidateNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_drop(context: &mut FunctionValidationContext) -> Result<InstructionOutcome, Error> { fn validate_drop(context: &mut FunctionValidationContext<E>) -> Result<InstructionOutcome, Error> {
context.pop_any_value().map(|_| ())?; context.pop_any_value().map(|_| ())?;
Ok(InstructionOutcome::ValidateNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_select(context: &mut FunctionValidationContext) -> Result<InstructionOutcome, Error> { fn validate_select(context: &mut FunctionValidationContext<E>) -> Result<InstructionOutcome, Error> {
context.pop_value(ValueType::I32.into())?; context.pop_value(ValueType::I32.into())?;
let select_type = context.pop_any_value()?; let select_type = context.pop_any_value()?;
context.pop_value(select_type)?; context.pop_value(select_type)?;
@ -362,13 +364,13 @@ impl Validator {
Ok(InstructionOutcome::ValidateNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_get_local(context: &mut FunctionValidationContext, index: u32) -> Result<InstructionOutcome, Error> { fn validate_get_local(context: &mut FunctionValidationContext<E>, index: u32) -> Result<InstructionOutcome, Error> {
let local_type = context.require_local(index)?; let local_type = context.require_local(index)?;
context.push_value(local_type)?; context.push_value(local_type)?;
Ok(InstructionOutcome::ValidateNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_set_local(context: &mut FunctionValidationContext, index: u32) -> Result<InstructionOutcome, Error> { fn validate_set_local(context: &mut FunctionValidationContext<E>, index: u32) -> Result<InstructionOutcome, Error> {
let local_type = context.require_local(index)?; let local_type = context.require_local(index)?;
let value_type = context.pop_any_value()?; let value_type = context.pop_any_value()?;
if local_type != value_type { if local_type != value_type {
@ -377,7 +379,7 @@ impl Validator {
Ok(InstructionOutcome::ValidateNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_tee_local(context: &mut FunctionValidationContext, index: u32) -> Result<InstructionOutcome, Error> { fn validate_tee_local(context: &mut FunctionValidationContext<E>, index: u32) -> Result<InstructionOutcome, Error> {
let local_type = context.require_local(index)?; let local_type = context.require_local(index)?;
let value_type = context.tee_any_value()?; let value_type = context.tee_any_value()?;
if local_type != value_type { if local_type != value_type {
@ -386,13 +388,13 @@ impl Validator {
Ok(InstructionOutcome::ValidateNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_get_global(context: &mut FunctionValidationContext, index: u32) -> Result<InstructionOutcome, Error> { fn validate_get_global(context: &mut FunctionValidationContext<E>, index: u32) -> Result<InstructionOutcome, Error> {
let global_type = context.require_global(index, None)?; let global_type = context.require_global(index, None)?;
context.push_value(global_type)?; context.push_value(global_type)?;
Ok(InstructionOutcome::ValidateNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_set_global(context: &mut FunctionValidationContext, index: u32) -> Result<InstructionOutcome, Error> { fn validate_set_global(context: &mut FunctionValidationContext<E>, index: u32) -> Result<InstructionOutcome, Error> {
let global_type = context.require_global(index, Some(true))?; let global_type = context.require_global(index, Some(true))?;
let value_type = context.pop_any_value()?; let value_type = context.pop_any_value()?;
if global_type != value_type { if global_type != value_type {
@ -401,7 +403,7 @@ impl Validator {
Ok(InstructionOutcome::ValidateNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_load(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: StackValueType) -> Result<InstructionOutcome, Error> { fn validate_load(context: &mut FunctionValidationContext<E>, align: u32, max_align: u32, value_type: StackValueType) -> Result<InstructionOutcome, Error> {
if align != NATURAL_ALIGNMENT { if align != NATURAL_ALIGNMENT {
if 1u32.checked_shl(align).unwrap_or(u32::MAX) > max_align { 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))); 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) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_store(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: StackValueType) -> Result<InstructionOutcome, Error> { fn validate_store(context: &mut FunctionValidationContext<E>, align: u32, max_align: u32, value_type: StackValueType) -> Result<InstructionOutcome, Error> {
if align != NATURAL_ALIGNMENT { if align != NATURAL_ALIGNMENT {
if 1u32.checked_shl(align).unwrap_or(u32::MAX) > max_align { 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))); 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) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_block(context: &mut FunctionValidationContext, block_type: BlockType) -> Result<InstructionOutcome, Error> { fn validate_block(context: &mut FunctionValidationContext<E>, block_type: BlockType) -> Result<InstructionOutcome, Error> {
context.push_label(BlockFrameType::Block, block_type).map(|_| InstructionOutcome::ValidateNextInstruction) context.push_label(BlockFrameType::Block, block_type).map(|_| InstructionOutcome::ValidateNextInstruction)
} }
fn validate_loop(context: &mut FunctionValidationContext, block_type: BlockType) -> Result<InstructionOutcome, Error> { fn validate_loop(context: &mut FunctionValidationContext<E>, block_type: BlockType) -> Result<InstructionOutcome, Error> {
context.push_label(BlockFrameType::Loop, block_type).map(|_| InstructionOutcome::ValidateNextInstruction) context.push_label(BlockFrameType::Loop, block_type).map(|_| InstructionOutcome::ValidateNextInstruction)
} }
fn validate_if(context: &mut FunctionValidationContext, block_type: BlockType) -> Result<InstructionOutcome, Error> { fn validate_if(context: &mut FunctionValidationContext<E>, block_type: BlockType) -> Result<InstructionOutcome, Error> {
context.pop_value(ValueType::I32.into())?; context.pop_value(ValueType::I32.into())?;
context.push_label(BlockFrameType::IfTrue, block_type).map(|_| InstructionOutcome::ValidateNextInstruction) context.push_label(BlockFrameType::IfTrue, block_type).map(|_| InstructionOutcome::ValidateNextInstruction)
} }
fn validate_else(context: &mut FunctionValidationContext) -> Result<InstructionOutcome, Error> { fn validate_else(context: &mut FunctionValidationContext<E>) -> Result<InstructionOutcome, Error> {
let block_type = { let block_type = {
let top_frame = context.top_label()?; let top_frame = context.top_label()?;
if top_frame.frame_type != BlockFrameType::IfTrue { if top_frame.frame_type != BlockFrameType::IfTrue {
@ -456,7 +458,7 @@ impl Validator {
context.push_label(BlockFrameType::IfFalse, block_type).map(|_| InstructionOutcome::ValidateNextInstruction) context.push_label(BlockFrameType::IfFalse, block_type).map(|_| InstructionOutcome::ValidateNextInstruction)
} }
fn validate_end(context: &mut FunctionValidationContext) -> Result<InstructionOutcome, Error> { fn validate_end(context: &mut FunctionValidationContext<E>) -> Result<InstructionOutcome, Error> {
{ {
let top_frame = context.top_label()?; let top_frame = context.top_label()?;
if top_frame.frame_type == BlockFrameType::IfTrue { if top_frame.frame_type == BlockFrameType::IfTrue {
@ -469,7 +471,7 @@ impl Validator {
context.pop_label().map(|_| InstructionOutcome::ValidateNextInstruction) context.pop_label().map(|_| InstructionOutcome::ValidateNextInstruction)
} }
fn validate_br(context: &mut FunctionValidationContext, idx: u32) -> Result<InstructionOutcome, Error> { fn validate_br(context: &mut FunctionValidationContext<E>, idx: u32) -> Result<InstructionOutcome, Error> {
let (frame_type, frame_block_type) = { let (frame_type, frame_block_type) = {
let frame = context.require_label(idx)?; let frame = context.require_label(idx)?;
(frame.frame_type, frame.block_type) (frame.frame_type, frame.block_type)
@ -483,7 +485,7 @@ impl Validator {
Ok(InstructionOutcome::Unreachable) Ok(InstructionOutcome::Unreachable)
} }
fn validate_br_if(context: &mut FunctionValidationContext, idx: u32) -> Result<InstructionOutcome, Error> { fn validate_br_if(context: &mut FunctionValidationContext<E>, idx: u32) -> Result<InstructionOutcome, Error> {
context.pop_value(ValueType::I32.into())?; context.pop_value(ValueType::I32.into())?;
if let BlockType::Value(value_type) = context.require_label(idx)?.block_type { if let BlockType::Value(value_type) = context.require_label(idx)?.block_type {
context.tee_value(value_type.into())?; context.tee_value(value_type.into())?;
@ -491,7 +493,7 @@ impl Validator {
Ok(InstructionOutcome::ValidateNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_br_table(context: &mut FunctionValidationContext, table: &Vec<u32>, default: u32) -> Result<InstructionOutcome, Error> { fn validate_br_table(context: &mut FunctionValidationContext<E>, table: &Vec<u32>, default: u32) -> Result<InstructionOutcome, Error> {
let mut required_block_type = None; let mut required_block_type = None;
{ {
@ -523,14 +525,14 @@ impl Validator {
Ok(InstructionOutcome::Unreachable) Ok(InstructionOutcome::Unreachable)
} }
fn validate_return(context: &mut FunctionValidationContext) -> Result<InstructionOutcome, Error> { fn validate_return(context: &mut FunctionValidationContext<E>) -> Result<InstructionOutcome, Error> {
if let BlockType::Value(value_type) = context.return_type()? { if let BlockType::Value(value_type) = context.return_type()? {
context.tee_value(value_type.into())?; context.tee_value(value_type.into())?;
} }
Ok(InstructionOutcome::Unreachable) Ok(InstructionOutcome::Unreachable)
} }
fn validate_call(context: &mut FunctionValidationContext, idx: u32) -> Result<InstructionOutcome, Error> { fn validate_call(context: &mut FunctionValidationContext<E>, idx: u32) -> Result<InstructionOutcome, Error> {
let (argument_types, return_type) = context.require_function(idx)?; let (argument_types, return_type) = context.require_function(idx)?;
for argument_type in argument_types.iter().rev() { for argument_type in argument_types.iter().rev() {
context.pop_value((*argument_type).into())?; context.pop_value((*argument_type).into())?;
@ -541,7 +543,7 @@ impl Validator {
Ok(InstructionOutcome::ValidateNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_call_indirect(context: &mut FunctionValidationContext, idx: u32) -> Result<InstructionOutcome, Error> { fn validate_call_indirect(context: &mut FunctionValidationContext<E>, idx: u32) -> Result<InstructionOutcome, Error> {
context.require_table(DEFAULT_TABLE_INDEX, VariableType::AnyFunc)?; context.require_table(DEFAULT_TABLE_INDEX, VariableType::AnyFunc)?;
context.pop_value(ValueType::I32.into())?; context.pop_value(ValueType::I32.into())?;
@ -555,13 +557,13 @@ impl Validator {
Ok(InstructionOutcome::ValidateNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_current_memory(context: &mut FunctionValidationContext) -> Result<InstructionOutcome, Error> { fn validate_current_memory(context: &mut FunctionValidationContext<E>) -> Result<InstructionOutcome, Error> {
context.require_memory(DEFAULT_MEMORY_INDEX)?; context.require_memory(DEFAULT_MEMORY_INDEX)?;
context.push_value(ValueType::I32.into())?; context.push_value(ValueType::I32.into())?;
Ok(InstructionOutcome::ValidateNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_grow_memory(context: &mut FunctionValidationContext) -> Result<InstructionOutcome, Error> { fn validate_grow_memory(context: &mut FunctionValidationContext<E>) -> Result<InstructionOutcome, Error> {
context.require_memory(DEFAULT_MEMORY_INDEX)?; context.require_memory(DEFAULT_MEMORY_INDEX)?;
context.pop_value(ValueType::I32.into())?; context.pop_value(ValueType::I32.into())?;
context.push_value(ValueType::I32.into())?; context.push_value(ValueType::I32.into())?;
@ -569,10 +571,10 @@ impl Validator {
} }
} }
impl<'a> FunctionValidationContext<'a> { impl<'a, E> FunctionValidationContext<'a, E> where E: CustomUserError {
pub fn new( pub fn new(
module_instance: &'a ModuleInstance, module_instance: &'a ModuleInstance<E>,
externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>>,
locals: &'a [ValueType], locals: &'a [ValueType],
value_stack_limit: usize, value_stack_limit: usize,
frame_stack_limit: usize, frame_stack_limit: usize,

View File

@ -21,7 +21,10 @@ pub use elements::{
pub use interpreter::{ pub use interpreter::{
ProgramInstance, ProgramInstance,
CustomProgramInstance,
ModuleInstance, ModuleInstance,
CustomModuleInstance,
ModuleInstanceInterface, ModuleInstanceInterface,
CustomModuleInstanceInterface,
RuntimeValue, RuntimeValue,
}; };