Refine errors (#36)

* Get rid of Stack error

* Add UnexpectedSignature error and remove Value err

* Publish FuncInstance::invoke

* Rename Trap to TrapKind

* Replace Trap with struct. Enum is now TrapKind

* Fixes

* Update value.rs

* Avoid reversing parameter types iter.

* Add impl From<TrapKind> for Trap

* Remove redundant clone in prepare_function_args.

* Use .into() to convert TrapKind into Trap
This commit is contained in:
Sergey Pepyakin 2018-02-06 14:14:57 +03:00 committed by Nikolay Volf
parent eda488233f
commit 367f17989b
6 changed files with 300 additions and 263 deletions

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 {Trap, 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;
@ -75,7 +75,6 @@ impl fmt::Debug for FuncInstance {
} }
impl FuncInstance { impl FuncInstance {
/// Allocate a function instance for a host function. /// Allocate a function instance for a host function.
/// ///
/// When this function instance will be called by the wasm code, /// When this function instance will be called by the wasm code,
@ -128,20 +127,30 @@ impl FuncInstance {
} }
} }
pub(crate) fn invoke<E: Externals>( /// Invoke this function.
///
/// # Errors
///
/// Returns `Err` if `args` types is not match function [`signature`] or
/// if [`Trap`] at execution time occured.
///
/// [`signature`]: #method.signature
/// [`Trap`]: #enum.Trap.html
pub fn invoke<E: Externals>(
func: &FuncRef, func: &FuncRef,
args: &[RuntimeValue], args: &[RuntimeValue],
externals: &mut E, externals: &mut E,
) -> Result<Option<RuntimeValue>, Trap> { ) -> Result<Option<RuntimeValue>, Trap> {
debug_assert!(check_function_args(func.signature(), &args).is_ok()); check_function_args(func.signature(), &args).map_err(|_| 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);
interpreter.start_execution(func, args) interpreter.start_execution(func, args)
} }
FuncInstanceInternal::Host { ref host_func_index, .. } => { FuncInstanceInternal::Host {
externals.invoke_index(*host_func_index, args.into()) ref host_func_index,
} ..
} => externals.invoke_index(*host_func_index, args.into()),
} }
} }
} }

View File

@ -1,6 +1,6 @@
use std::any::TypeId; use std::any::TypeId;
use value::{RuntimeValue, TryInto}; use value::{RuntimeValue, TryInto};
use {Error, Trap}; 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, Error> where RuntimeValue: TryInto<T, 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(|_| Error::Value("Invalid argument cast".to_owned()))?) Ok(self.nth_value_checked(idx)?.try_into().map_err(|_| 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, Error> { pub fn nth_value_checked(&self, idx: usize) -> Result<RuntimeValue, Trap> {
if self.0.len() <= idx { if self.0.len() <= idx {
return Err(Error::Value("Invalid argument index".to_owned())); return Err(TrapKind::UnexpectedSignature.into());
} }
Ok(self.0[idx]) Ok(self.0[idx])
} }
@ -39,7 +39,7 @@ impl<'a> RuntimeArgs<'a> {
/// # Panics /// # Panics
/// ///
/// Panics if cast is invalid or not enough arguments. /// Panics if cast is invalid or not enough arguments.
pub fn nth<T>(&self, idx: usize) -> T where RuntimeValue: TryInto<T, Error> { pub fn nth<T>(&self, idx: usize) -> T where RuntimeValue: TryInto<T, ::value::Error> {
let value = self.nth_value_checked(idx).expect("Invalid argument index"); let value = self.nth_value_checked(idx).expect("Invalid argument index");
value.try_into().expect("Unexpected argument type") value.try_into().expect("Unexpected argument type")
} }
@ -139,8 +139,8 @@ impl HostError {
/// ) -> Result<Option<RuntimeValue>, Trap> { /// ) -> 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)))
@ -207,7 +207,7 @@ impl Externals for NopExternals {
_index: usize, _index: usize,
_args: RuntimeArgs, _args: RuntimeArgs,
) -> Result<Option<RuntimeValue>, Trap> { ) -> Result<Option<RuntimeValue>, Trap> {
Err(Trap::Unreachable) Err(TrapKind::Unreachable.into())
} }
} }

View File

@ -105,12 +105,34 @@ use std::fmt;
use std::error; use std::error;
use std::collections::HashMap; use std::collections::HashMap;
/// Error type which can happen at execution time. /// 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. /// 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. /// Traps can't be handled by WebAssembly code, but are reported to the embedder.
#[derive(Debug)] #[derive(Debug)]
pub enum Trap { 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.
///
/// See [`Trap`] for details.
///
/// [`Trap`]: struct.Trap.html
#[derive(Debug)]
pub enum TrapKind {
/// Wasm code executed `unreachable` opcode. /// Wasm code executed `unreachable` opcode.
/// ///
/// `unreachable` is a special opcode which always traps upon execution. /// `unreachable` is a special opcode which always traps upon execution.
@ -169,6 +191,12 @@ pub enum Trap {
/// Extensive inlining might also be the cause of stack overflow. /// Extensive inlining might also be the cause of stack overflow.
StackOverflow, StackOverflow,
/// Unexpected signature provided.
///
/// This can happen if [`FuncInstance`] was invoked
/// with mismatching signature.
UnexpectedSignature,
/// Error specified by the host. /// Error specified by the host.
/// ///
/// Typically returned from an implementation of [`Externals`]. /// Typically returned from an implementation of [`Externals`].
@ -193,8 +221,6 @@ pub enum Error {
Memory(String), Memory(String),
/// Global-level error. /// Global-level error.
Global(String), Global(String),
/// Stack-level error.
Stack(String),
/// Value-level error. /// Value-level error.
Value(String), Value(String),
/// Trap. /// Trap.
@ -203,6 +229,27 @@ pub enum 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 {
@ -212,7 +259,6 @@ impl Into<String> for Error {
Error::Table(s) => s, Error::Table(s) => s,
Error::Memory(s) => s, Error::Memory(s) => s,
Error::Global(s) => s, Error::Global(s) => s,
Error::Stack(s) => s,
Error::Value(s) => s, Error::Value(s) => s,
Error::Trap(s) => format!("trap: {:?}", s), Error::Trap(s) => format!("trap: {:?}", s),
Error::Host(e) => format!("user: {}", e), Error::Host(e) => format!("user: {}", e),
@ -229,7 +275,6 @@ impl fmt::Display for Error {
Error::Table(ref s) => write!(f, "Table: {}", s), Error::Table(ref s) => write!(f, "Table: {}", s),
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::Stack(ref s) => write!(f, "Stack: {}", s),
Error::Value(ref s) => write!(f, "Value: {}", s), Error::Value(ref s) => write!(f, "Value: {}", s),
Error::Trap(ref s) => write!(f, "Trap: {:?}", s), Error::Trap(ref s) => write!(f, "Trap: {:?}", s),
Error::Host(ref e) => write!(f, "User: {}", e), Error::Host(ref e) => write!(f, "User: {}", e),
@ -237,8 +282,6 @@ impl fmt::Display for Error {
} }
} }
impl error::Error for Error { impl error::Error for Error {
fn description(&self) -> &str { fn description(&self) -> &str {
match *self { match *self {
@ -248,7 +291,6 @@ impl error::Error for Error {
Error::Table(ref s) => s, Error::Table(ref s) => s,
Error::Memory(ref s) => s, Error::Memory(ref s) => s,
Error::Global(ref s) => s, Error::Global(ref s) => s,
Error::Stack(ref s) => s,
Error::Value(ref s) => s, Error::Value(ref s) => s,
Error::Trap(_) => "Trap", Error::Trap(_) => "Trap",
Error::Host(_) => "Host error", Error::Host(_) => "Host error",
@ -256,7 +298,6 @@ impl error::Error for 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))
@ -265,7 +306,7 @@ impl<U> From<U> for Error where U: host::HostError + Sized {
impl<U> From<U> for Trap 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 {
Trap::Host(Box::new(e)) Trap::new(TrapKind::Host(Box::new(e)))
} }
} }
@ -275,15 +316,15 @@ impl From<Trap> for Error {
} }
} }
impl From<validation::Error> for Error { impl From<TrapKind> for Trap {
fn from(e: validation::Error) -> Error { fn from(e: TrapKind) -> Trap {
Error::Validation(e.to_string()) Trap::new(e)
} }
} }
impl From<::common::stack::Error> for Error { impl From<validation::Error> for Error {
fn from(e: ::common::stack::Error) -> Self { fn from(e: validation::Error) -> Error {
Error::Stack(e.to_string()) Error::Validation(e.to_string())
} }
} }

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, Trap, 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::{
@ -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);
} }
@ -113,7 +113,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
} }
} }
fn do_run_function(&mut self, function_context: &mut FunctionContext, function_body: &[Opcode], function_labels: &HashMap<usize, usize>) -> Result<RunResult, Trap> { fn do_run_function(&mut self, function_context: &mut FunctionContext, function_body: &[Opcode], function_labels: &HashMap<usize, usize>) -> Result<RunResult, TrapKind> {
loop { loop {
let instruction = &function_body[function_context.position]; let instruction = &function_body[function_context.position];
@ -148,15 +148,14 @@ impl<'a, E: Externals> Interpreter<'a, E> {
BlockType::Value(_) => { BlockType::Value(_) => {
let result = function_context let result = function_context
.value_stack_mut() .value_stack_mut()
.pop() .pop();
.expect("Due to validation stack shouldn't be empty");
Some(result) Some(result)
}, },
BlockType::NoResult => None, BlockType::NoResult => None,
})) }))
} }
fn run_instruction(&mut self, context: &mut FunctionContext, labels: &HashMap<usize, usize>, opcode: &Opcode) -> Result<InstructionOutcome, Trap> { fn run_instruction(&mut self, context: &mut FunctionContext, labels: &HashMap<usize, usize>, opcode: &Opcode) -> Result<InstructionOutcome, TrapKind> {
match opcode { match opcode {
&Opcode::Unreachable => self.run_unreachable(context), &Opcode::Unreachable => self.run_unreachable(context),
&Opcode::Nop => self.run_nop(context), &Opcode::Nop => self.run_nop(context),
@ -350,29 +349,28 @@ impl<'a, E: Externals> Interpreter<'a, E> {
} }
} }
fn run_unreachable(&mut self, _context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> { fn run_unreachable(&mut self, _context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
Err(Trap::Unreachable) Err(TrapKind::Unreachable)
} }
fn run_nop(&mut self, _context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> { fn run_nop(&mut self, _context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_block(&mut self, context: &mut FunctionContext, labels: &HashMap<usize, usize>, block_type: BlockType) -> Result<InstructionOutcome, Trap> { fn run_block(&mut self, context: &mut FunctionContext, labels: &HashMap<usize, usize>, block_type: BlockType) -> Result<InstructionOutcome, TrapKind> {
context.push_frame(labels, BlockFrameType::Block, block_type)?; context.push_frame(labels, BlockFrameType::Block, block_type)?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_loop(&mut self, context: &mut FunctionContext, labels: &HashMap<usize, usize>, block_type: BlockType) -> Result<InstructionOutcome, Trap> { fn run_loop(&mut self, context: &mut FunctionContext, labels: &HashMap<usize, usize>, block_type: BlockType) -> Result<InstructionOutcome, TrapKind> {
context.push_frame(labels, BlockFrameType::Loop, block_type)?; context.push_frame(labels, BlockFrameType::Loop, block_type)?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_if(&mut self, context: &mut FunctionContext, labels: &HashMap<usize, usize>, block_type: BlockType) -> Result<InstructionOutcome, Trap> { fn run_if(&mut self, context: &mut FunctionContext, labels: &HashMap<usize, usize>, block_type: BlockType) -> Result<InstructionOutcome, TrapKind> {
let condition: bool = context let condition: bool = context
.value_stack_mut() .value_stack_mut()
.pop_as() .pop_as();
.expect("Due to validation stack top should be I32");
let block_frame_type = if condition { BlockFrameType::IfTrue } else { let block_frame_type = if condition { BlockFrameType::IfTrue } else {
let else_pos = labels[&context.position]; let else_pos = labels[&context.position];
if !labels.contains_key(&else_pos) { if !labels.contains_key(&else_pos) {
@ -388,26 +386,24 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_else(&mut self, context: &mut FunctionContext, labels: &HashMap<usize, usize>) -> Result<InstructionOutcome, Trap> { fn run_else(&mut self, context: &mut FunctionContext, labels: &HashMap<usize, usize>) -> Result<InstructionOutcome, TrapKind> {
let end_pos = labels[&context.position]; let end_pos = labels[&context.position];
context.pop_frame(false)?; context.pop_frame(false)?;
context.position = end_pos; context.position = end_pos;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_end(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> { fn run_end(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
context.pop_frame(false)?; context.pop_frame(false)?;
Ok(InstructionOutcome::End) Ok(InstructionOutcome::End)
} }
fn run_br(&mut self, _context: &mut FunctionContext, label_idx: u32) -> Result<InstructionOutcome, Trap> { fn run_br(&mut self, _context: &mut FunctionContext, label_idx: u32) -> Result<InstructionOutcome, TrapKind> {
Ok(InstructionOutcome::Branch(label_idx as usize)) Ok(InstructionOutcome::Branch(label_idx as usize))
} }
fn run_br_if(&mut self, context: &mut FunctionContext, label_idx: u32) -> Result<InstructionOutcome, Trap> { fn run_br_if(&mut self, context: &mut FunctionContext, label_idx: u32) -> Result<InstructionOutcome, TrapKind> {
let condition = context.value_stack_mut() let condition = context.value_stack_mut().pop_as();
.pop_as()
.expect("Due to validation stack should contain value");
if condition { if condition {
Ok(InstructionOutcome::Branch(label_idx as usize)) Ok(InstructionOutcome::Branch(label_idx as usize))
} else { } else {
@ -415,14 +411,13 @@ impl<'a, E: Externals> Interpreter<'a, E> {
} }
} }
fn run_br_table(&mut self, context: &mut FunctionContext, table: &[u32], default: u32) -> Result<InstructionOutcome, Trap> { fn run_br_table(&mut self, context: &mut FunctionContext, table: &[u32], default: u32) -> Result<InstructionOutcome, TrapKind> {
let index: u32 = context.value_stack_mut() let index: u32 = context.value_stack_mut()
.pop_as() .pop_as();
.expect("Due to validation stack should contain value");
Ok(InstructionOutcome::Branch(table.get(index as usize).cloned().unwrap_or(default) as usize)) Ok(InstructionOutcome::Branch(table.get(index as usize).cloned().unwrap_or(default) as usize))
} }
fn run_return(&mut self, _context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> { fn run_return(&mut self, _context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
Ok(InstructionOutcome::Return) Ok(InstructionOutcome::Return)
} }
@ -430,7 +425,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
&mut self, &mut self,
context: &mut FunctionContext, context: &mut FunctionContext,
func_idx: u32, func_idx: u32,
) -> Result<InstructionOutcome, Trap> { ) -> Result<InstructionOutcome, TrapKind> {
let func = context let func = context
.module() .module()
.func_by_index(func_idx) .func_by_index(func_idx)
@ -442,18 +437,17 @@ impl<'a, E: Externals> Interpreter<'a, E> {
&mut self, &mut self,
context: &mut FunctionContext, context: &mut FunctionContext,
signature_idx: u32, signature_idx: u32,
) -> Result<InstructionOutcome, Trap> { ) -> Result<InstructionOutcome, TrapKind> {
let table_func_idx: u32 = context let table_func_idx: u32 = context
.value_stack_mut() .value_stack_mut()
.pop_as() .pop_as();
.expect("Due to validation stack top should be I32");
let table = context let table = context
.module() .module()
.table_by_index(DEFAULT_TABLE_INDEX) .table_by_index(DEFAULT_TABLE_INDEX)
.expect("Due to validation table should exists"); .expect("Due to validation table should exists");
let func_ref = table.get(table_func_idx) let func_ref = table.get(table_func_idx)
.map_err(|_| Trap::TableAccessOutOfBounds)? .map_err(|_| TrapKind::TableAccessOutOfBounds)?
.ok_or_else(|| Trap::ElemUninitialized)?; .ok_or_else(|| TrapKind::ElemUninitialized)?;
{ {
let actual_function_type = func_ref.signature(); let actual_function_type = func_ref.signature();
@ -463,25 +457,24 @@ impl<'a, E: Externals> Interpreter<'a, E> {
.expect("Due to validation type should exists"); .expect("Due to validation type should exists");
if &*required_function_type != actual_function_type { if &*required_function_type != actual_function_type {
return Err(Trap::ElemSignatureMismatch); return Err(TrapKind::ElemSignatureMismatch);
} }
} }
Ok(InstructionOutcome::ExecuteCall(func_ref)) Ok(InstructionOutcome::ExecuteCall(func_ref))
} }
fn run_drop(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> { fn run_drop(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
let _ = context let _ = context
.value_stack_mut() .value_stack_mut()
.pop(); .pop();
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_select(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> { fn run_select(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
let (left, mid, right) = context let (left, mid, right) = context
.value_stack_mut() .value_stack_mut()
.pop_triple() .pop_triple();
.expect("Due to validation there should be 3 values on stack");
let condition = right let condition = right
.try_into() .try_into()
@ -491,26 +484,24 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_get_local(&mut self, context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Trap> { fn run_get_local(&mut self, context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, TrapKind> {
let val = context.get_local(index as usize); let val = context.get_local(index as usize);
context.value_stack_mut().push(val)?; context.value_stack_mut().push(val)?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_set_local(&mut self, context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Trap> { fn run_set_local(&mut self, context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, TrapKind> {
let arg = context let arg = context
.value_stack_mut() .value_stack_mut()
.pop() .pop();
.expect("Due to vaidation stack should contain value");
context.set_local(index as usize, arg); context.set_local(index as usize, arg);
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_tee_local(&mut self, context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Trap> { fn run_tee_local(&mut self, context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, TrapKind> {
let arg = context let arg = context
.value_stack() .value_stack()
.top() .top()
.expect("Due to vaidation stack should contain value")
.clone(); .clone();
context.set_local(index as usize, arg); context.set_local(index as usize, arg);
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
@ -520,7 +511,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
&mut self, &mut self,
context: &mut FunctionContext, context: &mut FunctionContext,
index: u32, index: u32,
) -> Result<InstructionOutcome, Trap> { ) -> Result<InstructionOutcome, TrapKind> {
let global = context let global = context
.module() .module()
.global_by_index(index) .global_by_index(index)
@ -534,11 +525,10 @@ impl<'a, E: Externals> Interpreter<'a, E> {
&mut self, &mut self,
context: &mut FunctionContext, context: &mut FunctionContext,
index: u32, index: u32,
) -> Result<InstructionOutcome, Trap> { ) -> Result<InstructionOutcome, TrapKind> {
let val = context let val = context
.value_stack_mut() .value_stack_mut()
.pop() .pop();
.expect("Due to vaidation stack should contain value");
let global = context let global = context
.module() .module()
.global_by_index(index) .global_by_index(index)
@ -547,12 +537,11 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_load<T>(&mut self, context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome, Trap> fn run_load<T>(&mut self, context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<T>, T: LittleEndianConvert { where RuntimeValue: From<T>, T: LittleEndianConvert {
let raw_address = context let raw_address = context
.value_stack_mut() .value_stack_mut()
.pop_as() .pop_as();
.expect("Due to vaidation stack should contain value");
let address = let address =
effective_address( effective_address(
offset, offset,
@ -562,19 +551,18 @@ impl<'a, E: Externals> Interpreter<'a, E> {
.memory_by_index(DEFAULT_MEMORY_INDEX) .memory_by_index(DEFAULT_MEMORY_INDEX)
.expect("Due to validation memory should exists"); .expect("Due to validation memory should exists");
let b = m.get(address, mem::size_of::<T>()) let b = m.get(address, mem::size_of::<T>())
.map_err(|_| Trap::MemoryAccessOutOfBounds)?; .map_err(|_| TrapKind::MemoryAccessOutOfBounds)?;
let n = T::from_little_endian(&b) let n = T::from_little_endian(&b)
.expect("Can't fail since buffer length should be size_of::<T>"); .expect("Can't fail since buffer length should be size_of::<T>");
context.value_stack_mut().push(n.into())?; context.value_stack_mut().push(n.into())?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_load_extend<T, U>(&mut self, context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome, Trap> fn run_load_extend<T, U>(&mut self, context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome, TrapKind>
where T: ExtendInto<U>, RuntimeValue: From<U>, T: LittleEndianConvert { where T: ExtendInto<U>, RuntimeValue: From<U>, T: LittleEndianConvert {
let raw_address = context let raw_address = context
.value_stack_mut() .value_stack_mut()
.pop_as() .pop_as();
.expect("Due to vaidation stack should contain value");
let address = let address =
effective_address( effective_address(
offset, offset,
@ -584,7 +572,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
.memory_by_index(DEFAULT_MEMORY_INDEX) .memory_by_index(DEFAULT_MEMORY_INDEX)
.expect("Due to validation memory should exists"); .expect("Due to validation memory should exists");
let b = m.get(address, mem::size_of::<T>()) let b = m.get(address, mem::size_of::<T>())
.map_err(|_| Trap::MemoryAccessOutOfBounds)?; .map_err(|_| TrapKind::MemoryAccessOutOfBounds)?;
let v = T::from_little_endian(&b) let v = T::from_little_endian(&b)
.expect("Can't fail since buffer length should be size_of::<T>"); .expect("Can't fail since buffer length should be size_of::<T>");
let stack_value: U = v.extend_into(); let stack_value: U = v.extend_into();
@ -595,17 +583,15 @@ impl<'a, E: Externals> Interpreter<'a, E> {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_store<T>(&mut self, context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome, Trap> fn run_store<T>(&mut self, context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: TryInto<T, Error>, T: LittleEndianConvert { where RuntimeValue: TryInto<T, ::value::Error>, T: LittleEndianConvert {
let stack_value = context let stack_value = context
.value_stack_mut() .value_stack_mut()
.pop_as::<T>() .pop_as::<T>()
.expect("Due to vaidation stack should contain value")
.into_little_endian(); .into_little_endian();
let raw_address = context let raw_address = context
.value_stack_mut() .value_stack_mut()
.pop_as::<u32>() .pop_as::<u32>();
.expect("Due to validation stack should contain value");
let address = let address =
effective_address( effective_address(
offset, offset,
@ -616,7 +602,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
.memory_by_index(DEFAULT_MEMORY_INDEX) .memory_by_index(DEFAULT_MEMORY_INDEX)
.expect("Due to validation memory should exists"); .expect("Due to validation memory should exists");
m.set(address, &stack_value) m.set(address, &stack_value)
.map_err(|_| Trap::MemoryAccessOutOfBounds)?; .map_err(|_| TrapKind::MemoryAccessOutOfBounds)?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
@ -625,23 +611,21 @@ impl<'a, E: Externals> Interpreter<'a, E> {
context: &mut FunctionContext, context: &mut FunctionContext,
_align: u32, _align: u32,
offset: u32, offset: u32,
) -> Result<InstructionOutcome, Trap> ) -> Result<InstructionOutcome, TrapKind>
where where
RuntimeValue: TryInto<T, Error>, RuntimeValue: TryInto<T, ::value::Error>,
T: WrapInto<U>, T: WrapInto<U>,
U: LittleEndianConvert, U: LittleEndianConvert,
{ {
let stack_value: T = context let stack_value: T = context
.value_stack_mut() .value_stack_mut()
.pop() .pop()
.expect("Due to vaidation stack should contain value")
.try_into() .try_into()
.expect("Due to validation value should be of proper type"); .expect("Due to validation value should be of proper type");
let stack_value = stack_value.wrap_into().into_little_endian(); let stack_value = stack_value.wrap_into().into_little_endian();
let raw_address = context let raw_address = context
.value_stack_mut() .value_stack_mut()
.pop_as::<u32>() .pop_as::<u32>();
.expect("Due to validation stack should contain value");
let address = let address =
effective_address( effective_address(
offset, offset,
@ -651,11 +635,11 @@ impl<'a, E: Externals> Interpreter<'a, E> {
.memory_by_index(DEFAULT_MEMORY_INDEX) .memory_by_index(DEFAULT_MEMORY_INDEX)
.expect("Due to validation memory should exists"); .expect("Due to validation memory should exists");
m.set(address, &stack_value) m.set(address, &stack_value)
.map_err(|_| Trap::MemoryAccessOutOfBounds)?; .map_err(|_| TrapKind::MemoryAccessOutOfBounds)?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_current_memory(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> { fn run_current_memory(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
let m = context.module() let m = context.module()
.memory_by_index(DEFAULT_MEMORY_INDEX) .memory_by_index(DEFAULT_MEMORY_INDEX)
.expect("Due to validation memory should exists"); .expect("Due to validation memory should exists");
@ -666,11 +650,10 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_grow_memory(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> { fn run_grow_memory(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
let pages: u32 = context let pages: u32 = context
.value_stack_mut() .value_stack_mut()
.pop_as() .pop_as();
.expect("Due to validation stack should contain value");
let m = context.module() let m = context.module()
.memory_by_index(DEFAULT_MEMORY_INDEX) .memory_by_index(DEFAULT_MEMORY_INDEX)
.expect("Due to validation memory should exists"); .expect("Due to validation memory should exists");
@ -683,7 +666,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_const(&mut self, context: &mut FunctionContext, val: RuntimeValue) -> Result<InstructionOutcome, Trap> { fn run_const(&mut self, context: &mut FunctionContext, val: RuntimeValue) -> Result<InstructionOutcome, TrapKind> {
context context
.value_stack_mut() .value_stack_mut()
.push(val) .push(val)
@ -691,9 +674,9 @@ impl<'a, E: Externals> Interpreter<'a, E> {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_relop<T, F>(&mut self, context: &mut FunctionContext, f: F) -> Result<InstructionOutcome, Trap> fn run_relop<T, F>(&mut self, context: &mut FunctionContext, f: F) -> Result<InstructionOutcome, TrapKind>
where where
RuntimeValue: TryInto<T, Error>, RuntimeValue: TryInto<T, ::value::Error>,
F: FnOnce(T, T) -> bool, F: FnOnce(T, T) -> bool,
{ {
let (left, right) = context let (left, right) = context
@ -709,79 +692,77 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_eqz<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_eqz<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> + Default { where RuntimeValue: TryInto<T, ::value::Error>, T: PartialEq<T> + Default {
let v = context let v = context
.value_stack_mut() .value_stack_mut()
.pop_as::<T>() .pop_as::<T>();
.expect("Due to vaidation stack should contain value");
let v = RuntimeValue::I32(if v == Default::default() { 1 } else { 0 }); let v = RuntimeValue::I32(if v == Default::default() { 1 } else { 0 });
context.value_stack_mut().push(v)?; context.value_stack_mut().push(v)?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_eq<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_eq<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> where RuntimeValue: TryInto<T, ::value::Error>, T: PartialEq<T>
{ {
self.run_relop(context, |left, right| left == right) self.run_relop(context, |left, right| left == right)
} }
fn run_ne<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_ne<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> { where RuntimeValue: TryInto<T, ::value::Error>, T: PartialEq<T> {
self.run_relop(context, |left, right| left != right) self.run_relop(context, |left, right| left != right)
} }
fn run_lt<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_lt<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> + Display { where RuntimeValue: TryInto<T, ::value::Error>, T: PartialOrd<T> + Display {
self.run_relop(context, |left, right| left < right) self.run_relop(context, |left, right| left < right)
} }
fn run_gt<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_gt<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> { where RuntimeValue: TryInto<T, ::value::Error>, T: PartialOrd<T> {
self.run_relop(context, |left, right| left > right) self.run_relop(context, |left, right| left > right)
} }
fn run_lte<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_lte<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> { where RuntimeValue: TryInto<T, ::value::Error>, T: PartialOrd<T> {
self.run_relop(context, |left, right| left <= right) self.run_relop(context, |left, right| left <= right)
} }
fn run_gte<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_gte<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> { where RuntimeValue: TryInto<T, ::value::Error>, T: PartialOrd<T> {
self.run_relop(context, |left, right| left >= right) self.run_relop(context, |left, right| left >= right)
} }
fn run_unop<T, U, F>(&mut self, context: &mut FunctionContext, f: F) -> Result<InstructionOutcome, Trap> fn run_unop<T, U, F>(&mut self, context: &mut FunctionContext, f: F) -> Result<InstructionOutcome, TrapKind>
where where
F: FnOnce(T) -> U, F: FnOnce(T) -> U,
RuntimeValue: From<U> + TryInto<T, Error> RuntimeValue: From<U> + TryInto<T, ::value::Error>
{ {
let v = context let v = context
.value_stack_mut() .value_stack_mut()
.pop_as::<T>() .pop_as::<T>();
.map(|v| f(v)) let v = f(v);
.expect("Due to vaidation stack should contain value");
context.value_stack_mut().push(v.into())?; context.value_stack_mut().push(v.into())?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_clz<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_clz<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> { where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Integer<T> {
self.run_unop(context, |v| v.leading_zeros()) self.run_unop(context, |v| v.leading_zeros())
} }
fn run_ctz<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_ctz<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> { where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Integer<T> {
self.run_unop(context, |v| v.trailing_zeros()) self.run_unop(context, |v| v.trailing_zeros())
} }
fn run_popcnt<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_popcnt<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> { where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Integer<T> {
self.run_unop(context, |v| v.count_ones()) self.run_unop(context, |v| v.count_ones())
} }
fn run_add<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_add<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> { where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: ArithmeticOps<T> {
let (left, right) = context let (left, right) = context
.value_stack_mut() .value_stack_mut()
.pop_pair_as::<T>() .pop_pair_as::<T>()
@ -791,8 +772,8 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_sub<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_sub<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> { where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: ArithmeticOps<T> {
let (left, right) = context let (left, right) = context
.value_stack_mut() .value_stack_mut()
.pop_pair_as::<T>() .pop_pair_as::<T>()
@ -802,8 +783,8 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_mul<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_mul<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> { where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: ArithmeticOps<T> {
let (left, right) = context let (left, right) = context
.value_stack_mut() .value_stack_mut()
.pop_pair_as::<T>() .pop_pair_as::<T>()
@ -813,8 +794,8 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_div<T, U>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_div<T, U>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U> + Display, U: ArithmeticOps<U> + TransmuteInto<T> { where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: TransmuteInto<U> + Display, U: ArithmeticOps<U> + TransmuteInto<T> {
let (left, right) = context let (left, right) = context
.value_stack_mut() .value_stack_mut()
.pop_pair_as::<T>() .pop_pair_as::<T>()
@ -826,8 +807,8 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_rem<T, U>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_rem<T, U>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U>, U: Integer<U> + TransmuteInto<T> { where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: TransmuteInto<U>, U: Integer<U> + TransmuteInto<T> {
let (left, right) = context let (left, right) = context
.value_stack_mut() .value_stack_mut()
.pop_pair_as::<T>() .pop_pair_as::<T>()
@ -839,8 +820,8 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_and<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_and<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<<T as ops::BitAnd>::Output> + TryInto<T, Error>, T: ops::BitAnd<T> { where RuntimeValue: From<<T as ops::BitAnd>::Output> + TryInto<T, ::value::Error>, T: ops::BitAnd<T> {
let (left, right) = context let (left, right) = context
.value_stack_mut() .value_stack_mut()
.pop_pair_as::<T>() .pop_pair_as::<T>()
@ -850,8 +831,8 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_or<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_or<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<<T as ops::BitOr>::Output> + TryInto<T, Error>, T: ops::BitOr<T> { where RuntimeValue: From<<T as ops::BitOr>::Output> + TryInto<T, ::value::Error>, T: ops::BitOr<T> {
let (left, right) = context let (left, right) = context
.value_stack_mut() .value_stack_mut()
.pop_pair_as::<T>() .pop_pair_as::<T>()
@ -861,8 +842,8 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_xor<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_xor<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<<T as ops::BitXor>::Output> + TryInto<T, Error>, T: ops::BitXor<T> { where RuntimeValue: From<<T as ops::BitXor>::Output> + TryInto<T, ::value::Error>, T: ops::BitXor<T> {
let (left, right) = context let (left, right) = context
.value_stack_mut() .value_stack_mut()
.pop_pair_as::<T>() .pop_pair_as::<T>()
@ -872,8 +853,8 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_shl<T>(&mut self, context: &mut FunctionContext, mask: T) -> Result<InstructionOutcome, Trap> fn run_shl<T>(&mut self, context: &mut FunctionContext, mask: T) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<<T as ops::Shl<T>>::Output> + TryInto<T, Error>, T: ops::Shl<T> + ops::BitAnd<T, Output=T> { where RuntimeValue: From<<T as ops::Shl<T>>::Output> + TryInto<T, ::value::Error>, T: ops::Shl<T> + ops::BitAnd<T, Output=T> {
let (left, right) = context let (left, right) = context
.value_stack_mut() .value_stack_mut()
.pop_pair_as::<T>() .pop_pair_as::<T>()
@ -883,8 +864,8 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_shr<T, U>(&mut self, context: &mut FunctionContext, mask: U) -> Result<InstructionOutcome, Trap> fn run_shr<T, U>(&mut self, context: &mut FunctionContext, mask: U) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U>, U: ops::Shr<U> + ops::BitAnd<U, Output=U>, <U as ops::Shr<U>>::Output: TransmuteInto<T> { where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: TransmuteInto<U>, U: ops::Shr<U> + ops::BitAnd<U, Output=U>, <U as ops::Shr<U>>::Output: TransmuteInto<T> {
let (left, right) = context let (left, right) = context
.value_stack_mut() .value_stack_mut()
.pop_pair_as::<T>() .pop_pair_as::<T>()
@ -896,8 +877,8 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_rotl<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_rotl<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> { where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Integer<T> {
let (left, right) = context let (left, right) = context
.value_stack_mut() .value_stack_mut()
.pop_pair_as::<T>() .pop_pair_as::<T>()
@ -907,8 +888,8 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_rotr<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_rotr<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Integer<T>
{ {
let (left, right) = context let (left, right) = context
.value_stack_mut() .value_stack_mut()
@ -919,52 +900,52 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_abs<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_abs<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Float<T>
{ {
self.run_unop(context, |v| v.abs()) self.run_unop(context, |v| v.abs())
} }
fn run_neg<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_neg<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where where
RuntimeValue: From<<T as ops::Neg>::Output> + TryInto<T, Error>, RuntimeValue: From<<T as ops::Neg>::Output> + TryInto<T, ::value::Error>,
T: ops::Neg T: ops::Neg
{ {
self.run_unop(context, |v| v.neg()) self.run_unop(context, |v| v.neg())
} }
fn run_ceil<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_ceil<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Float<T>
{ {
self.run_unop(context, |v| v.ceil()) self.run_unop(context, |v| v.ceil())
} }
fn run_floor<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_floor<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Float<T>
{ {
self.run_unop(context, |v| v.floor()) self.run_unop(context, |v| v.floor())
} }
fn run_trunc<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_trunc<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Float<T>
{ {
self.run_unop(context, |v| v.trunc()) self.run_unop(context, |v| v.trunc())
} }
fn run_nearest<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_nearest<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Float<T>
{ {
self.run_unop(context, |v| v.nearest()) self.run_unop(context, |v| v.nearest())
} }
fn run_sqrt<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_sqrt<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Float<T>
{ {
self.run_unop(context, |v| v.sqrt()) self.run_unop(context, |v| v.sqrt())
} }
fn run_min<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_min<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Float<T>
{ {
let (left, right) = context let (left, right) = context
.value_stack_mut() .value_stack_mut()
@ -975,8 +956,8 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_max<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_max<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> { where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Float<T> {
let (left, right) = context let (left, right) = context
.value_stack_mut() .value_stack_mut()
.pop_pair_as::<T>() .pop_pair_as::<T>()
@ -986,8 +967,8 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_copysign<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_copysign<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> { where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Float<T> {
let (left, right) = context let (left, right) = context
.value_stack_mut() .value_stack_mut()
.pop_pair_as::<T>() .pop_pair_as::<T>()
@ -997,17 +978,16 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_wrap<T, U>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_wrap<T, U>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<U> + TryInto<T, Error>, T: WrapInto<U> { where RuntimeValue: From<U> + TryInto<T, ::value::Error>, T: WrapInto<U> {
self.run_unop(context, |v| v.wrap_into()) self.run_unop(context, |v| v.wrap_into())
} }
fn run_trunc_to_int<T, U, V>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_trunc_to_int<T, U, V>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<V> + TryInto<T, Error>, T: TryTruncateInto<U, Trap>, U: TransmuteInto<V>, { where RuntimeValue: From<V> + TryInto<T, ::value::Error>, T: TryTruncateInto<U, TrapKind>, U: TransmuteInto<V>, {
let v = context let v = context
.value_stack_mut() .value_stack_mut()
.pop_as::<T>() .pop_as::<T>();
.expect("Due to vaidation stack should contain value");
v.try_truncate_into() v.try_truncate_into()
.map(|v| v.transmute_into()) .map(|v| v.transmute_into())
@ -1015,14 +995,13 @@ impl<'a, E: Externals> Interpreter<'a, E> {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_extend<T, U, V>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_extend<T, U, V>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where where
RuntimeValue: From<V> + TryInto<T, Error>, T: ExtendInto<U>, U: TransmuteInto<V> RuntimeValue: From<V> + TryInto<T, ::value::Error>, T: ExtendInto<U>, U: TransmuteInto<V>
{ {
let v = context let v = context
.value_stack_mut() .value_stack_mut()
.pop_as::<T>() .pop_as::<T>();
.expect("Due to vaidation stack should contain value");
let v = v.extend_into().transmute_into(); let v = v.extend_into().transmute_into();
context.value_stack_mut().push(v.into())?; context.value_stack_mut().push(v.into())?;
@ -1030,14 +1009,13 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_reinterpret<T, U>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> fn run_reinterpret<T, U>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where where
RuntimeValue: From<U>, RuntimeValue: TryInto<T, Error>, T: TransmuteInto<U> RuntimeValue: From<U>, RuntimeValue: TryInto<T, ::value::Error>, T: TransmuteInto<U>
{ {
let v = context let v = context
.value_stack_mut() .value_stack_mut()
.pop_as::<T>() .pop_as::<T>();
.expect("Due to vaidation stack should contain value");
let v = v.transmute_into(); let v = v.transmute_into();
context.value_stack_mut().push(v.into())?; context.value_stack_mut().push(v.into())?;
@ -1083,7 +1061,7 @@ impl FunctionContext {
} }
} }
pub fn nested(&mut self, function: FuncRef) -> Result<Self, Trap> { pub fn nested(&mut self, function: FuncRef) -> Result<Self, TrapKind> {
let (function_locals, module, function_return_type) = { let (function_locals, module, function_return_type) = {
let module = match *function.as_internal() { let module = match *function.as_internal() {
FuncInstanceInternal::Internal { ref module, .. } => module.upgrade().expect("module deallocated"), FuncInstanceInternal::Internal { ref module, .. } => module.upgrade().expect("module deallocated"),
@ -1149,7 +1127,7 @@ impl FunctionContext {
&self.frame_stack &self.frame_stack
} }
pub fn push_frame(&mut self, labels: &HashMap<usize, usize>, frame_type: BlockFrameType, block_type: BlockType) -> Result<(), Trap> { pub fn push_frame(&mut self, labels: &HashMap<usize, usize>, frame_type: BlockFrameType, block_type: BlockType) -> Result<(), TrapKind> {
let begin_position = self.position; let begin_position = self.position;
let branch_position = match frame_type { let branch_position = match frame_type {
BlockFrameType::Function => usize::MAX, BlockFrameType::Function => usize::MAX,
@ -1175,7 +1153,7 @@ impl FunctionContext {
branch_position: branch_position, branch_position: branch_position,
end_position: end_position, end_position: end_position,
value_stack_len: self.value_stack.len(), value_stack_len: self.value_stack.len(),
}).map_err(|_| Trap::StackOverflow)?; }).map_err(|_| TrapKind::StackOverflow)?;
Ok(()) Ok(())
} }
@ -1184,7 +1162,7 @@ impl FunctionContext {
let _ = self.frame_stack.pop().expect("Due to validation frame stack shouldn't be empty"); let _ = self.frame_stack.pop().expect("Due to validation frame stack shouldn't be empty");
} }
pub fn pop_frame(&mut self, is_branch: bool) -> Result<(), Trap> { pub fn pop_frame(&mut self, is_branch: bool) -> Result<(), TrapKind> {
let frame = self.frame_stack let frame = self.frame_stack
.pop() .pop()
.expect("Due to validation frame stack shouldn't be empty"); .expect("Due to validation frame stack shouldn't be empty");
@ -1192,7 +1170,7 @@ impl FunctionContext {
let frame_value = match frame.block_type { let frame_value = match frame.block_type {
BlockType::Value(_) if frame.frame_type != BlockFrameType::Loop || !is_branch => BlockType::Value(_) if frame.frame_type != BlockFrameType::Loop || !is_branch =>
Some(self.value_stack.pop().expect("Due to validation, stack shouldn't be empty")), Some(self.value_stack.pop()),
_ => None, _ => None,
}; };
self.value_stack.resize(frame.value_stack_len); self.value_stack.resize(frame.value_stack_len);
@ -1211,17 +1189,22 @@ impl fmt::Debug for FunctionContext {
} }
} }
fn effective_address(address: u32, offset: u32) -> Result<u32, Trap> { fn effective_address(address: u32, offset: u32) -> Result<u32, TrapKind> {
match offset.checked_add(address) { match offset.checked_add(address) {
None => Err(Trap::MemoryAccessOutOfBounds), None => Err(TrapKind::MemoryAccessOutOfBounds),
Some(address) => Ok(address), Some(address) => Ok(address),
} }
} }
fn prepare_function_args(signature: &Signature, caller_stack: &mut ValueStack) -> Vec<RuntimeValue> { fn prepare_function_args(
let mut args = signature.params().iter().cloned().rev().map(|_| { signature: &Signature,
caller_stack.pop().expect("Due to validation stack shouldn't be empty") caller_stack: &mut ValueStack,
}).collect::<Vec<RuntimeValue>>(); ) -> Vec<RuntimeValue> {
let mut args = signature
.params()
.iter()
.map(|_| caller_stack.pop())
.collect::<Vec<RuntimeValue>>();
args.reverse(); args.reverse();
check_function_args(signature, &args).expect("Due to validation arguments should match"); check_function_args(signature, &args).expect("Due to validation arguments should match");
args args
@ -1262,37 +1245,39 @@ impl ValueStack {
} }
} }
fn pop_as<T>(&mut self) -> Result<T, Error> fn pop_as<T>(&mut self) -> T
where where
RuntimeValue: TryInto<T, Error>, RuntimeValue: TryInto<T, ::value::Error>,
{ {
let value = self.stack_with_limit.pop()?; let value = self.stack_with_limit
TryInto::try_into(value) .pop()
.expect("Due to validation stack shouldn't be empty");
TryInto::try_into(value).expect("Due to validation stack top's type should match")
} }
fn pop_pair_as<T>(&mut self) -> Result<(T, T), Error> fn pop_pair_as<T>(&mut self) -> Result<(T, T), Error>
where where
RuntimeValue: TryInto<T, Error>, RuntimeValue: TryInto<T, ::value::Error>,
{ {
let right = self.pop_as()?; let right = self.pop_as();
let left = self.pop_as()?; let left = self.pop_as();
Ok((left, right)) Ok((left, right))
} }
fn pop_triple(&mut self) -> Result<(RuntimeValue, RuntimeValue, RuntimeValue), Error> { fn pop_triple(&mut self) -> (RuntimeValue, RuntimeValue, RuntimeValue) {
let right = self.stack_with_limit.pop()?; let right = self.stack_with_limit.pop().expect("Due to validation stack shouldn't be empty");
let mid = self.stack_with_limit.pop()?; let mid = self.stack_with_limit.pop().expect("Due to validation stack shouldn't be empty");
let left = self.stack_with_limit.pop()?; let left = self.stack_with_limit.pop().expect("Due to validation stack shouldn't be empty");
Ok((left, mid, right)) (left, mid, right)
} }
fn pop(&mut self) -> Result<RuntimeValue, Error> { fn pop(&mut self) -> RuntimeValue {
self.stack_with_limit.pop().map_err(|e| Error::Stack(e.to_string())) self.stack_with_limit.pop().expect("Due to validation stack shouldn't be empty")
} }
fn push(&mut self, value: RuntimeValue) -> Result<(), Trap> { fn push(&mut self, value: RuntimeValue) -> Result<(), TrapKind> {
self.stack_with_limit.push(value) self.stack_with_limit.push(value)
.map_err(|_| Trap::StackOverflow) .map_err(|_| TrapKind::StackOverflow)
} }
fn resize(&mut self, new_len: usize) { fn resize(&mut self, new_len: usize) {
@ -1307,7 +1292,7 @@ impl ValueStack {
self.stack_with_limit.limit() self.stack_with_limit.limit()
} }
fn top(&self) -> Result<&RuntimeValue, Error> { fn top(&self) -> &RuntimeValue {
self.stack_with_limit.top().map_err(|e| Error::Stack(e.to_string())) self.stack_with_limit.top().expect("Due to validation stack shouldn't be empty")
} }
} }

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, Trap, RuntimeValue, RuntimeArgs, TableDescriptor, MemoryDescriptor, Trap, TrapKind,
}; };
use types::ValueType; use types::ValueType;
use super::parse_wat; use super::parse_wat;
@ -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(Trap::Host(Box::new(error))) Err(TrapKind::Host(Box::new(error)).into())
} }
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(Trap::Host(Box::new(HostErrorWithCode { error_code: 123 }))); return Err(TrapKind::Host(Box::new(HostErrorWithCode { error_code: 123 })).into());
} }
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::Trap(Trap::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);
@ -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(|_| Trap::TableAccessOutOfBounds)?; .map_err(|_| TrapKind::TableAccessOutOfBounds)?;
Ok(Some(RuntimeValue::I32(table_index as i32))) Ok(Some(RuntimeValue::I32(table_index as i32)))
} }

View File

@ -1,9 +1,16 @@
use std::{i32, i64, u32, u64, f32}; use std::{i32, i64, u32, u64, f32};
use std::io; use std::io;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use {Error, Trap};
use parity_wasm::elements::ValueType; use parity_wasm::elements::ValueType;
use TrapKind;
#[derive(Debug)]
pub enum Error {
UnexpectedType {
expected: ValueType,
},
InvalidLittleEndianBuffer,
}
/// Runtime value. /// Runtime value.
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
@ -65,7 +72,7 @@ pub trait ArithmeticOps<T> {
/// Multiply two values. /// Multiply two values.
fn mul(self, other: T) -> T; fn mul(self, other: T) -> T;
/// Divide two values. /// Divide two values.
fn div(self, other: T) -> Result<T, Trap>; fn div(self, other: T) -> Result<T, TrapKind>;
} }
/// Integer value. /// Integer value.
@ -81,7 +88,7 @@ pub trait Integer<T>: ArithmeticOps<T> {
/// Get right bit rotation result. /// Get right bit rotation result.
fn rotr(self, other: T) -> T; fn rotr(self, other: T) -> T;
/// Get division remainder. /// Get division remainder.
fn rem(self, other: T) -> Result<T, Trap>; fn rem(self, other: T) -> Result<T, TrapKind>;
} }
/// Float-point value. /// Float-point value.
@ -180,7 +187,7 @@ impl TryInto<bool, Error> for RuntimeValue {
fn try_into(self) -> Result<bool, Error> { fn try_into(self) -> Result<bool, Error> {
match self { match self {
RuntimeValue::I32(val) => Ok(val != 0), RuntimeValue::I32(val) => Ok(val != 0),
_ => Err(Error::Value("32-bit int value expected".to_owned())), _ => Err(Error::UnexpectedType { expected: ValueType::I32 }),
} }
} }
} }
@ -189,7 +196,7 @@ impl TryInto<i32, Error> for RuntimeValue {
fn try_into(self) -> Result<i32, Error> { fn try_into(self) -> Result<i32, Error> {
match self { match self {
RuntimeValue::I32(val) => Ok(val), RuntimeValue::I32(val) => Ok(val),
_ => Err(Error::Value("32-bit int value expected".to_owned())), _ => Err(Error::UnexpectedType { expected: ValueType::I32 }),
} }
} }
} }
@ -198,7 +205,7 @@ impl TryInto<i64, Error> for RuntimeValue {
fn try_into(self) -> Result<i64, Error> { fn try_into(self) -> Result<i64, Error> {
match self { match self {
RuntimeValue::I64(val) => Ok(val), RuntimeValue::I64(val) => Ok(val),
_ => Err(Error::Value("64-bit int value expected".to_owned())), _ => Err(Error::UnexpectedType { expected: ValueType::I64 }),
} }
} }
} }
@ -207,7 +214,7 @@ impl TryInto<f32, Error> for RuntimeValue {
fn try_into(self) -> Result<f32, Error> { fn try_into(self) -> Result<f32, Error> {
match self { match self {
RuntimeValue::F32(val) => Ok(val), RuntimeValue::F32(val) => Ok(val),
_ => Err(Error::Value("32-bit float value expected".to_owned())), _ => Err(Error::UnexpectedType { expected: ValueType::F32 }),
} }
} }
} }
@ -216,7 +223,7 @@ impl TryInto<f64, Error> for RuntimeValue {
fn try_into(self) -> Result<f64, Error> { fn try_into(self) -> Result<f64, Error> {
match self { match self {
RuntimeValue::F64(val) => Ok(val), RuntimeValue::F64(val) => Ok(val),
_ => Err(Error::Value("64-bit float value expected".to_owned())), _ => Err(Error::UnexpectedType { expected: ValueType::F64 }),
} }
} }
} }
@ -225,7 +232,7 @@ impl TryInto<u32, Error> for RuntimeValue {
fn try_into(self) -> Result<u32, Error> { fn try_into(self) -> Result<u32, Error> {
match self { match self {
RuntimeValue::I32(val) => Ok(val as u32), RuntimeValue::I32(val) => Ok(val as u32),
_ => Err(Error::Value("32-bit int value expected".to_owned())), _ => Err(Error::UnexpectedType { expected: ValueType::I32 }),
} }
} }
} }
@ -234,7 +241,7 @@ impl TryInto<u64, Error> for RuntimeValue {
fn try_into(self) -> Result<u64, Error> { fn try_into(self) -> Result<u64, Error> {
match self { match self {
RuntimeValue::I64(val) => Ok(val as u64), RuntimeValue::I64(val) => Ok(val as u64),
_ => Err(Error::Value("64-bit int value expected".to_owned())), _ => Err(Error::UnexpectedType { expected: ValueType::I64 }),
} }
} }
} }
@ -263,19 +270,19 @@ impl_wrap_into!(f64, f32);
macro_rules! impl_try_truncate_into { macro_rules! impl_try_truncate_into {
($from: ident, $into: ident) => { ($from: ident, $into: ident) => {
impl TryTruncateInto<$into, Trap> for $from { impl TryTruncateInto<$into, TrapKind> for $from {
fn try_truncate_into(self) -> Result<$into, Trap> { fn try_truncate_into(self) -> Result<$into, TrapKind> {
// Casting from a float to an integer will round the float towards zero // Casting from a float to an integer will round the float towards zero
// NOTE: currently this will cause Undefined Behavior if the rounded value cannot be represented by the // NOTE: currently this will cause Undefined Behavior if the rounded value cannot be represented by the
// target integer type. This includes Inf and NaN. This is a bug and will be fixed. // target integer type. This includes Inf and NaN. This is a bug and will be fixed.
if self.is_nan() || self.is_infinite() { if self.is_nan() || self.is_infinite() {
return Err(Trap::InvalidConversionToInt); return Err(TrapKind::InvalidConversionToInt);
} }
// range check // range check
let result = self as $into; let result = self as $into;
if result as $from != self.trunc() { if result as $from != self.trunc() {
return Err(Trap::InvalidConversionToInt); return Err(TrapKind::InvalidConversionToInt);
} }
Ok(self as $into) Ok(self as $into)
@ -379,7 +386,7 @@ impl LittleEndianConvert for i8 {
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> { fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
buffer.get(0) buffer.get(0)
.map(|v| *v as i8) .map(|v| *v as i8)
.ok_or_else(|| Error::Value("invalid little endian buffer".into())) .ok_or_else(|| Error::InvalidLittleEndianBuffer)
} }
} }
@ -391,7 +398,7 @@ impl LittleEndianConvert for u8 {
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> { fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
buffer.get(0) buffer.get(0)
.cloned() .cloned()
.ok_or_else(|| Error::Value("invalid little endian buffer".into())) .ok_or_else(|| Error::InvalidLittleEndianBuffer)
} }
} }
@ -405,7 +412,7 @@ impl LittleEndianConvert for i16 {
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> { fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
io::Cursor::new(buffer).read_i16::<LittleEndian>() io::Cursor::new(buffer).read_i16::<LittleEndian>()
.map_err(|e| Error::Value(e.to_string())) .map_err(|_| Error::InvalidLittleEndianBuffer)
} }
} }
@ -419,7 +426,7 @@ impl LittleEndianConvert for u16 {
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> { fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
io::Cursor::new(buffer).read_u16::<LittleEndian>() io::Cursor::new(buffer).read_u16::<LittleEndian>()
.map_err(|e| Error::Value(e.to_string())) .map_err(|_| Error::InvalidLittleEndianBuffer)
} }
} }
@ -433,7 +440,7 @@ impl LittleEndianConvert for i32 {
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> { fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
io::Cursor::new(buffer).read_i32::<LittleEndian>() io::Cursor::new(buffer).read_i32::<LittleEndian>()
.map_err(|e| Error::Value(e.to_string())) .map_err(|_| Error::InvalidLittleEndianBuffer)
} }
} }
@ -447,7 +454,7 @@ impl LittleEndianConvert for u32 {
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> { fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
io::Cursor::new(buffer).read_u32::<LittleEndian>() io::Cursor::new(buffer).read_u32::<LittleEndian>()
.map_err(|e| Error::Value(e.to_string())) .map_err(|_| Error::InvalidLittleEndianBuffer)
} }
} }
@ -461,7 +468,7 @@ impl LittleEndianConvert for i64 {
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> { fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
io::Cursor::new(buffer).read_i64::<LittleEndian>() io::Cursor::new(buffer).read_i64::<LittleEndian>()
.map_err(|e| Error::Value(e.to_string())) .map_err(|_| Error::InvalidLittleEndianBuffer)
} }
} }
@ -476,7 +483,7 @@ impl LittleEndianConvert for f32 {
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> { fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
io::Cursor::new(buffer).read_u32::<LittleEndian>() io::Cursor::new(buffer).read_u32::<LittleEndian>()
.map(f32_from_bits) .map(f32_from_bits)
.map_err(|e| Error::Value(e.to_string())) .map_err(|_| Error::InvalidLittleEndianBuffer)
} }
} }
@ -491,7 +498,7 @@ impl LittleEndianConvert for f64 {
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> { fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
io::Cursor::new(buffer).read_u64::<LittleEndian>() io::Cursor::new(buffer).read_u64::<LittleEndian>()
.map(f64_from_bits) .map(f64_from_bits)
.map_err(|e| Error::Value(e.to_string())) .map_err(|_| Error::InvalidLittleEndianBuffer)
} }
} }
@ -537,14 +544,14 @@ macro_rules! impl_integer_arithmetic_ops {
fn add(self, other: $type) -> $type { self.wrapping_add(other) } fn add(self, other: $type) -> $type { self.wrapping_add(other) }
fn sub(self, other: $type) -> $type { self.wrapping_sub(other) } fn sub(self, other: $type) -> $type { self.wrapping_sub(other) }
fn mul(self, other: $type) -> $type { self.wrapping_mul(other) } fn mul(self, other: $type) -> $type { self.wrapping_mul(other) }
fn div(self, other: $type) -> Result<$type, Trap> { fn div(self, other: $type) -> Result<$type, TrapKind> {
if other == 0 { if other == 0 {
Err(Trap::DivisionByZero) Err(TrapKind::DivisionByZero)
} }
else { else {
let (result, overflow) = self.overflowing_div(other); let (result, overflow) = self.overflowing_div(other);
if overflow { if overflow {
Err(Trap::InvalidConversionToInt) Err(TrapKind::InvalidConversionToInt)
} else { } else {
Ok(result) Ok(result)
} }
@ -565,7 +572,7 @@ macro_rules! impl_float_arithmetic_ops {
fn add(self, other: $type) -> $type { self + other } fn add(self, other: $type) -> $type { self + other }
fn sub(self, other: $type) -> $type { self - other } fn sub(self, other: $type) -> $type { self - other }
fn mul(self, other: $type) -> $type { self * other } fn mul(self, other: $type) -> $type { self * other }
fn div(self, other: $type) -> Result<$type, Trap> { Ok(self / other) } fn div(self, other: $type) -> Result<$type, TrapKind> { Ok(self / other) }
} }
} }
} }
@ -581,8 +588,8 @@ macro_rules! impl_integer {
fn count_ones(self) -> $type { self.count_ones() as $type } fn count_ones(self) -> $type { self.count_ones() as $type }
fn rotl(self, other: $type) -> $type { self.rotate_left(other as u32) } fn rotl(self, other: $type) -> $type { self.rotate_left(other as u32) }
fn rotr(self, other: $type) -> $type { self.rotate_right(other as u32) } fn rotr(self, other: $type) -> $type { self.rotate_right(other as u32) }
fn rem(self, other: $type) -> Result<$type, Trap> { fn rem(self, other: $type) -> Result<$type, TrapKind> {
if other == 0 { Err(Trap::DivisionByZero) } if other == 0 { Err(TrapKind::DivisionByZero) }
else { Ok(self.wrapping_rem(other)) } else { Ok(self.wrapping_rem(other)) }
} }
} }