Traps in execution

This commit is contained in:
Sergey Pepyakin 2018-01-31 18:32:06 +03:00
parent 6147ad0a2e
commit 9c156890e4
7 changed files with 182 additions and 160 deletions

View File

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

View File

@ -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 {Error, Signature}; use {Trap, 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;
@ -132,10 +132,10 @@ impl FuncInstance {
func: &FuncRef, func: &FuncRef,
args: &[RuntimeValue], args: &[RuntimeValue],
externals: &mut E, externals: &mut E,
) -> Result<Option<RuntimeValue>, Error> { ) -> Result<Option<RuntimeValue>, Trap> {
debug_assert!(check_function_args(func.signature(), &args).is_ok());
match *func.as_internal() { match *func.as_internal() {
FuncInstanceInternal::Internal { ref signature, .. } => { FuncInstanceInternal::Internal { .. } => {
check_function_args(signature, &args)?;
let mut interpreter = Interpreter::new(externals); let mut interpreter = Interpreter::new(externals);
interpreter.start_execution(func, args) interpreter.start_execution(func, args)
} }

View File

@ -173,7 +173,7 @@ pub trait Externals {
&mut self, &mut self,
index: usize, index: usize,
args: RuntimeArgs, args: RuntimeArgs,
) -> Result<Option<RuntimeValue>, Error>; ) -> Result<Option<RuntimeValue>, Trap>;
} }
/// Implementation of [`Externals`] that just traps on [`invoke_index`]. /// Implementation of [`Externals`] that just traps on [`invoke_index`].
@ -187,8 +187,8 @@ impl Externals for NopExternals {
&mut self, &mut self,
_index: usize, _index: usize,
_args: RuntimeArgs, _args: RuntimeArgs,
) -> Result<Option<RuntimeValue>, Error> { ) -> Result<Option<RuntimeValue>, Trap> {
Err(Error::Trap(Trap::Unreachable)) Err(Trap::Unreachable)
} }
} }

View File

@ -115,6 +115,7 @@ pub enum Trap {
ElemSignatureMismatch, ElemSignatureMismatch,
DivisionByZero, DivisionByZero,
InvalidConversionToInt, InvalidConversionToInt,
StackOverflow,
} }
/// Internal interpreter error. /// Internal interpreter error.

View File

@ -1,3 +1,4 @@
use Trap;
use std::rc::Rc; use std::rc::Rc;
use std::cell::RefCell; use std::cell::RefCell;
use std::fmt; use std::fmt;
@ -575,7 +576,7 @@ impl ModuleInstance {
} }
}; };
FuncInstance::invoke(&func_instance, args, externals) FuncInstance::invoke(&func_instance, args, externals).map_err(|t| Error::Trap(t))
} }
/// Find export by a name. /// Find export by a name.
@ -608,7 +609,7 @@ impl<'a> NotStartedModuleRef<'a> {
&self.instance &self.instance
} }
pub fn run_start<E: Externals>(self, state: &mut E) -> Result<ModuleRef, Error> { pub fn run_start<E: Externals>(self, state: &mut E) -> Result<ModuleRef, Trap> {
if let Some(start_fn_idx) = self.loaded_module.module().start_section() { if let Some(start_fn_idx) = self.loaded_module.module().start_section() {
let start_func = self.instance.func_by_index(start_fn_idx).expect( let start_func = self.instance.func_by_index(start_fn_idx).expect(
"Due to validation start function should exists", "Due to validation start function should exists",

View File

@ -51,7 +51,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
} }
} }
pub fn start_execution(&mut self, func: &FuncRef, args: &[RuntimeValue]) -> Result<Option<RuntimeValue>, Error> { pub fn start_execution(&mut self, func: &FuncRef, args: &[RuntimeValue]) -> Result<Option<RuntimeValue>, Trap> {
let context = FunctionContext::new( let context = FunctionContext::new(
func.clone(), func.clone(),
DEFAULT_VALUE_STACK_LIMIT, DEFAULT_VALUE_STACK_LIMIT,
@ -59,13 +59,14 @@ impl<'a, E: Externals> Interpreter<'a, E> {
func.signature(), func.signature(),
args.into_iter().cloned().collect(), args.into_iter().cloned().collect(),
); );
self.run_function(context)
let mut function_stack = VecDeque::new();
function_stack.push_back(context);
self.run_interpreter_loop(&mut function_stack)
} }
fn run_function(&mut self, function_context: FunctionContext) -> Result<Option<RuntimeValue>, Error> { fn run_interpreter_loop(&mut self, function_stack: &mut VecDeque<FunctionContext>) -> Result<Option<RuntimeValue>, Trap> {
let mut function_stack = VecDeque::new();
function_stack.push_back(function_context);
loop { loop {
let mut function_context = function_stack.pop_back().expect("on loop entry - not empty; on loop continue - checking for emptiness; qed"); let mut function_context = function_stack.pop_back().expect("on loop entry - not empty; on loop continue - checking for emptiness; qed");
let function_ref = function_context.function.clone(); let function_ref = function_context.function.clone();
@ -99,7 +100,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
function_stack.push_back(nested_context); function_stack.push_back(nested_context);
}, },
FuncInstanceInternal::Host { ref signature, .. } => { FuncInstanceInternal::Host { ref signature, .. } => {
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)?;
@ -112,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, Error> { fn do_run_function(&mut self, function_context: &mut FunctionContext, function_body: &[Opcode], function_labels: &HashMap<usize, usize>) -> Result<RunResult, Trap> {
loop { loop {
let instruction = &function_body[function_context.position]; let instruction = &function_body[function_context.position];
@ -121,7 +122,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
InstructionOutcome::Branch(mut index) => { InstructionOutcome::Branch(mut index) => {
// discard index - 1 blocks // discard index - 1 blocks
while index >= 1 { while index >= 1 {
function_context.discard_frame()?; function_context.discard_frame();
index -= 1; index -= 1;
} }
@ -144,12 +145,18 @@ impl<'a, E: Externals> Interpreter<'a, E> {
} }
Ok(RunResult::Return(match function_context.return_type { Ok(RunResult::Return(match function_context.return_type {
BlockType::Value(_) => Some(function_context.value_stack_mut().pop()?), BlockType::Value(_) => {
let result = function_context
.value_stack_mut()
.pop()
.expect("Due to validation stack shouldn't be empty");
Some(result)
},
BlockType::NoResult => None, BlockType::NoResult => None,
})) }))
} }
fn run_instruction(&mut self, context: &mut FunctionContext, labels: &HashMap<usize, usize>, opcode: &Opcode) -> Result<InstructionOutcome, Error> { fn run_instruction(&mut self, context: &mut FunctionContext, labels: &HashMap<usize, usize>, opcode: &Opcode) -> Result<InstructionOutcome, Trap> {
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),
@ -343,25 +350,25 @@ impl<'a, E: Externals> Interpreter<'a, E> {
} }
} }
fn run_unreachable(&mut self, _context: &mut FunctionContext) -> Result<InstructionOutcome, Error> { fn run_unreachable(&mut self, _context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> {
Err(Error::Trap(Trap::Unreachable)) Err(Trap::Unreachable)
} }
fn run_nop(&mut self, _context: &mut FunctionContext) -> Result<InstructionOutcome, Error> { fn run_nop(&mut self, _context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_block(&mut self, context: &mut FunctionContext, labels: &HashMap<usize, usize>, block_type: BlockType) -> Result<InstructionOutcome, Error> { fn run_block(&mut self, context: &mut FunctionContext, labels: &HashMap<usize, usize>, block_type: BlockType) -> Result<InstructionOutcome, Trap> {
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, Error> { fn run_loop(&mut self, context: &mut FunctionContext, labels: &HashMap<usize, usize>, block_type: BlockType) -> Result<InstructionOutcome, Trap> {
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, Error> { fn run_if(&mut self, context: &mut FunctionContext, labels: &HashMap<usize, usize>, block_type: BlockType) -> Result<InstructionOutcome, Trap> {
let condition: bool = context let condition: bool = context
.value_stack_mut() .value_stack_mut()
.pop_as() .pop_as()
@ -376,39 +383,46 @@ impl<'a, E: Externals> Interpreter<'a, E> {
context.position = else_pos; context.position = else_pos;
BlockFrameType::IfFalse BlockFrameType::IfFalse
}; };
context.push_frame(labels, block_frame_type, block_type).map(|_| InstructionOutcome::RunNextInstruction) context.push_frame(labels, block_frame_type, block_type)?;
Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_else(&mut self, context: &mut FunctionContext, labels: &HashMap<usize, usize>) -> Result<InstructionOutcome, Error> { fn run_else(&mut self, context: &mut FunctionContext, labels: &HashMap<usize, usize>) -> Result<InstructionOutcome, Trap> {
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, Error> { fn run_end(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> {
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, Error> { fn run_br(&mut self, _context: &mut FunctionContext, label_idx: u32) -> Result<InstructionOutcome, Trap> {
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, Error> { fn run_br_if(&mut self, context: &mut FunctionContext, label_idx: u32) -> Result<InstructionOutcome, Trap> {
if context.value_stack_mut().pop_as()? { let condition = context.value_stack_mut()
.pop_as()
.expect("Due to validation stack should contain value");
if condition {
Ok(InstructionOutcome::Branch(label_idx as usize)) Ok(InstructionOutcome::Branch(label_idx as usize))
} else { } else {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
} }
fn run_br_table(&mut self, context: &mut FunctionContext, table: &[u32], default: u32) -> Result<InstructionOutcome, Error> { fn run_br_table(&mut self, context: &mut FunctionContext, table: &[u32], default: u32) -> Result<InstructionOutcome, Trap> {
let index: u32 = context.value_stack_mut().pop_as()?; let index: u32 = context.value_stack_mut()
.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, Error> { fn run_return(&mut self, _context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> {
Ok(InstructionOutcome::Return) Ok(InstructionOutcome::Return)
} }
@ -416,7 +430,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, Error> { ) -> Result<InstructionOutcome, Trap> {
let func = context let func = context
.module() .module()
.func_by_index(func_idx) .func_by_index(func_idx)
@ -428,7 +442,7 @@ 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, Error> { ) -> Result<InstructionOutcome, Trap> {
let table_func_idx: u32 = context let table_func_idx: u32 = context
.value_stack_mut() .value_stack_mut()
.pop_as() .pop_as()
@ -438,8 +452,8 @@ impl<'a, E: Externals> Interpreter<'a, E> {
.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(|_| Error::Trap(Trap::TableAccessOutOfBounds))? .map_err(|_| Trap::TableAccessOutOfBounds)?
.ok_or_else(|| Error::Trap(Trap::ElemUninitialized))?; .ok_or_else(|| Trap::ElemUninitialized)?;
{ {
let actual_function_type = func_ref.signature(); let actual_function_type = func_ref.signature();
@ -449,43 +463,41 @@ 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(Error::Trap(Trap::ElemSignatureMismatch)); return Err(Trap::ElemSignatureMismatch);
} }
} }
Ok(InstructionOutcome::ExecuteCall(func_ref)) Ok(InstructionOutcome::ExecuteCall(func_ref))
} }
fn run_drop(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Error> { fn run_drop(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> {
context let _ = context
.value_stack_mut() .value_stack_mut()
.pop() .pop();
.map_err(Into::into)
.map(|_| InstructionOutcome::RunNextInstruction)
}
fn run_select(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Error> {
context
.value_stack_mut()
.pop_triple()
.and_then(|(left, mid, right)| {
let condition = right
.try_into()
.expect("Due to validation stack top should be I32");
Ok((left, mid, condition))
})
.map(|(left, mid, condition)| if condition { left } else { mid })
.map(|val| context.value_stack_mut().push(val))
.map(|_| InstructionOutcome::RunNextInstruction)
}
fn run_get_local(&mut self, context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Error> {
let value = context.get_local(index as usize);
context.value_stack_mut().push(value)?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_set_local(&mut self, context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Error> { fn run_select(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> {
let (left, mid, right) = context
.value_stack_mut()
.pop_triple()
.expect("Due to validation there should be 3 values on stack");
let condition = right
.try_into()
.expect("Due to validation stack top should be I32");
let val = if condition { left } else { mid };
context.value_stack_mut().push(val)?;
Ok(InstructionOutcome::RunNextInstruction)
}
fn run_get_local(&mut self, context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Trap> {
let val = context.get_local(index as usize);
context.value_stack_mut().push(val)?;
Ok(InstructionOutcome::RunNextInstruction)
}
fn run_set_local(&mut self, context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Trap> {
let arg = context let arg = context
.value_stack_mut() .value_stack_mut()
.pop() .pop()
@ -494,7 +506,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_tee_local(&mut self, context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Error> { fn run_tee_local(&mut self, context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Trap> {
let arg = context let arg = context
.value_stack() .value_stack()
.top() .top()
@ -508,7 +520,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
&mut self, &mut self,
context: &mut FunctionContext, context: &mut FunctionContext,
index: u32, index: u32,
) -> Result<InstructionOutcome, Error> { ) -> Result<InstructionOutcome, Trap> {
let global = context let global = context
.module() .module()
.global_by_index(index) .global_by_index(index)
@ -522,7 +534,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
&mut self, &mut self,
context: &mut FunctionContext, context: &mut FunctionContext,
index: u32, index: u32,
) -> Result<InstructionOutcome, Error> { ) -> Result<InstructionOutcome, Trap> {
let val = context let val = context
.value_stack_mut() .value_stack_mut()
.pop() .pop()
@ -535,7 +547,7 @@ 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, Error> fn run_load<T>(&mut self, context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome, Trap>
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()
@ -545,20 +557,19 @@ impl<'a, E: Externals> Interpreter<'a, E> {
effective_address( effective_address(
offset, offset,
raw_address, raw_address,
) )?;
.map_err(Error::Trap)?;
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");
let b = m.get(address, mem::size_of::<T>()) let b = m.get(address, mem::size_of::<T>())
.map_err(|_| Error::Trap(Trap::MemoryAccessOutOfBounds))?; .map_err(|_| Trap::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, Error> fn run_load_extend<T, U>(&mut self, context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome, Trap>
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()
@ -568,13 +579,12 @@ impl<'a, E: Externals> Interpreter<'a, E> {
effective_address( effective_address(
offset, offset,
raw_address, raw_address,
) )?;
.map_err(Error::Trap)?;
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");
let b = m.get(address, mem::size_of::<T>()) let b = m.get(address, mem::size_of::<T>())
.map_err(|_| Error::Trap(Trap::MemoryAccessOutOfBounds))?; .map_err(|_| Trap::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();
@ -585,25 +595,28 @@ 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, Error> fn run_store<T>(&mut self, context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome, Trap>
where RuntimeValue: TryInto<T, Error>, T: LittleEndianConvert { where RuntimeValue: TryInto<T, 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") .expect("Due to vaidation stack should contain value")
.into_little_endian(); .into_little_endian();
let raw_address = context
.value_stack_mut()
.pop_as::<u32>()
.expect("Due to validation stack should contain value");
let address = let address =
effective_address( effective_address(
offset, offset,
context.value_stack_mut().pop_as::<u32>()? raw_address,
) )?;
.map_err(Error::Trap)?;
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");
m.set(address, &stack_value) m.set(address, &stack_value)
.map_err(|_| Error::Trap(Trap::MemoryAccessOutOfBounds))?; .map_err(|_| Trap::MemoryAccessOutOfBounds)?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
@ -612,7 +625,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
context: &mut FunctionContext, context: &mut FunctionContext,
_align: u32, _align: u32,
offset: u32, offset: u32,
) -> Result<InstructionOutcome, Error> ) -> Result<InstructionOutcome, Trap>
where where
RuntimeValue: TryInto<T, Error>, RuntimeValue: TryInto<T, Error>,
T: WrapInto<U>, T: WrapInto<U>,
@ -633,17 +646,16 @@ impl<'a, E: Externals> Interpreter<'a, E> {
effective_address( effective_address(
offset, offset,
raw_address, raw_address,
) )?;
.map_err(Error::Trap)?;
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");
m.set(address, &stack_value) m.set(address, &stack_value)
.map_err(|_| Error::Trap(Trap::MemoryAccessOutOfBounds))?; .map_err(|_| Trap::MemoryAccessOutOfBounds)?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_current_memory(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Error> { fn run_current_memory(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> {
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");
@ -654,8 +666,11 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_grow_memory(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Error> { fn run_grow_memory(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap> {
let pages: u32 = context.value_stack_mut().pop_as()?; let pages: u32 = context
.value_stack_mut()
.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");
@ -668,7 +683,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, Error> { fn run_const(&mut self, context: &mut FunctionContext, val: RuntimeValue) -> Result<InstructionOutcome, Trap> {
context context
.value_stack_mut() .value_stack_mut()
.push(val) .push(val)
@ -676,7 +691,7 @@ 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, Error> fn run_relop<T, F>(&mut self, context: &mut FunctionContext, f: F) -> Result<InstructionOutcome, Trap>
where where
RuntimeValue: TryInto<T, Error>, RuntimeValue: TryInto<T, Error>,
F: FnOnce(T, T) -> bool, F: FnOnce(T, T) -> bool,
@ -690,53 +705,53 @@ impl<'a, E: Externals> Interpreter<'a, E> {
} else { } else {
RuntimeValue::I32(0) RuntimeValue::I32(0)
}; };
context.value_stack_mut().push(v).map_err(|e| Error::Stack(e.to_string()))?; context.value_stack_mut().push(v)?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_eqz<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_eqz<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> + Default { where RuntimeValue: TryInto<T, 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"); .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).map_err(|e| Error::Stack(e.to_string()))?; context.value_stack_mut().push(v)?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_eq<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_eq<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> where RuntimeValue: TryInto<T, 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, Error> fn run_ne<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> { where RuntimeValue: TryInto<T, 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, Error> fn run_lt<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> + Display { where RuntimeValue: TryInto<T, 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, Error> fn run_gt<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> { where RuntimeValue: TryInto<T, 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, Error> fn run_lte<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> { where RuntimeValue: TryInto<T, 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, Error> fn run_gte<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> { where RuntimeValue: TryInto<T, 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, Error> fn run_unop<T, U, F>(&mut self, context: &mut FunctionContext, f: F) -> Result<InstructionOutcome, Trap>
where where
F: FnOnce(T) -> U, F: FnOnce(T) -> U,
RuntimeValue: From<U> + TryInto<T, Error> RuntimeValue: From<U> + TryInto<T, Error>
@ -750,22 +765,22 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_clz<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_clz<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> { where RuntimeValue: From<T> + TryInto<T, 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, Error> fn run_ctz<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> { where RuntimeValue: From<T> + TryInto<T, 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, Error> fn run_popcnt<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> { where RuntimeValue: From<T> + TryInto<T, 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, Error> fn run_add<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> {
let (left, right) = context let (left, right) = context
.value_stack_mut() .value_stack_mut()
@ -776,7 +791,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_sub<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_sub<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> {
let (left, right) = context let (left, right) = context
.value_stack_mut() .value_stack_mut()
@ -787,7 +802,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_mul<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_mul<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> {
let (left, right) = context let (left, right) = context
.value_stack_mut() .value_stack_mut()
@ -798,33 +813,33 @@ 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, Error> fn run_div<T, U>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U> + Display, U: ArithmeticOps<U> + TransmuteInto<T> { where RuntimeValue: From<T> + TryInto<T, 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>()
.expect("Due to validation stack should contain pair of values"); .expect("Due to validation stack should contain pair of values");
let (left, right) = (left.transmute_into(), right.transmute_into()); let (left, right) = (left.transmute_into(), right.transmute_into());
let v = left.div(right).map_err(Error::Trap)?; let v = left.div(right)?;
let v = v.transmute_into(); let v = v.transmute_into();
context.value_stack_mut().push(v.into())?; context.value_stack_mut().push(v.into())?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_rem<T, U>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_rem<T, U>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U>, U: Integer<U> + TransmuteInto<T> { where RuntimeValue: From<T> + TryInto<T, 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>()
.expect("Due to validation stack should contain pair of values"); .expect("Due to validation stack should contain pair of values");
let (left, right) = (left.transmute_into(), right.transmute_into()); let (left, right) = (left.transmute_into(), right.transmute_into());
let v = left.rem(right).map_err(Error::Trap)?; let v = left.rem(right)?;
let v = v.transmute_into(); let v = v.transmute_into();
context.value_stack_mut().push(v.into())?; context.value_stack_mut().push(v.into())?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_and<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_and<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
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, Error>, T: ops::BitAnd<T> {
let (left, right) = context let (left, right) = context
.value_stack_mut() .value_stack_mut()
@ -835,7 +850,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_or<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_or<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
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, Error>, T: ops::BitOr<T> {
let (left, right) = context let (left, right) = context
.value_stack_mut() .value_stack_mut()
@ -846,7 +861,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_xor<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_xor<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
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, Error>, T: ops::BitXor<T> {
let (left, right) = context let (left, right) = context
.value_stack_mut() .value_stack_mut()
@ -857,7 +872,7 @@ 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, Error> fn run_shl<T>(&mut self, context: &mut FunctionContext, mask: T) -> Result<InstructionOutcome, Trap>
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, Error>, T: ops::Shl<T> + ops::BitAnd<T, Output=T> {
let (left, right) = context let (left, right) = context
.value_stack_mut() .value_stack_mut()
@ -868,7 +883,7 @@ 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, Error> fn run_shr<T, U>(&mut self, context: &mut FunctionContext, mask: U) -> Result<InstructionOutcome, Trap>
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, 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()
@ -881,7 +896,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_rotl<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_rotl<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
let (left, right) = context let (left, right) = context
.value_stack_mut() .value_stack_mut()
@ -892,7 +907,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_rotr<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_rotr<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T>
{ {
let (left, right) = context let (left, right) = context
@ -904,13 +919,13 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_abs<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_abs<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> where RuntimeValue: From<T> + TryInto<T, 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, Error> fn run_neg<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where where
RuntimeValue: From<<T as ops::Neg>::Output> + TryInto<T, Error>, RuntimeValue: From<<T as ops::Neg>::Output> + TryInto<T, Error>,
T: ops::Neg T: ops::Neg
@ -918,37 +933,37 @@ impl<'a, E: Externals> Interpreter<'a, E> {
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, Error> fn run_ceil<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> where RuntimeValue: From<T> + TryInto<T, 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, Error> fn run_floor<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> where RuntimeValue: From<T> + TryInto<T, 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, Error> fn run_trunc<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> where RuntimeValue: From<T> + TryInto<T, 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, Error> fn run_nearest<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> where RuntimeValue: From<T> + TryInto<T, 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, Error> fn run_sqrt<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> where RuntimeValue: From<T> + TryInto<T, 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, Error> fn run_min<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T>
{ {
let (left, right) = context let (left, right) = context
@ -960,7 +975,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_max<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_max<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
let (left, right) = context let (left, right) = context
.value_stack_mut() .value_stack_mut()
@ -971,7 +986,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_copysign<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_copysign<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
let (left, right) = context let (left, right) = context
.value_stack_mut() .value_stack_mut()
@ -982,25 +997,25 @@ 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, Error> fn run_wrap<T, U>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: From<U> + TryInto<T, Error>, T: WrapInto<U> { where RuntimeValue: From<U> + TryInto<T, 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, Error> fn run_trunc_to_int<T, U, V>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where RuntimeValue: From<V> + TryInto<T, Error>, T: TryTruncateInto<U, Trap>, U: TransmuteInto<V>, { where RuntimeValue: From<V> + TryInto<T, Error>, T: TryTruncateInto<U, Trap>, 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"); .expect("Due to vaidation stack should contain value");
v.try_truncate_into().map_err(Error::Trap) v.try_truncate_into()
.map(|v| v.transmute_into()) .map(|v| v.transmute_into())
.map(|v| context.value_stack_mut().push(v.into())) .map(|v| context.value_stack_mut().push(v.into()))
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_extend<T, U, V>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_extend<T, U, V>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where where
RuntimeValue: From<V> + TryInto<T, Error>, T: ExtendInto<U>, U: TransmuteInto<V> RuntimeValue: From<V> + TryInto<T, Error>, T: ExtendInto<U>, U: TransmuteInto<V>
{ {
@ -1015,7 +1030,7 @@ 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, Error> fn run_reinterpret<T, U>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Trap>
where where
RuntimeValue: From<U>, RuntimeValue: TryInto<T, Error>, T: TransmuteInto<U> RuntimeValue: From<U>, RuntimeValue: TryInto<T, Error>, T: TransmuteInto<U>
{ {
@ -1068,7 +1083,7 @@ impl FunctionContext {
} }
} }
pub fn nested(&mut self, function: FuncRef) -> Result<Self, Error> { pub fn nested(&mut self, function: FuncRef) -> Result<Self, Trap> {
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"),
@ -1076,7 +1091,7 @@ impl FunctionContext {
}; };
let function_type = function.signature(); let function_type = function.signature();
let function_return_type = function_type.return_type().map(|vt| BlockType::Value(vt.into_elements())).unwrap_or(BlockType::NoResult); let function_return_type = function_type.return_type().map(|vt| BlockType::Value(vt.into_elements())).unwrap_or(BlockType::NoResult);
let function_locals = prepare_function_args(function_type, &mut self.value_stack)?; let function_locals = prepare_function_args(function_type, &mut self.value_stack);
(function_locals, module, function_return_type) (function_locals, module, function_return_type)
}; };
@ -1134,7 +1149,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<(), Error> { pub fn push_frame(&mut self, labels: &HashMap<usize, usize>, frame_type: BlockFrameType, block_type: BlockType) -> Result<(), Trap> {
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,
@ -1152,28 +1167,32 @@ impl FunctionContext {
BlockFrameType::Function => usize::MAX, BlockFrameType::Function => usize::MAX,
_ => labels[&begin_position] + 1, _ => labels[&begin_position] + 1,
}; };
Ok(self.frame_stack.push(BlockFrame {
self.frame_stack.push(BlockFrame {
frame_type: frame_type, frame_type: frame_type,
block_type: block_type, block_type: block_type,
begin_position: begin_position, begin_position: begin_position,
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)?;
Ok(())
} }
pub fn discard_frame(&mut self) -> Result<(), Error> { pub fn discard_frame(&mut self) {
Ok(self.frame_stack.pop().map(|_| ())?) 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<(), Error> { pub fn pop_frame(&mut self, is_branch: bool) -> Result<(), Trap> {
let frame = self.frame_stack.pop()?; let frame = self.frame_stack
if frame.value_stack_len > self.value_stack.len() { .pop()
return Err(Error::Stack("invalid stack len".into())); .expect("Due to validation frame stack shouldn't be empty");
} assert!(frame.value_stack_len <= self.value_stack.len(), "invalid stack len");
let frame_value = match frame.block_type { let frame_value = match frame.block_type {
BlockType::Value(_) if frame.frame_type != BlockFrameType::Loop || !is_branch => Some(self.value_stack.pop()?), BlockType::Value(_) if frame.frame_type != BlockFrameType::Loop || !is_branch =>
Some(self.value_stack.pop().expect("Due to validation, stack shouldn't be empty")),
_ => None, _ => None,
}; };
self.value_stack.resize(frame.value_stack_len); self.value_stack.resize(frame.value_stack_len);
@ -1199,13 +1218,13 @@ fn effective_address(address: u32, offset: u32) -> Result<u32, Trap> {
} }
} }
fn prepare_function_args(signature: &Signature, caller_stack: &mut ValueStack) -> Result<Vec<RuntimeValue>, Error> { fn prepare_function_args(signature: &Signature, caller_stack: &mut ValueStack) -> Vec<RuntimeValue> {
let mut args = signature.params().iter().cloned().rev().map(|_| { let mut args = signature.params().iter().cloned().rev().map(|_| {
caller_stack.pop() caller_stack.pop().expect("Due to validation stack shouldn't be empty")
}).collect::<Result<Vec<RuntimeValue>, _>>()?; }).collect::<Vec<RuntimeValue>>();
args.reverse(); args.reverse();
check_function_args(signature, &args)?; check_function_args(signature, &args).expect("Due to validation arguments should match");
Ok(args) args
} }
pub fn check_function_args(signature: &Signature, args: &[RuntimeValue]) -> Result<(), Error> { pub fn check_function_args(signature: &Signature, args: &[RuntimeValue]) -> Result<(), Error> {
@ -1271,8 +1290,9 @@ impl ValueStack {
self.stack_with_limit.pop().map_err(|e| Error::Stack(e.to_string())) self.stack_with_limit.pop().map_err(|e| Error::Stack(e.to_string()))
} }
fn push(&mut self, value: RuntimeValue) -> Result<(), Error> { fn push(&mut self, value: RuntimeValue) -> Result<(), Trap> {
self.stack_with_limit.push(value).map_err(|e| Error::Stack(e.to_string())) self.stack_with_limit.push(value)
.map_err(|_| Trap::StackOverflow)
} }
fn resize(&mut self, new_len: usize) { fn resize(&mut self, new_len: usize) {

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, Module, TableDescriptor, MemoryDescriptor, RuntimeValue, RuntimeArgs, Module, TableDescriptor, MemoryDescriptor, Trap,
}; };
use types::ValueType; use types::ValueType;
use wabt::wat2wasm; use wabt::wat2wasm;
@ -79,7 +79,7 @@ impl Externals for TestHost {
&mut self, &mut self,
index: usize, index: usize,
args: RuntimeArgs, args: RuntimeArgs,
) -> Result<Option<RuntimeValue>, Error> { ) -> Result<Option<RuntimeValue>, Trap> {
match index { match index {
SUB_FUNC_INDEX => { SUB_FUNC_INDEX => {
let a: i32 = args.nth(0)?; let a: i32 = args.nth(0)?;
@ -464,7 +464,7 @@ fn defer_providing_externals() {
&mut self, &mut self,
index: usize, index: usize,
args: RuntimeArgs, args: RuntimeArgs,
) -> Result<Option<RuntimeValue>, Error> { ) -> Result<Option<RuntimeValue>, Trap> {
match index { match index {
INC_FUNC_INDEX => { INC_FUNC_INDEX => {
let a = args.nth::<u32>(0)?; let a = args.nth::<u32>(0)?;
@ -528,7 +528,7 @@ fn two_envs_one_externals() {
&mut self, &mut self,
index: usize, index: usize,
_args: RuntimeArgs, _args: RuntimeArgs,
) -> Result<Option<RuntimeValue>, Error> { ) -> Result<Option<RuntimeValue>, Trap> {
match index { match index {
PRIVILEGED_FUNC_INDEX => { PRIVILEGED_FUNC_INDEX => {
println!("privileged!"); println!("privileged!");
@ -648,7 +648,7 @@ fn dynamically_add_host_func() {
&mut self, &mut self,
index: usize, index: usize,
_args: RuntimeArgs, _args: RuntimeArgs,
) -> Result<Option<RuntimeValue>, Error> { ) -> Result<Option<RuntimeValue>, Trap> {
match index { match index {
ADD_FUNC_FUNC_INDEX => { ADD_FUNC_FUNC_INDEX => {
// Allocate indicies for the new function. // Allocate indicies for the new function.