Skip to content
This repository has been archived by the owner on Oct 21, 2022. It is now read-only.

Commit

Permalink
Merge pull request #80 from NikVolf/custom_errors
Browse files Browse the repository at this point in the history
Custom user errors
  • Loading branch information
NikVolf authored Aug 1, 2017
2 parents f9bfb53 + ffd0621 commit 8f1e83e
Show file tree
Hide file tree
Showing 20 changed files with 621 additions and 509 deletions.
2 changes: 1 addition & 1 deletion examples/interpret.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ fn main() {
return;
}

let program = parity_wasm::ProgramInstance::with_env_params(
let program = parity_wasm::DefaultProgramInstance::with_env_params(
interpreter::EnvParams {
total_stack: 128*1024,
total_memory: 2*1024*1024,
Expand Down
2 changes: 1 addition & 1 deletion examples/invoke.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fn main() {
let func_name = &args[2];
let (_, program_args) = args.split_at(3);

let program = parity_wasm::ProgramInstance::with_env_params(
let program = parity_wasm::DefaultProgramInstance::with_env_params(
interpreter::EnvParams {
total_stack: 128*1024,
total_memory: 2*1024*1024,
Expand Down
15 changes: 8 additions & 7 deletions spec/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ use test;
use parity_wasm::{self, elements, builder};
use parity_wasm::interpreter::{
RuntimeValue,
ProgramInstance, ModuleInstance,
DefaultProgramInstance, DefaultModuleInstance,
ItemIndex, ExportEntryType,
Error as InterpreterError,
DummyError as DummyInterpreterError,
};

fn spec_test_module() -> elements::Module {
Expand Down Expand Up @@ -41,7 +42,7 @@ fn spec_test_module() -> elements::Module {
.build()
}

fn load_module(base_dir: &str, path: &str, name: &Option<String>, program: &ProgramInstance) -> Arc<ModuleInstance> {
fn load_module(base_dir: &str, path: &str, name: &Option<String>, program: &DefaultProgramInstance) -> Arc<DefaultModuleInstance> {
let module = try_deserialize(base_dir, path).expect(&format!("Wasm file {} failed to load", path));

program.add_module("spectest", spec_test_module(), None).expect("Failed adding 'spectest' module");
Expand All @@ -57,9 +58,9 @@ fn try_deserialize(base_dir: &str, module_path: &str) -> Result<elements::Module
parity_wasm::deserialize_file(&wasm_path)
}

fn try_load(base_dir: &str, module_path: &str) -> Result<(), parity_wasm::interpreter::Error> {
fn try_load(base_dir: &str, module_path: &str) -> Result<(), DummyInterpreterError> {
let module = try_deserialize(base_dir, module_path).map_err(|e| parity_wasm::interpreter::Error::Program(format!("{:?}", e)))?;
let program = ProgramInstance::new().expect("Failed creating program");
let program = DefaultProgramInstance::new().expect("Failed creating program");
program.add_module("try_load", module, None).map(|_| ())
}

Expand Down Expand Up @@ -89,8 +90,8 @@ fn runtime_values(test_vals: &[test::RuntimeValue]) -> Vec<parity_wasm::RuntimeV
test_vals.iter().map(runtime_value).collect::<Vec<parity_wasm::RuntimeValue>>()
}

fn run_action(program: &ProgramInstance, action: &test::Action)
-> Result<Option<parity_wasm::RuntimeValue>, InterpreterError>
fn run_action(program: &DefaultProgramInstance, action: &test::Action)
-> Result<Option<parity_wasm::RuntimeValue>, DummyInterpreterError>
{
match *action {
test::Action::Invoke { ref module, ref field, ref args } => {
Expand Down Expand Up @@ -172,7 +173,7 @@ pub fn spec(name: &str) {
.expect(&format!("Failed to load json file {}", &fixture.json));
let spec: test::Spec = serde_json::from_reader(&mut f).expect("Failed to deserialize JSON file");

let program = ProgramInstance::new().expect("Failed creating program");
let program = DefaultProgramInstance::new().expect("Failed creating program");
let mut last_module = None;
for command in &spec.commands {
println!("command {:?}", command);
Expand Down
51 changes: 27 additions & 24 deletions src/interpreter/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::collections::HashMap;
use builder::module;
use elements::{Module, ExportEntry, Internal, GlobalEntry, GlobalType,
ValueType, InitExpr, Opcode, Opcodes};
use interpreter::Error;
use interpreter::{Error, UserError};
use interpreter::env_native::NATIVE_INDEX_FUNC_MIN;
use interpreter::module::{ModuleInstanceInterface, ModuleInstance, ExecutionParams,
ItemIndex, CallerContext, ExportEntryType, InternalFunctionReference, InternalFunction, FunctionSignature};
Expand Down Expand Up @@ -78,13 +78,13 @@ pub struct EnvParams {
pub allow_memory_growth: bool,
}

pub struct EnvModuleInstance {
pub struct EnvModuleInstance<E: UserError> {
_params: EnvParams,
instance: ModuleInstance,
instance: ModuleInstance<E>,
}

impl EnvModuleInstance {
pub fn new(params: EnvParams, module: Module) -> Result<Self, Error> {
impl<E> EnvModuleInstance<E> where E: UserError {
pub fn new(params: EnvParams, module: Module) -> Result<Self, Error<E>> {
let mut instance = ModuleInstance::new(Weak::default(), "env".into(), module)?;
instance.instantiate(None)?;

Expand All @@ -95,76 +95,79 @@ 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: UserError {
fn execute_index(&self, index: u32, params: ExecutionParams<E>) -> Result<Option<RuntimeValue>, Error<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>, Error<E>> {
self.instance.execute_export(name, params)
}

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<E>> {
self.instance.export_entry(name, required_type)
}

fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance>, Error> {
fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance<E>>, Error<E>> {
self.instance.table(index)
}

fn memory(&self, index: ItemIndex) -> Result<Arc<MemoryInstance>, Error> {
fn memory(&self, index: ItemIndex) -> Result<Arc<MemoryInstance<E>>, Error<E>> {
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<E>>, Error<E>> {
self.instance.global(index, variable_type, externals)
}

fn function_type(&self, function_index: ItemIndex) -> Result<FunctionSignature, Error> {
fn function_type(&self, function_index: ItemIndex) -> Result<FunctionSignature, Error<E>> {
self.instance.function_type(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<E>> {
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<E>> {
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<E>> {
self.instance.function_reference_indirect(table_idx, type_idx, func_idx, externals)
}

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<E>> {
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>, Error<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)
.and_then(|g| g.set(RuntimeValue::I32(1)))
.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: UserError>(params: EnvParams) -> Result<EnvModuleInstance<E>, Error<E>> {
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);
Expand Down
54 changes: 27 additions & 27 deletions src/interpreter/env_native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::collections::HashMap;
use std::borrow::Cow;
use parking_lot::RwLock;
use elements::{Internal, ValueType};
use interpreter::Error;
use interpreter::{Error, UserError};
use interpreter::module::{ModuleInstanceInterface, ExecutionParams, ItemIndex,
CallerContext, ExportEntryType, InternalFunctionReference, InternalFunction, FunctionSignature};
use interpreter::memory::MemoryInstance;
Expand All @@ -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: UserError> {
/// 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>, Error<E>>;
}

/// User function descriptor
Expand Down Expand Up @@ -68,34 +68,34 @@ impl UserFunctionDescriptor {
}

/// Set of user-defined module elements.
pub struct UserDefinedElements<'a> {
pub struct UserDefinedElements<'a, E: 'a + UserError> {
/// User globals list.
pub globals: HashMap<String, Arc<VariableInstance>>,
pub globals: HashMap<String, Arc<VariableInstance<E>>>,
/// 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 + UserError> {
/// 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.
functions: Cow<'static, [UserFunctionDescriptor]>,
/// By-name functions index.
globals_by_name: HashMap<String, u32>,
/// User globals list.
globals: Vec<Arc<VariableInstance>>,
globals: Vec<Arc<VariableInstance<E>>>,
}

impl<'a> NativeModuleInstance<'a> {
impl<'a, E> NativeModuleInstance<'a, E> where E: UserError {
/// 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<E>> {
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()));
}
Expand All @@ -111,16 +111,16 @@ 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: UserError {
fn execute_index(&self, index: u32, params: ExecutionParams<E>) -> Result<Option<RuntimeValue>, Error<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>, Error<E>> {
self.env.execute_export(name, params)
}

fn export_entry<'b>(&self, name: &str, required_type: &ExportEntryType) -> Result<Internal, Error> {
fn export_entry<'b>(&self, name: &str, required_type: &ExportEntryType) -> Result<Internal, Error<E>> {
if let Some(index) = self.functions_by_name.get(name) {
let composite_index = NATIVE_INDEX_FUNC_MIN + *index;
match required_type {
Expand All @@ -147,15 +147,15 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> {
self.env.export_entry(name, required_type)
}

fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance>, Error> {
fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance<E>>, Error<E>> {
self.env.table(index)
}

fn memory(&self, index: ItemIndex) -> Result<Arc<MemoryInstance>, Error> {
fn memory(&self, index: ItemIndex) -> Result<Arc<MemoryInstance<E>>, Error<E>> {
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<E>>, Error<E>> {
let index = match global_index {
ItemIndex::IndexSpace(index) | ItemIndex::Internal(index) => index,
ItemIndex::External(_) => unreachable!("trying to get global, exported by native env module"),
Expand All @@ -171,7 +171,7 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> {
.ok_or(Error::Native(format!("trying to get native global with index {}", index)))
}

fn function_type(&self, function_index: ItemIndex) -> Result<FunctionSignature, Error> {
fn function_type(&self, function_index: ItemIndex) -> Result<FunctionSignature, Error<E>> {
let index = match function_index {
ItemIndex::IndexSpace(index) | ItemIndex::Internal(index) => index,
ItemIndex::External(_) => unreachable!("trying to call function, exported by native env module"),
Expand All @@ -186,30 +186,30 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> {
.ok_or(Error::Native(format!("missing native env function with index {}", index)))?))
}

fn function_type_by_index(&self, type_index: u32) -> Result<FunctionSignature, Error> {
fn function_type_by_index(&self, type_index: u32) -> Result<FunctionSignature, Error<E>> {
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<E>> {
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<E>> {
self.env.function_reference_indirect(table_idx, type_idx, func_idx, externals)
}

fn function_body<'b>(&'b self, _internal_index: u32) -> Result<Option<InternalFunction<'b>>, Error> {
fn function_body<'b>(&'b self, _internal_index: u32) -> Result<Option<InternalFunction<'b>>, Error<E>> {
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>, Error<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")
Expand All @@ -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: UserError>(env: Arc<ModuleInstanceInterface<E>>, user_elements: UserDefinedElements<'a, E>) -> Result<NativeModuleInstance<E>, Error<E>> {
NativeModuleInstance::new(env, user_elements)
}

Expand Down
Loading

0 comments on commit 8f1e83e

Please sign in to comment.