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

Custom user errors #80

Merged
merged 4 commits into from
Aug 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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