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 parity_wasm::{interpreter, ModuleInstanceInterface};
use parity_wasm::{interpreter, CustomModuleInstanceInterface};
fn main() {
let args: Vec<_> = args().collect();

View File

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

View File

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

View File

@ -3,7 +3,7 @@ use std::collections::HashMap;
use builder::module;
use elements::{Module, ExportEntry, Internal, GlobalEntry, GlobalType,
ValueType, InitExpr, Opcode, Opcodes};
use interpreter::Error;
use interpreter::{Error, CustomUserError, InterpreterError};
use interpreter::env_native::NATIVE_INDEX_FUNC_MIN;
use interpreter::module::{ModuleInstanceInterface, ModuleInstance, ExecutionParams,
ItemIndex, CallerContext, ExportEntryType, InternalFunctionReference, InternalFunction, FunctionSignature};
@ -78,12 +78,12 @@ pub struct EnvParams {
pub allow_memory_growth: bool,
}
pub struct EnvModuleInstance {
pub struct EnvModuleInstance<E: CustomUserError> {
_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> {
let mut instance = ModuleInstance::new(Weak::default(), "env".into(), module)?;
instance.instantiate(None)?;
@ -95,12 +95,12 @@ impl EnvModuleInstance {
}
}
impl ModuleInstanceInterface for EnvModuleInstance {
fn execute_index(&self, index: u32, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
impl<E> ModuleInstanceInterface<E> for EnvModuleInstance<E> where E: CustomUserError {
fn execute_index(&self, index: u32, params: ExecutionParams<E>) -> Result<Option<RuntimeValue>, InterpreterError<E>> {
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)
}
@ -116,7 +116,7 @@ impl ModuleInstanceInterface for EnvModuleInstance {
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)
}
@ -128,11 +128,11 @@ impl ModuleInstanceInterface for EnvModuleInstance {
self.instance.function_type_by_index(type_index)
}
fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap<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)
}
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)
}
@ -140,12 +140,13 @@ impl ModuleInstanceInterface for EnvModuleInstance {
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
match index {
INDEX_FUNC_ABORT => self.global(ItemIndex::IndexSpace(INDEX_GLOBAL_ABORT), Some(VariableType::I32), None)
.and_then(|g| g.set(RuntimeValue::I32(1)))
.and_then(|_| Err(Error::Trap("abort".into()))),
.and_then(|_| Err(Error::Trap("abort".into())))
.map_err(Into::into),
INDEX_FUNC_ASSERT => outer.value_stack.pop_as::<i32>()
.and_then(|condition| if condition == 0 {
self.global(ItemIndex::IndexSpace(INDEX_GLOBAL_ABORT), Some(VariableType::I32), None)
@ -153,18 +154,20 @@ impl ModuleInstanceInterface for EnvModuleInstance {
.and_then(|_| Err(Error::Trap("assertion failed".into())))
} else {
Ok(None)
}),
})
.map_err(Into::into),
INDEX_FUNC_ENLARGE_MEMORY => Ok(Some(RuntimeValue::I32(0))), // TODO: support memory enlarge
INDEX_FUNC_GET_TOTAL_MEMORY => self.global(ItemIndex::IndexSpace(INDEX_GLOBAL_TOTAL_MEMORY), Some(VariableType::I32), None)
.map(|g| g.get())
.map(Some),
INDEX_FUNC_MIN_NONUSED ... INDEX_FUNC_MAX => Err(Error::Trap("unimplemented".into())),
_ => Err(Error::Trap(format!("trying to call function with index {} in env module", index))),
.map(Some)
.map_err(Into::into),
INDEX_FUNC_MIN_NONUSED ... INDEX_FUNC_MAX => Err(Error::Trap("unimplemented".into()).into()),
_ => Err(Error::Trap(format!("trying to call function with index {} in env module", index)).into()),
}
}
}
pub fn env_module(params: EnvParams) -> Result<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 % 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 parking_lot::RwLock;
use elements::{Internal, ValueType};
use interpreter::Error;
use interpreter::{Error, CustomUserError, InterpreterError};
use interpreter::module::{ModuleInstanceInterface, ExecutionParams, ItemIndex,
CallerContext, ExportEntryType, InternalFunctionReference, InternalFunction, FunctionSignature};
use interpreter::memory::MemoryInstance;
@ -17,9 +17,9 @@ pub const NATIVE_INDEX_FUNC_MIN: u32 = 10001;
pub const NATIVE_INDEX_GLOBAL_MIN: u32 = 20001;
/// User functions executor.
pub trait UserFunctionExecutor {
pub trait UserFunctionExecutor<E: CustomUserError> {
/// 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
@ -68,21 +68,21 @@ impl UserFunctionDescriptor {
}
/// Set of user-defined module elements.
pub struct UserDefinedElements<'a> {
pub struct UserDefinedElements<'a, E: 'a + CustomUserError> {
/// User globals list.
pub globals: HashMap<String, Arc<VariableInstance>>,
/// User functions list.
pub functions: Cow<'static, [UserFunctionDescriptor]>,
/// Functions executor.
pub executor: Option<&'a mut UserFunctionExecutor>,
pub executor: Option<&'a mut UserFunctionExecutor<E>>,
}
/// Native module instance.
pub struct NativeModuleInstance<'a> {
pub struct NativeModuleInstance<'a, E: 'a + CustomUserError> {
/// Underllying module reference.
env: Arc<ModuleInstanceInterface>,
env: Arc<ModuleInstanceInterface<E>>,
/// User function executor.
executor: RwLock<Option<&'a mut UserFunctionExecutor>>,
executor: RwLock<Option<&'a mut UserFunctionExecutor<E>>>,
/// By-name functions index.
functions_by_name: HashMap<String, u32>,
/// User functions list.
@ -93,9 +93,9 @@ pub struct NativeModuleInstance<'a> {
globals: Vec<Arc<VariableInstance>>,
}
impl<'a> NativeModuleInstance<'a> {
impl<'a, E> NativeModuleInstance<'a, E> where E: CustomUserError {
/// 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() {
return Err(Error::Function("trying to construct native env module with functions, but without executor".into()));
}
@ -111,12 +111,12 @@ impl<'a> NativeModuleInstance<'a> {
}
}
impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> {
fn execute_index(&self, index: u32, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
impl<'a, E> ModuleInstanceInterface<E> for NativeModuleInstance<'a, E> where E: CustomUserError {
fn execute_index(&self, index: u32, params: ExecutionParams<E>) -> Result<Option<RuntimeValue>, InterpreterError<E>> {
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)
}
@ -155,7 +155,7 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> {
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 {
ItemIndex::IndexSpace(index) | ItemIndex::Internal(index) => index,
ItemIndex::External(_) => unreachable!("trying to get global, exported by native env module"),
@ -190,11 +190,11 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> {
self.function_type(ItemIndex::Internal(type_index))
}
fn function_reference<'b>(&self, index: ItemIndex, externals: Option<&'b HashMap<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)
}
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)
}
@ -202,14 +202,14 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> {
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 {
return self.env.call_internal_function(outer, index);
}
self.functions
.get((index - NATIVE_INDEX_FUNC_MIN) as usize)
.ok_or(Error::Native(format!("trying to call native function with index {}", index)))
.ok_or(Error::Native(format!("trying to call native function with index {}", index)).into())
.and_then(|f| self.executor.write()
.as_mut()
.expect("function existss; if function exists, executor must also exists [checked in constructor]; qed")
@ -218,7 +218,7 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> {
}
/// Create wrapper for env module with given native user functions.
pub fn env_native_module<'a>(env: Arc<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)
}

View File

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

View File

@ -2,6 +2,19 @@
/// Interpreter error.
#[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 {
/// Program-level error.
Program(String),
@ -35,6 +48,12 @@ pub enum Error {
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 {
fn into(self) -> String {
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_native;
mod imports;
@ -74,10 +103,24 @@ mod variable;
mod tests;
pub use self::memory::MemoryInstance;
pub use self::module::{ModuleInstance, ModuleInstanceInterface, ItemIndex, ExportEntryType, CallerContext, ExecutionParams, FunctionSignature};
pub use self::module::{ModuleInstance as CustomModuleInstance,
ModuleInstanceInterface as CustomModuleInstanceInterface,
ItemIndex, ExportEntryType, CallerContext, ExecutionParams, FunctionSignature};
pub use self::table::TableInstance;
pub use self::program::ProgramInstance;
pub use self::program::ProgramInstance as CustomProgramInstance;
pub use self::value::RuntimeValue;
pub use self::variable::{VariableInstance, VariableType, ExternalVariableValue};
pub use self::env_native::{env_native_module, UserDefinedElements, UserFunctionExecutor, UserFunctionDescriptor};
pub use self::env::EnvParams;
/// 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::fmt;
use elements::{Module, InitExpr, Opcode, Type, FunctionType, Internal, External, BlockType, ResizableLimits, Local, ValueType};
use interpreter::Error;
use interpreter::{Error, CustomUserError, InterpreterError};
use interpreter::env_native::UserFunctionDescriptor;
use interpreter::imports::ModuleImports;
use interpreter::memory::MemoryInstance;
@ -21,12 +21,12 @@ const DEFAULT_VALUE_STACK_LIMIT: usize = 16384;
const DEFAULT_FRAME_STACK_LIMIT: usize = 1024;
/// Execution context.
#[derive(Default, Clone)]
pub struct ExecutionParams<'a> {
#[derive(Clone)]
pub struct ExecutionParams<'a, E: CustomUserError> {
/// Arguments.
pub args: Vec<RuntimeValue>,
/// Execution-local external modules.
pub externals: HashMap<String, Arc<ModuleInstanceInterface + 'a>>,
pub externals: HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>,
}
/// Export type.
@ -50,11 +50,11 @@ pub enum FunctionSignature<'a> {
}
/// Module instance API.
pub trait ModuleInstanceInterface {
pub trait ModuleInstanceInterface<E: CustomUserError> {
/// 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.
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.
fn export_entry<'a>(&self, name: &str, required_type: &ExportEntryType) -> Result<Internal, Error>;
/// Get table reference.
@ -62,19 +62,19 @@ pub trait ModuleInstanceInterface {
/// Get memory reference.
fn memory(&self, index: ItemIndex) -> Result<Arc<MemoryInstance>, Error>;
/// 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.
fn function_type(&self, function_index: ItemIndex) -> Result<FunctionSignature, Error>;
/// Get function type for given function index.
fn function_type_by_index(&self, type_index: u32) -> Result<FunctionSignature, Error>;
/// 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.
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.
fn function_body<'a>(&'a self, internal_index: u32) -> Result<Option<InternalFunction<'a>>, Error>;
/// 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.
@ -89,7 +89,7 @@ pub enum ItemIndex {
}
/// Module instance.
pub struct ModuleInstance {
pub struct ModuleInstance<E: CustomUserError> {
/// Module name.
name: String,
/// Module.
@ -97,7 +97,7 @@ pub struct ModuleInstance {
/// Function labels.
functions_labels: HashMap<u32, HashMap<usize, usize>>,
/// Module imports.
imports: ModuleImports,
imports: ModuleImports<E>,
/// Module exports.
exports: HashMap<String, Vec<Internal>>,
/// Tables.
@ -109,7 +109,7 @@ pub struct ModuleInstance {
}
/// Caller context.
pub struct CallerContext<'a> {
pub struct CallerContext<'a, E: 'a + CustomUserError> {
/// Value stack limit
pub value_stack_limit: usize,
/// Frame stack limit
@ -117,19 +117,19 @@ pub struct CallerContext<'a> {
/// Stack of the input parameters
pub value_stack: &'a mut StackWithLimit<RuntimeValue>,
/// Execution-local external modules.
pub externals: &'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>,
pub externals: &'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>,
}
/// Internal function reference.
#[derive(Clone)]
pub struct InternalFunctionReference<'a> {
pub struct InternalFunctionReference<'a, E: CustomUserError> {
/// Module reference.
pub module: Arc<ModuleInstanceInterface + 'a>,
pub module: Arc<ModuleInstanceInterface<E> + 'a>,
/// Internal function index.
pub internal_index: u32,
}
impl<'a> fmt::Debug for InternalFunctionReference<'a> {
impl<'a, E> fmt::Debug for InternalFunctionReference<'a, E> where E: CustomUserError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "InternalFunctionReference")
}
@ -145,9 +145,9 @@ pub struct InternalFunction<'a> {
pub labels: &'a HashMap<usize, usize>,
}
impl<'a> ExecutionParams<'a> {
impl<'a, E> ExecutionParams<'a, E> where E: CustomUserError {
/// Create new execution params with given externa; module override.
pub fn with_external(name: String, module: Arc<ModuleInstanceInterface + 'a>) -> Self {
pub fn with_external(name: String, module: Arc<ModuleInstanceInterface<E> + 'a>) -> Self {
let mut externals = HashMap::new();
externals.insert(name, module);
ExecutionParams {
@ -163,8 +163,17 @@ impl<'a> ExecutionParams<'a> {
}
}
impl<'a> From<Vec<RuntimeValue>> for ExecutionParams<'a> {
fn from(args: Vec<RuntimeValue>) -> ExecutionParams<'a> {
impl<'a, E> Default for ExecutionParams<'a, E> where E: CustomUserError {
fn default() -> Self {
ExecutionParams {
args: Vec::default(),
externals: HashMap::default(),
}
}
}
impl<'a, E> From<Vec<RuntimeValue>> for ExecutionParams<'a, E> where E: CustomUserError {
fn from(args: Vec<RuntimeValue>) -> ExecutionParams<'a, E> {
ExecutionParams {
args: args,
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.
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
let imports = ModuleImports::new(program, module.import_section());
@ -222,7 +231,7 @@ impl ModuleInstance {
}
/// Run instantiation-time procedures (validation). Module is not completely validated until this call.
pub fn instantiate<'a>(&mut self, externals: Option<&'a HashMap<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
if let Some(start_function) = self.module.start_section() {
let func_type_index = self.require_function(ItemIndex::IndexSpace(start_function))?;
@ -388,7 +397,7 @@ impl ModuleInstance {
}
/// Run start function [if any].
pub fn run_start_function(&self) -> Result<(), Error> {
pub fn run_start_function(&self) -> Result<(), InterpreterError<E>> {
// execute start function (if any)
if let Some(start_function) = self.module.start_section() {
self.execute_index(start_function, ExecutionParams::default())?;
@ -396,7 +405,7 @@ impl ModuleInstance {
Ok(())
}
fn self_ref<'a>(&self, externals: Option<&'a HashMap<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)
}
@ -420,8 +429,8 @@ impl ModuleInstance {
}
}
impl ModuleInstanceInterface for ModuleInstance {
fn execute_index(&self, index: u32, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
impl<E> ModuleInstanceInterface<E> for ModuleInstance<E> where E: CustomUserError {
fn execute_index(&self, index: u32, params: ExecutionParams<E>) -> Result<Option<RuntimeValue>, InterpreterError<E>> {
let ExecutionParams { args, externals } = params;
let mut args = StackWithLimit::with_data(args, DEFAULT_VALUE_STACK_LIMIT);
let function_reference = self.function_reference(ItemIndex::IndexSpace(index), Some(&externals))?;
@ -429,7 +438,7 @@ impl ModuleInstanceInterface for ModuleInstance {
function_reference.module.call_internal_function(function_context, function_reference.internal_index)
}
fn execute_export(&self, name: &str, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
fn execute_export(&self, name: &str, params: ExecutionParams<E>) -> Result<Option<RuntimeValue>, InterpreterError<E>> {
let index = self.exports.get(name)
.ok_or(Error::Function(format!("missing executable export with name {}", name)))
.and_then(|l| l.iter()
@ -494,7 +503,7 @@ impl ModuleInstanceInterface for ModuleInstance {
}
}
fn global<'a>(&self, index: ItemIndex, variable_type: Option<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) {
ItemIndex::IndexSpace(_) => unreachable!("parse_global_index resolves IndexSpace option"),
ItemIndex::Internal(index) => self.globals.get(index as usize).cloned()
@ -533,7 +542,7 @@ impl ModuleInstanceInterface for ModuleInstance {
.map(FunctionSignature::Module)
}
fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap<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) {
ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"),
ItemIndex::Internal(index) => Ok(InternalFunctionReference {
@ -555,7 +564,7 @@ impl ModuleInstanceInterface for ModuleInstance {
}
}
fn function_reference_indirect<'a>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'a HashMap<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 (module, index) = match table.get(func_idx)? {
RuntimeValue::AnyFunc(module, index) => (module.clone(), index),
@ -591,7 +600,7 @@ impl ModuleInstanceInterface for ModuleInstance {
}))
}
fn call_internal_function(&self, mut outer: CallerContext, index: u32) -> Result<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 args = prepare_function_args(&function_type, outer.value_stack)?;
let function_ref = InternalFunctionReference { module: self.self_ref(Some(outer.externals))?, internal_index: index };
@ -600,9 +609,9 @@ impl ModuleInstanceInterface for ModuleInstance {
}
}
impl<'a> CallerContext<'a> {
impl<'a, E> CallerContext<'a, E> where E: CustomUserError {
/// Top most args
pub fn topmost(args: &'a mut StackWithLimit<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 {
value_stack_limit: DEFAULT_VALUE_STACK_LIMIT,
frame_stack_limit: DEFAULT_FRAME_STACK_LIMIT,
@ -612,7 +621,7 @@ impl<'a> CallerContext<'a> {
}
/// Nested context
pub fn nested(outer: &'a mut FunctionContext) -> Self {
pub fn nested(outer: &'a mut FunctionContext<E>) -> Self {
CallerContext {
value_stack_limit: outer.value_stack().limit() - outer.value_stack().len(),
frame_stack_limit: outer.frame_stack().limit() - outer.frame_stack().len(),
@ -632,7 +641,7 @@ pub fn check_limits(limits: &ResizableLimits) -> Result<(), Error> {
Ok(())
}
fn get_initializer(expr: &InitExpr, module: &Module, imports: &ModuleImports, expected_type: VariableType) -> Result<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() {
1 => &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 parking_lot::RwLock;
use elements::Module;
use interpreter::Error;
use interpreter::{Error, CustomUserError, InterpreterError};
use interpreter::env::{self, env_module};
use interpreter::module::{ModuleInstance, ModuleInstanceInterface};
/// Program instance. Program is a set of instantiated modules.
pub struct ProgramInstance {
pub struct ProgramInstance<E: CustomUserError> {
/// Shared data reference.
essence: Arc<ProgramInstanceEssence>,
essence: Arc<ProgramInstanceEssence<E>>,
}
/// Program instance essence.
pub struct ProgramInstanceEssence {
pub struct ProgramInstanceEssence<E: CustomUserError> {
/// 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.
pub fn new() -> Result<Self, Error> {
ProgramInstance::with_env_params(env::EnvParams::default())
@ -32,7 +32,7 @@ impl ProgramInstance {
}
/// Instantiate module with validation.
pub fn add_module<'a>(&self, name: &str, module: Module, externals: Option<&'a HashMap<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)?;
module_instance.instantiate(externals)?;
@ -43,19 +43,19 @@ impl ProgramInstance {
}
/// 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
self.essence.modules.write().insert(name.into(), module_instance.clone());
Ok(module_instance)
}
/// Get one of the modules by name
pub fn module(&self, name: &str) -> Option<Arc<ModuleInstanceInterface>> {
pub fn module(&self, name: &str) -> Option<Arc<ModuleInstanceInterface<E>>> {
self.essence.module(name)
}
}
impl ProgramInstanceEssence {
impl<E> ProgramInstanceEssence<E> where E: CustomUserError {
/// Create new program essence.
pub fn new() -> Result<Self, Error> {
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> {
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);
Ok(ProgramInstanceEssence {
modules: RwLock::new(modules),
@ -71,7 +71,7 @@ impl ProgramInstanceEssence {
}
/// 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()
}
}

View File

@ -6,7 +6,7 @@ use std::fmt::{self, Display};
use std::iter::repeat;
use std::collections::{HashMap, VecDeque};
use elements::{Opcode, BlockType, Local};
use interpreter::Error;
use interpreter::{Error, CustomUserError, InterpreterError};
use interpreter::module::{ModuleInstanceInterface, CallerContext, ItemIndex, InternalFunctionReference, FunctionSignature};
use interpreter::stack::StackWithLimit;
use interpreter::value::{
@ -22,16 +22,18 @@ pub const DEFAULT_MEMORY_INDEX: u32 = 0;
pub const DEFAULT_TABLE_INDEX: u32 = 0;
/// Function interpreter.
pub struct Interpreter;
pub struct Interpreter<E: CustomUserError> {
_dummy: ::std::marker::PhantomData<E>,
}
/// Function execution context.
pub struct FunctionContext<'a> {
pub struct FunctionContext<'a, E: 'a + CustomUserError> {
/// Is context initialized.
pub is_initialized: bool,
/// Internal function reference.
pub function: InternalFunctionReference<'a>,
pub function: InternalFunctionReference<'a, E>,
/// Execution-local external modules.
pub externals: &'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>,
pub externals: &'a HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>>,
/// Function return type.
pub return_type: BlockType,
/// Local variables.
@ -46,13 +48,13 @@ pub struct FunctionContext<'a> {
/// Interpreter action to execute after executing instruction.
#[derive(Debug)]
pub enum InstructionOutcome<'a> {
pub enum InstructionOutcome<'a, E: CustomUserError> {
/// Continue with next instruction.
RunNextInstruction,
/// Branch to given frame.
Branch(usize),
/// Execute function call.
ExecuteCall(InternalFunctionReference<'a>),
ExecuteCall(InternalFunctionReference<'a, E>),
/// End current frame.
End,
/// Return from current function block.
@ -60,15 +62,15 @@ pub enum InstructionOutcome<'a> {
}
/// Function run result.
enum RunResult<'a> {
enum RunResult<'a, E: 'a + CustomUserError> {
/// Function has returned (optional) value.
Return(Option<RuntimeValue>),
/// Function is calling other function.
NestedCall(FunctionContext<'a>),
NestedCall(FunctionContext<'a, E>),
}
impl Interpreter {
pub fn run_function(function_context: FunctionContext) -> Result<Option<RuntimeValue>, Error> {
impl<E> Interpreter<E> where E: CustomUserError {
pub fn run_function(function_context: FunctionContext<E>) -> Result<Option<RuntimeValue>, InterpreterError<E>> {
let mut function_stack = VecDeque::new();
function_stack.push_back(function_context);
@ -118,7 +120,7 @@ impl Interpreter {
}
}
fn do_run_function<'a>(function_context: &mut FunctionContext<'a>, function_body: &[Opcode], function_labels: &HashMap<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 {
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 {
&Opcode::Unreachable => Interpreter::run_unreachable(context),
&Opcode::Nop => Interpreter::run_nop(context),
@ -350,25 +352,25 @@ impl Interpreter {
}
}
fn run_unreachable<'a>(_context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
fn run_unreachable<'a>(_context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error> {
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)
}
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)?;
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)?;
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 block_frame_type = if branch { BlockFrameType::IfTrue } else {
let else_pos = labels[&context.position];
@ -383,23 +385,23 @@ impl Interpreter {
context.push_frame(labels, block_frame_type, block_type).map(|_| InstructionOutcome::RunNextInstruction)
}
fn run_else<'a>(context: &mut FunctionContext, labels: &HashMap<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];
context.pop_frame(false)?;
context.position = end_pos;
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)?;
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))
}
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()? {
Ok(InstructionOutcome::Branch(label_idx as usize))
} 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()?;
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)
}
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))?))
}
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 function_reference = context.module().function_reference_indirect(DEFAULT_TABLE_INDEX, type_idx, table_func_idx, Some(context.externals))?;
{
@ -435,14 +437,14 @@ impl Interpreter {
Ok(InstructionOutcome::ExecuteCall(function_reference))
}
fn run_drop<'a>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
fn run_drop<'a>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error> {
context
.value_stack_mut()
.pop()
.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
.value_stack_mut()
.pop_triple()
@ -457,32 +459,32 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction)
}
fn run_get_local<'a>(context: &mut FunctionContext, index: u32) -> Result<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)
.map(|value| context.value_stack_mut().push(value))
.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()?;
context.set_local(index as usize, arg)
.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();
context.set_local(index as usize, arg)
.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()
.global(ItemIndex::IndexSpace(index), None, Some(context.externals))
.and_then(|g| context.value_stack_mut().push(g.get()))
.map(|_| InstructionOutcome::RunNextInstruction)
}
fn run_set_global<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome<'a>, Error> {
fn run_set_global<'a>(context: &mut FunctionContext<E>, index: u32) -> Result<InstructionOutcome<'a, E>, Error> {
context
.value_stack_mut()
.pop()
@ -490,7 +492,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction)
}
fn run_load<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result<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 {
let address = effective_address(offset, context.value_stack_mut().pop_as()?)?;
context.module()
@ -501,7 +503,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction)
}
fn run_load_extend<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result<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 {
let address = effective_address(offset, context.value_stack_mut().pop_as()?)?;
let stack_value: U = context.module()
@ -515,7 +517,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction)
}
fn run_store<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result<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 {
let stack_value = context
.value_stack_mut()
@ -528,7 +530,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction)
}
fn run_store_wrap<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result<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 {
let stack_value: T = context.value_stack_mut().pop().and_then(|v| v.try_into())?;
let stack_value = stack_value.wrap_into().into_little_endian();
@ -539,7 +541,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction)
}
fn run_current_memory<'a>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
fn run_current_memory<'a>(context: &mut FunctionContext<E>) -> Result<InstructionOutcome<'a, E>, Error> {
context.module()
.memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX))
.map(|m| m.size())
@ -547,7 +549,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction)
}
fn run_grow_memory<'a>(context: &mut FunctionContext) -> Result<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()?;
context.module()
.memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX))
@ -556,14 +558,14 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction)
}
fn run_const<'a>(context: &mut FunctionContext, val: RuntimeValue) -> Result<InstructionOutcome<'a>, Error> {
fn run_const<'a>(context: &mut FunctionContext<E>, val: RuntimeValue) -> Result<InstructionOutcome<'a, E>, Error> {
context
.value_stack_mut()
.push(val)
.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 {
context
.value_stack_mut()
@ -573,7 +575,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -583,7 +585,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -593,7 +595,7 @@ impl Interpreter {
.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 {
context
.value_stack_mut()
@ -603,7 +605,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -613,7 +615,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -623,7 +625,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -633,7 +635,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -643,7 +645,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -653,7 +655,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -663,7 +665,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -673,7 +675,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -683,7 +685,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -693,7 +695,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -705,7 +707,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -717,7 +719,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -727,7 +729,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -737,7 +739,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -747,7 +749,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -757,7 +759,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction)
}
fn run_shr<'a, T, U>(context: &mut FunctionContext, mask: U) -> Result<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> {
context
.value_stack_mut()
@ -769,7 +771,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -779,7 +781,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -789,7 +791,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -799,7 +801,7 @@ impl Interpreter {
.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 {
context
.value_stack_mut()
@ -809,7 +811,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -819,7 +821,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -829,7 +831,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -839,7 +841,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -849,7 +851,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -859,7 +861,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -869,7 +871,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -879,7 +881,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -889,7 +891,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -899,7 +901,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction)
}
fn run_trunc_to_int<'a, T, U, V>(context: &mut FunctionContext) -> Result<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>, {
context
.value_stack_mut()
@ -910,7 +912,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -921,7 +923,7 @@ impl Interpreter {
.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> {
context
.value_stack_mut()
@ -932,8 +934,8 @@ impl Interpreter {
}
}
impl<'a> FunctionContext<'a> {
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 {
impl<'a, E> FunctionContext<'a, E> where E: CustomUserError {
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 {
is_initialized: false,
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_type = function.module.function_type(ItemIndex::Internal(function.internal_index))?;
let function_return_type = function_type.return_type().map(|vt| BlockType::Value(vt)).unwrap_or(BlockType::NoResult);
@ -982,15 +984,15 @@ impl<'a> FunctionContext<'a> {
Ok(())
}
pub fn module(&self) -> &Arc<ModuleInstanceInterface + 'a> {
pub fn module(&self) -> &Arc<ModuleInstanceInterface<E> + 'a> {
&self.function.module
}
pub fn externals(&self) -> &HashMap<String, Arc<ModuleInstanceInterface + 'a>> {
pub fn externals(&self) -> &HashMap<String, Arc<ModuleInstanceInterface<E> + 'a>> {
&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)
.ok_or(Error::Local(format!("expected to have local with index {}", index)))
.and_then(|l| l.set(value))
@ -1072,7 +1074,7 @@ impl<'a> FunctionContext<'a> {
}
}
impl<'a> fmt::Debug for FunctionContext<'a> {
impl<'a, E> fmt::Debug for FunctionContext<'a, E> where E: CustomUserError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "FunctionContext")
}

View File

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

View File

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

View File

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

View File

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

View File

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