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:
parent
eda488233f
commit
367f17989b
23
src/func.rs
23
src/func.rs
|
@ -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()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
18
src/host.rs
18
src/host.rs
|
@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
75
src/lib.rs
75
src/lib.rs
|
@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
367
src/runner.rs
367
src/runner.rs
|
@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)))
|
||||||
}
|
}
|
||||||
|
|
65
src/value.rs
65
src/value.rs
|
@ -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)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue