Replace Trap with struct. Enum is now TrapKind

This commit is contained in:
Sergey Pepyakin 2018-02-05 19:05:08 +03:00
parent daf7d95a65
commit 2b80a98b7f
9 changed files with 94 additions and 58 deletions

View File

@ -8,7 +8,7 @@ use wasmi::{
Error as InterpreterError, ModuleInstance, ModuleRef, Error as InterpreterError, ModuleInstance, ModuleRef,
Externals, RuntimeValue, FuncRef, ModuleImportResolver, Externals, RuntimeValue, FuncRef, ModuleImportResolver,
FuncInstance, HostError, ImportsBuilder, Signature, ValueType, FuncInstance, HostError, ImportsBuilder, Signature, ValueType,
RuntimeArgs, TrapKind, RuntimeArgs, Trap,
}; };
#[derive(Debug)] #[derive(Debug)]
@ -149,7 +149,7 @@ impl<'a> Externals for Runtime<'a> {
&mut self, &mut self,
index: usize, index: usize,
args: RuntimeArgs, args: RuntimeArgs,
) -> Result<Option<RuntimeValue>, TrapKind> { ) -> Result<Option<RuntimeValue>, Trap> {
match index { match index {
SET_FUNC_INDEX => { SET_FUNC_INDEX => {
let idx: i32 = args.nth(0); let idx: i32 = args.nth(0);

View File

@ -13,14 +13,14 @@ use wasmi::{
GlobalInstance, GlobalRef, ImportResolver, ImportsBuilder, GlobalInstance, GlobalRef, ImportResolver, ImportsBuilder,
MemoryInstance, MemoryRef, ModuleImportResolver, ModuleInstance, MemoryInstance, MemoryRef, ModuleImportResolver, ModuleInstance,
ModuleRef, RuntimeValue, TableInstance, TableRef, ValueType, ModuleRef, RuntimeValue, TableInstance, TableRef, ValueType,
Module, Signature, MemoryDescriptor, TrapKind, Module, Signature, MemoryDescriptor, Trap,
TableDescriptor, GlobalDescriptor, FuncInstance, RuntimeArgs, TableDescriptor, GlobalDescriptor, FuncInstance, RuntimeArgs,
}; };
#[derive(Debug)] #[derive(Debug)]
enum Error { enum Error {
Load(String), Load(String),
Start(TrapKind), Start(Trap),
Interpreter(InterpreterError), Interpreter(InterpreterError),
} }
@ -59,7 +59,7 @@ impl Externals for SpecModule {
&mut self, &mut self,
index: usize, index: usize,
args: RuntimeArgs, args: RuntimeArgs,
) -> Result<Option<RuntimeValue>, TrapKind> { ) -> Result<Option<RuntimeValue>, Trap> {
match index { match index {
PRINT_FUNC_INDEX => { PRINT_FUNC_INDEX => {
println!("print: {:?}", args); println!("print: {:?}", args);
@ -495,7 +495,7 @@ pub fn spec(name: &str) {
Err(e) => println!("assert_exhaustion at line {} - success ({:?})", line, e), Err(e) => println!("assert_exhaustion at line {} - success ({:?})", line, e),
} }
} }
&test::Command::AssertTrapKind { &test::Command::AssertTrap {
line, ref action, .. line, ref action, ..
} => { } => {
let result = run_action(&mut spec_driver, action); let result = run_action(&mut spec_driver, action);

View File

@ -49,7 +49,7 @@ pub enum Command {
action: Action, action: Action,
}, },
#[serde(rename = "assert_trap")] #[serde(rename = "assert_trap")]
AssertTrapKind { AssertTrap {
line: u64, line: u64,
action: Action, action: Action,
text: String, text: String,

View File

@ -2,7 +2,7 @@ use std::rc::{Rc, Weak};
use std::fmt; use std::fmt;
use std::collections::HashMap; use std::collections::HashMap;
use parity_wasm::elements::{Local, Opcodes}; use parity_wasm::elements::{Local, Opcodes};
use {TrapKind, Signature}; use {Trap, TrapKind, Signature};
use host::Externals; use host::Externals;
use runner::{check_function_args, Interpreter}; use runner::{check_function_args, Interpreter};
use value::RuntimeValue; use value::RuntimeValue;
@ -140,8 +140,8 @@ impl FuncInstance {
func: &FuncRef, func: &FuncRef,
args: &[RuntimeValue], args: &[RuntimeValue],
externals: &mut E, externals: &mut E,
) -> Result<Option<RuntimeValue>, TrapKind> { ) -> Result<Option<RuntimeValue>, Trap> {
check_function_args(func.signature(), &args).map_err(|_| TrapKind::UnexpectedSignature)?; check_function_args(func.signature(), &args).map_err(|_| Trap::new(TrapKind::UnexpectedSignature))?;
match *func.as_internal() { match *func.as_internal() {
FuncInstanceInternal::Internal { .. } => { FuncInstanceInternal::Internal { .. } => {
let mut interpreter = Interpreter::new(externals); let mut interpreter = Interpreter::new(externals);

View File

@ -1,6 +1,6 @@
use std::any::TypeId; use std::any::TypeId;
use value::{RuntimeValue, TryInto}; use value::{RuntimeValue, TryInto};
use TrapKind; use {TrapKind, Trap};
/// Safe wrapper for list of arguments. /// Safe wrapper for list of arguments.
#[derive(Debug)] #[derive(Debug)]
@ -18,8 +18,8 @@ impl<'a> RuntimeArgs<'a> {
/// # Errors /// # Errors
/// ///
/// Returns `Err` if cast is invalid or not enough arguments. /// Returns `Err` if cast is invalid or not enough arguments.
pub fn nth_checked<T>(&self, idx: usize) -> Result<T, TrapKind> where RuntimeValue: TryInto<T, ::value::Error> { pub fn nth_checked<T>(&self, idx: usize) -> Result<T, Trap> where RuntimeValue: TryInto<T, ::value::Error> {
Ok(self.nth_value_checked(idx)?.try_into().map_err(|_| TrapKind::UnexpectedSignature)?) Ok(self.nth_value_checked(idx)?.try_into().map_err(|_| Trap::new(TrapKind::UnexpectedSignature))?)
} }
/// Extract argument as a [`RuntimeValue`] by index `idx`. /// Extract argument as a [`RuntimeValue`] by index `idx`.
@ -27,9 +27,9 @@ impl<'a> RuntimeArgs<'a> {
/// # Errors /// # Errors
/// ///
/// Returns `Err` if this list has not enough arguments. /// Returns `Err` if this list has not enough arguments.
pub fn nth_value_checked(&self, idx: usize) -> Result<RuntimeValue, TrapKind> { pub fn nth_value_checked(&self, idx: usize) -> Result<RuntimeValue, Trap> {
if self.0.len() <= idx { if self.0.len() <= idx {
return Err(TrapKind::UnexpectedSignature); return Err(Trap::new(TrapKind::UnexpectedSignature));
} }
Ok(self.0[idx]) Ok(self.0[idx])
} }
@ -122,7 +122,7 @@ impl HostError {
/// ```rust /// ```rust
/// use wasmi::{ /// use wasmi::{
/// Externals, RuntimeValue, RuntimeArgs, Error, ModuleImportResolver, /// Externals, RuntimeValue, RuntimeArgs, Error, ModuleImportResolver,
/// FuncRef, ValueType, Signature, FuncInstance, TrapKind, /// FuncRef, ValueType, Signature, FuncInstance, Trap,
/// }; /// };
/// ///
/// struct HostExternals { /// struct HostExternals {
@ -136,11 +136,11 @@ impl HostError {
/// &mut self, /// &mut self,
/// index: usize, /// index: usize,
/// args: RuntimeArgs, /// args: RuntimeArgs,
/// ) -> Result<Option<RuntimeValue>, TrapKind> { /// ) -> Result<Option<RuntimeValue>, Trap> {
/// match index { /// match index {
/// ADD_FUNC_INDEX => { /// ADD_FUNC_INDEX => {
/// let a: u32 = args.nth(0); /// let a: u32 = args.nth_checked(0)?;
/// let b: u32 = args.nth(1); /// let b: u32 = args.nth_checked(1)?;
/// let result = a + b; /// let result = a + b;
/// ///
/// Ok(Some(RuntimeValue::I32(result as i32))) /// Ok(Some(RuntimeValue::I32(result as i32)))
@ -192,7 +192,7 @@ pub trait Externals {
&mut self, &mut self,
index: usize, index: usize,
args: RuntimeArgs, args: RuntimeArgs,
) -> Result<Option<RuntimeValue>, TrapKind>; ) -> Result<Option<RuntimeValue>, Trap>;
} }
/// Implementation of [`Externals`] that just traps on [`invoke_index`]. /// Implementation of [`Externals`] that just traps on [`invoke_index`].
@ -206,8 +206,8 @@ impl Externals for NopExternals {
&mut self, &mut self,
_index: usize, _index: usize,
_args: RuntimeArgs, _args: RuntimeArgs,
) -> Result<Option<RuntimeValue>, TrapKind> { ) -> Result<Option<RuntimeValue>, Trap> {
Err(TrapKind::Unreachable) Err(Trap::new(TrapKind::Unreachable))
} }
} }

View File

@ -105,6 +105,27 @@ use std::fmt;
use std::error; use std::error;
use std::collections::HashMap; use std::collections::HashMap;
/// Error type which can thrown by wasm code or by host environment.
///
/// Under some conditions, wasm execution may produce a `Trap`, which immediately aborts execution.
/// Traps can't be handled by WebAssembly code, but are reported to the embedder.
#[derive(Debug)]
pub struct Trap {
kind: TrapKind,
}
impl Trap {
/// Create new trap.
pub fn new(kind: TrapKind) -> Trap {
Trap { kind }
}
/// Returns kind of this trap.
pub fn kind(&self) -> &TrapKind {
&self.kind
}
}
/// Error type which can thrown by wasm code or by host environment. /// Error type which can thrown by wasm code or by host environment.
/// ///
/// Under some conditions, wasm execution may produce a `TrapKind`, which immediately aborts execution. /// Under some conditions, wasm execution may produce a `TrapKind`, which immediately aborts execution.
@ -201,12 +222,33 @@ pub enum Error {
Global(String), Global(String),
/// Value-level error. /// Value-level error.
Value(String), Value(String),
/// TrapKind. /// Trap.
TrapKind(TrapKind), Trap(Trap),
/// Custom embedder error. /// Custom embedder error.
Host(Box<host::HostError>), Host(Box<host::HostError>),
} }
impl Error {
/// Returns [`HostError`] if this `Error` represents some host error.
///
/// I.e. if this error have variant [`Host`] or [`Trap`][`Trap`] with [host][`TrapKind::Host`] error.
///
/// [`HostError`]: trait.HostError.html
/// [`Host`]: enum.Error.html#variant.Host
/// [`Trap`]: enum.Error.html#variant.Trap
/// [`TrapKind::Host`]: enum.TrapKind.html#variant.Host
pub fn as_host_error(&self) -> Option<&host::HostError> {
match *self {
Error::Host(ref host_err) => Some(&**host_err),
Error::Trap(ref trap) => match *trap.kind() {
TrapKind::Host(ref host_err) => Some(&**host_err),
_ => None,
}
_ => None,
}
}
}
impl Into<String> for Error { impl Into<String> for Error {
fn into(self) -> String { fn into(self) -> String {
match self { match self {
@ -217,7 +259,7 @@ impl Into<String> for Error {
Error::Memory(s) => s, Error::Memory(s) => s,
Error::Global(s) => s, Error::Global(s) => s,
Error::Value(s) => s, Error::Value(s) => s,
Error::TrapKind(s) => format!("trap: {:?}", s), Error::Trap(s) => format!("trap: {:?}", s),
Error::Host(e) => format!("user: {}", e), Error::Host(e) => format!("user: {}", e),
} }
} }
@ -233,7 +275,7 @@ impl fmt::Display for Error {
Error::Memory(ref s) => write!(f, "Memory: {}", s), Error::Memory(ref s) => write!(f, "Memory: {}", s),
Error::Global(ref s) => write!(f, "Global: {}", s), Error::Global(ref s) => write!(f, "Global: {}", s),
Error::Value(ref s) => write!(f, "Value: {}", s), Error::Value(ref s) => write!(f, "Value: {}", s),
Error::TrapKind(ref s) => write!(f, "TrapKind: {:?}", s), Error::Trap(ref s) => write!(f, "TrapKind: {:?}", s),
Error::Host(ref e) => write!(f, "User: {}", e), Error::Host(ref e) => write!(f, "User: {}", e),
} }
} }
@ -249,28 +291,27 @@ impl error::Error for Error {
Error::Memory(ref s) => s, Error::Memory(ref s) => s,
Error::Global(ref s) => s, Error::Global(ref s) => s,
Error::Value(ref s) => s, Error::Value(ref s) => s,
Error::TrapKind(_) => "TrapKind", Error::Trap(_) => "TrapKind",
Error::Host(_) => "Host error", Error::Host(_) => "Host error",
} }
} }
} }
impl<U> From<U> for Error where U: host::HostError + Sized { impl<U> From<U> for Error where U: host::HostError + Sized {
fn from(e: U) -> Self { fn from(e: U) -> Self {
Error::Host(Box::new(e)) Error::Host(Box::new(e))
} }
} }
impl<U> From<U> for TrapKind where U: host::HostError + Sized { impl<U> From<U> for Trap where U: host::HostError + Sized {
fn from(e: U) -> Self { fn from(e: U) -> Self {
TrapKind::Host(Box::new(e)) Trap::new(TrapKind::Host(Box::new(e)))
} }
} }
impl From<TrapKind> for Error { impl From<Trap> for Error {
fn from(e: TrapKind) -> Error { fn from(e: Trap) -> Error {
Error::TrapKind(e) Error::Trap(e)
} }
} }

View File

@ -1,5 +1,5 @@
use runner::check_function_args; use runner::check_function_args;
use TrapKind; use Trap;
use std::rc::Rc; use std::rc::Rc;
use std::cell::RefCell; use std::cell::RefCell;
use std::fmt; use std::fmt;
@ -594,7 +594,7 @@ impl ModuleInstance {
check_function_args(func_instance.signature(), &args)?; check_function_args(func_instance.signature(), &args)?;
FuncInstance::invoke(&func_instance, args, externals) FuncInstance::invoke(&func_instance, args, externals)
.map_err(|t| Error::TrapKind(t)) .map_err(|t| Error::Trap(t))
} }
/// Find export by a name. /// Find export by a name.
@ -647,7 +647,7 @@ impl<'a> NotStartedModuleRef<'a> {
/// # Errors /// # Errors
/// ///
/// Returns `Err` if start function traps. /// Returns `Err` if start function traps.
pub fn run_start<E: Externals>(self, state: &mut E) -> Result<ModuleRef, TrapKind> { pub fn run_start<E: Externals>(self, state: &mut E) -> Result<ModuleRef, Trap> {
if let Some(start_fn_idx) = self.loaded_module.module().start_section() { if let Some(start_fn_idx) = self.loaded_module.module().start_section() {
let start_func = self.instance.func_by_index(start_fn_idx).expect( let start_func = self.instance.func_by_index(start_fn_idx).expect(
"Due to validation start function should exists", "Due to validation start function should exists",

View File

@ -5,7 +5,7 @@ use std::fmt::{self, Display};
use std::iter::repeat; use std::iter::repeat;
use std::collections::{HashMap, VecDeque}; use std::collections::{HashMap, VecDeque};
use parity_wasm::elements::{Opcode, BlockType, Local}; use parity_wasm::elements::{Opcode, BlockType, Local};
use {Error, TrapKind, Signature}; use {Error, Trap, TrapKind, Signature};
use module::ModuleRef; use module::ModuleRef;
use func::{FuncRef, FuncInstance, FuncInstanceInternal}; use func::{FuncRef, FuncInstance, FuncInstanceInternal};
use value::{ use value::{
@ -51,7 +51,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
} }
} }
pub fn start_execution(&mut self, func: &FuncRef, args: &[RuntimeValue]) -> Result<Option<RuntimeValue>, TrapKind> { pub fn start_execution(&mut self, func: &FuncRef, args: &[RuntimeValue]) -> Result<Option<RuntimeValue>, Trap> {
let context = FunctionContext::new( let context = FunctionContext::new(
func.clone(), func.clone(),
DEFAULT_VALUE_STACK_LIMIT, DEFAULT_VALUE_STACK_LIMIT,
@ -66,7 +66,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
self.run_interpreter_loop(&mut function_stack) self.run_interpreter_loop(&mut function_stack)
} }
fn run_interpreter_loop(&mut self, function_stack: &mut VecDeque<FunctionContext>) -> Result<Option<RuntimeValue>, TrapKind> { fn run_interpreter_loop(&mut self, function_stack: &mut VecDeque<FunctionContext>) -> Result<Option<RuntimeValue>, Trap> {
loop { loop {
let mut function_context = function_stack.pop_back().expect("on loop entry - not empty; on loop continue - checking for emptiness; qed"); let mut function_context = function_stack.pop_back().expect("on loop entry - not empty; on loop continue - checking for emptiness; qed");
let function_ref = function_context.function.clone(); let function_ref = function_context.function.clone();
@ -78,16 +78,16 @@ impl<'a, E: Externals> Interpreter<'a, E> {
if !function_context.is_initialized() { if !function_context.is_initialized() {
let return_type = function_context.return_type; let return_type = function_context.return_type;
function_context.initialize(&function_body.locals); function_context.initialize(&function_body.locals);
function_context.push_frame(&function_body.labels, BlockFrameType::Function, return_type)?; function_context.push_frame(&function_body.labels, BlockFrameType::Function, return_type).map_err(Trap::new)?;
} }
let function_return = self.do_run_function(&mut function_context, function_body.opcodes.elements(), &function_body.labels)?; let function_return = self.do_run_function(&mut function_context, function_body.opcodes.elements(), &function_body.labels).map_err(Trap::new)?;
match function_return { match function_return {
RunResult::Return(return_value) => { RunResult::Return(return_value) => {
match function_stack.back_mut() { match function_stack.back_mut() {
Some(caller_context) => if let Some(return_value) = return_value { Some(caller_context) => if let Some(return_value) = return_value {
caller_context.value_stack_mut().push(return_value)?; caller_context.value_stack_mut().push(return_value).map_err(Trap::new)?;
}, },
None => return Ok(return_value), None => return Ok(return_value),
} }
@ -95,7 +95,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
RunResult::NestedCall(nested_func) => { RunResult::NestedCall(nested_func) => {
match *nested_func.as_internal() { match *nested_func.as_internal() {
FuncInstanceInternal::Internal { .. } => { FuncInstanceInternal::Internal { .. } => {
let nested_context = function_context.nested(nested_func.clone())?; let nested_context = function_context.nested(nested_func.clone()).map_err(Trap::new)?;
function_stack.push_back(function_context); function_stack.push_back(function_context);
function_stack.push_back(nested_context); function_stack.push_back(nested_context);
}, },
@ -103,7 +103,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
let args = prepare_function_args(signature, &mut function_context.value_stack); let args = prepare_function_args(signature, &mut function_context.value_stack);
let return_val = FuncInstance::invoke(&nested_func, &args, self.externals)?; let return_val = FuncInstance::invoke(&nested_func, &args, self.externals)?;
if let Some(return_val) = return_val { if let Some(return_val) = return_val {
function_context.value_stack_mut().push(return_val)?; function_context.value_stack_mut().push(return_val).map_err(Trap::new)?;
} }
function_stack.push_back(function_context); function_stack.push_back(function_context);
} }

View File

@ -1,7 +1,7 @@
use { use {
Error, Signature, Externals, FuncInstance, FuncRef, HostError, ImportsBuilder, Error, Signature, Externals, FuncInstance, FuncRef, HostError, ImportsBuilder,
MemoryInstance, MemoryRef, TableInstance, TableRef, ModuleImportResolver, ModuleInstance, ModuleRef, MemoryInstance, MemoryRef, TableInstance, TableRef, ModuleImportResolver, ModuleInstance, ModuleRef,
RuntimeValue, RuntimeArgs, TableDescriptor, MemoryDescriptor, TrapKind, RuntimeValue, RuntimeArgs, TableDescriptor, MemoryDescriptor, Trap, TrapKind,
}; };
use types::ValueType; use types::ValueType;
use super::parse_wat; use super::parse_wat;
@ -79,7 +79,7 @@ impl Externals for TestHost {
&mut self, &mut self,
index: usize, index: usize,
args: RuntimeArgs, args: RuntimeArgs,
) -> Result<Option<RuntimeValue>, TrapKind> { ) -> Result<Option<RuntimeValue>, Trap> {
match index { match index {
SUB_FUNC_INDEX => { SUB_FUNC_INDEX => {
let a: i32 = args.nth(0); let a: i32 = args.nth(0);
@ -92,7 +92,7 @@ impl Externals for TestHost {
ERR_FUNC_INDEX => { ERR_FUNC_INDEX => {
let error_code: u32 = args.nth(0); let error_code: u32 = args.nth(0);
let error = HostErrorWithCode { error_code }; let error = HostErrorWithCode { error_code };
Err(TrapKind::Host(Box::new(error))) Err(Trap::new(TrapKind::Host(Box::new(error))))
} }
INC_MEM_FUNC_INDEX => { INC_MEM_FUNC_INDEX => {
let ptr: u32 = args.nth(0); let ptr: u32 = args.nth(0);
@ -131,7 +131,7 @@ impl Externals for TestHost {
.expect("expected to be Some"); .expect("expected to be Some");
if val.value_type() != result.value_type() { if val.value_type() != result.value_type() {
return Err(TrapKind::Host(Box::new(HostErrorWithCode { error_code: 123 }))); return Err(Trap::new(TrapKind::Host(Box::new(HostErrorWithCode { error_code: 123 }))));
} }
Ok(Some(result)) Ok(Some(result))
} }
@ -257,12 +257,7 @@ fn host_err() {
"`test` expected to return error", "`test` expected to return error",
); );
let host_error: Box<HostError> = match error { let error_with_code = error.as_host_error().expect("Expected host error").downcast_ref::<HostErrorWithCode>().expect(
Error::TrapKind(TrapKind::Host(err)) => err,
err => panic!("Unexpected error {:?}", err),
};
let error_with_code = host_error.downcast_ref::<HostErrorWithCode>().expect(
"Failed to downcast to expected error type", "Failed to downcast to expected error type",
); );
assert_eq!(error_with_code.error_code, 228); assert_eq!(error_with_code.error_code, 228);
@ -459,7 +454,7 @@ fn defer_providing_externals() {
&mut self, &mut self,
index: usize, index: usize,
args: RuntimeArgs, args: RuntimeArgs,
) -> Result<Option<RuntimeValue>, TrapKind> { ) -> Result<Option<RuntimeValue>, Trap> {
match index { match index {
INC_FUNC_INDEX => { INC_FUNC_INDEX => {
let a = args.nth::<u32>(0); let a = args.nth::<u32>(0);
@ -523,7 +518,7 @@ fn two_envs_one_externals() {
&mut self, &mut self,
index: usize, index: usize,
_args: RuntimeArgs, _args: RuntimeArgs,
) -> Result<Option<RuntimeValue>, TrapKind> { ) -> Result<Option<RuntimeValue>, Trap> {
match index { match index {
PRIVILEGED_FUNC_INDEX => { PRIVILEGED_FUNC_INDEX => {
println!("privileged!"); println!("privileged!");
@ -643,7 +638,7 @@ fn dynamically_add_host_func() {
&mut self, &mut self,
index: usize, index: usize,
_args: RuntimeArgs, _args: RuntimeArgs,
) -> Result<Option<RuntimeValue>, TrapKind> { ) -> Result<Option<RuntimeValue>, Trap> {
match index { match index {
ADD_FUNC_FUNC_INDEX => { ADD_FUNC_FUNC_INDEX => {
// Allocate indicies for the new function. // Allocate indicies for the new function.
@ -657,7 +652,7 @@ fn dynamically_add_host_func() {
host_func_index as usize, host_func_index as usize,
); );
self.table.set(table_index, Some(added_func)) self.table.set(table_index, Some(added_func))
.map_err(|_| TrapKind::TableAccessOutOfBounds)?; .map_err(|_| Trap::new(TrapKind::TableAccessOutOfBounds))?;
Ok(Some(RuntimeValue::I32(table_index as i32))) Ok(Some(RuntimeValue::I32(table_index as i32)))
} }