WIP
This commit is contained in:
parent
bd3d8fc762
commit
aba44ca5ed
|
@ -59,6 +59,14 @@ impl<T> StackWithLimit<T> where T: Clone {
|
||||||
.ok_or_else(|| Error("non-empty stack expected".into()))
|
.ok_or_else(|| Error("non-empty stack expected".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pick_mut(&mut self, depth: usize) -> Result<&mut T, Error> {
|
||||||
|
let len = self.values.len();
|
||||||
|
// TODO:
|
||||||
|
self.values
|
||||||
|
.get_mut(len - 1 - depth)
|
||||||
|
.ok_or_else(|| Error("non-empty stack expected".into()))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get(&self, index: usize) -> Result<&T, Error> {
|
pub fn get(&self, index: usize) -> Result<&T, Error> {
|
||||||
if index >= self.values.len() {
|
if index >= self.values.len() {
|
||||||
return Err(Error(format!("trying to get value at position {} on stack of size {}", index, self.values.len())));
|
return Err(Error(format!("trying to get value at position {} on stack of size {}", index, self.values.len())));
|
||||||
|
|
398
src/runner.rs
398
src/runner.rs
|
@ -22,9 +22,8 @@ use isa;
|
||||||
/// Maximum number of entries in value stack.
|
/// Maximum number of entries in value stack.
|
||||||
pub const DEFAULT_VALUE_STACK_LIMIT: usize = 16384;
|
pub const DEFAULT_VALUE_STACK_LIMIT: usize = 16384;
|
||||||
|
|
||||||
/// Function interpreter.
|
struct EvalContext {
|
||||||
pub struct Interpreter<'a, E: Externals + 'a> {
|
call_stack: VecDeque<FunctionContext>,
|
||||||
externals: &'a mut E,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Interpreter action to execute after executing instruction.
|
/// Interpreter action to execute after executing instruction.
|
||||||
|
@ -36,64 +35,84 @@ pub enum InstructionOutcome {
|
||||||
/// Execute function call.
|
/// Execute function call.
|
||||||
ExecuteCall(FuncRef),
|
ExecuteCall(FuncRef),
|
||||||
/// Return from current function block.
|
/// Return from current function block.
|
||||||
Return,
|
Return(u32, u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Function run result.
|
/// Function run result.
|
||||||
enum RunResult {
|
enum RunResult {
|
||||||
/// Function has returned (optional) value.
|
/// Function has returned.
|
||||||
Return(Option<RuntimeValue>),
|
Return,
|
||||||
/// Function is calling other function.
|
/// Function is calling other function.
|
||||||
NestedCall(FuncRef),
|
NestedCall(FuncRef),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Function interpreter.
|
||||||
|
pub struct Interpreter<'a, E: Externals + 'a> {
|
||||||
|
externals: &'a mut E,
|
||||||
|
value_stack: ValueStack,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, E: Externals> Interpreter<'a, E> {
|
impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
pub fn new(externals: &'a mut E) -> Interpreter<'a, E> {
|
pub fn new(externals: &'a mut E) -> Interpreter<'a, E> {
|
||||||
|
let value_stack = ValueStack::with_limit(DEFAULT_VALUE_STACK_LIMIT);
|
||||||
Interpreter {
|
Interpreter {
|
||||||
externals,
|
externals,
|
||||||
|
value_stack,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_execution(&mut self, func: &FuncRef, args: &[RuntimeValue]) -> Result<Option<RuntimeValue>, Trap> {
|
pub fn start_execution(&mut self, func: &FuncRef, args: &[RuntimeValue]) -> Result<Option<RuntimeValue>, Trap> {
|
||||||
|
for arg in args {
|
||||||
|
self.value_stack.push(*arg).expect("TODO");
|
||||||
|
}
|
||||||
|
|
||||||
let context = FunctionContext::new(
|
let context = FunctionContext::new(
|
||||||
func.clone(),
|
func.clone(),
|
||||||
DEFAULT_VALUE_STACK_LIMIT,
|
|
||||||
func.signature(),
|
|
||||||
args.into_iter().cloned().collect(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut function_stack = VecDeque::new();
|
let mut function_stack = VecDeque::new();
|
||||||
function_stack.push_back(context);
|
function_stack.push_back(context);
|
||||||
|
|
||||||
self.run_interpreter_loop(&mut function_stack)
|
self.run_interpreter_loop(&mut function_stack)?;
|
||||||
|
|
||||||
|
println!("return stack: {:?}", self.value_stack);
|
||||||
|
|
||||||
|
Ok(func.signature().return_type().map(|vt| {
|
||||||
|
let return_value = self.value_stack
|
||||||
|
.pop();
|
||||||
|
|
||||||
|
return_value
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_interpreter_loop(&mut self, function_stack: &mut VecDeque<FunctionContext>) -> Result<Option<RuntimeValue>, Trap> {
|
fn run_interpreter_loop(&mut self, function_stack: &mut VecDeque<FunctionContext>) -> Result<(), Trap> {
|
||||||
loop {
|
loop {
|
||||||
let mut function_context = function_stack.pop_back().expect("on loop entry - not empty; on loop continue - checking for emptiness; qed");
|
let mut function_context = function_stack
|
||||||
|
.pop_back()
|
||||||
|
.expect("on loop entry - not empty; on loop continue - checking for emptiness; qed");
|
||||||
let function_ref = function_context.function.clone();
|
let function_ref = function_context.function.clone();
|
||||||
let function_body = function_ref
|
let function_body = function_ref
|
||||||
.body()
|
.body()
|
||||||
.expect(
|
.expect(
|
||||||
"Host functions checked in function_return below; Internal functions always have a body; qed"
|
"Host functions checked in function_return below; Internal functions always have a body; qed"
|
||||||
);
|
);
|
||||||
|
|
||||||
if !function_context.is_initialized() {
|
if !function_context.is_initialized() {
|
||||||
let return_type = function_context.return_type;
|
// Initialize stack frame for the function call.
|
||||||
function_context.initialize(&function_body.locals);
|
function_context.initialize(&function_body.locals, &mut self.value_stack)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let function_return = self.do_run_function(
|
let function_return =
|
||||||
&mut function_context,
|
self.do_run_function(
|
||||||
&function_body.code.code,
|
&mut function_context,
|
||||||
).map_err(Trap::new)?;
|
&function_body.code.code,
|
||||||
|
).map_err(Trap::new)?;
|
||||||
|
|
||||||
match function_return {
|
match function_return {
|
||||||
RunResult::Return(return_value) => {
|
RunResult::Return => {
|
||||||
match function_stack.back_mut() {
|
if function_stack.back().is_none() {
|
||||||
Some(caller_context) => if let Some(return_value) = return_value {
|
// There are no more frames in the call stack.
|
||||||
caller_context.value_stack_mut().push(return_value).map_err(Trap::new)?;
|
return Ok(());
|
||||||
},
|
|
||||||
None => return Ok(return_value),
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
RunResult::NestedCall(nested_func) => {
|
RunResult::NestedCall(nested_func) => {
|
||||||
|
@ -104,7 +123,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 self.value_stack);
|
||||||
let return_val = FuncInstance::invoke(&nested_func, &args, self.externals)?;
|
let return_val = FuncInstance::invoke(&nested_func, &args, self.externals)?;
|
||||||
|
|
||||||
// Check if `return_val` matches the signature.
|
// Check if `return_val` matches the signature.
|
||||||
|
@ -115,7 +134,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(return_val) = return_val {
|
if let Some(return_val) = return_val {
|
||||||
function_context.value_stack_mut().push(return_val).map_err(Trap::new)?;
|
self.value_stack.push(return_val).map_err(Trap::new)?;
|
||||||
}
|
}
|
||||||
function_stack.push_back(function_context);
|
function_stack.push_back(function_context);
|
||||||
}
|
}
|
||||||
|
@ -125,45 +144,48 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn drop_keep(&mut self, drop: u32, keep: u8) -> Result<(), TrapKind> {
|
||||||
|
assert!(keep <= 1);
|
||||||
|
println!("drop: {}, keep: {}, stack: {:?}", drop, keep, self.value_stack);
|
||||||
|
if keep == 1 {
|
||||||
|
let top = *self.value_stack.top();
|
||||||
|
*self.value_stack.pick_mut(drop as usize) = top;
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("drop: {}, keep: {}, stack: {:?}", drop, keep, self.value_stack);
|
||||||
|
let cur_stack_len = self.value_stack.len();
|
||||||
|
self.value_stack.resize(cur_stack_len - drop as usize);
|
||||||
|
println!("drop: {}, keep: {}, stack: {:?}", drop, keep, self.value_stack);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn do_run_function(&mut self, function_context: &mut FunctionContext, instructions: &[isa::Instruction]) -> Result<RunResult, TrapKind> {
|
fn do_run_function(&mut self, function_context: &mut FunctionContext, instructions: &[isa::Instruction]) -> Result<RunResult, TrapKind> {
|
||||||
loop {
|
loop {
|
||||||
let instruction = &instructions[function_context.position];
|
let instruction = &instructions[function_context.position];
|
||||||
|
|
||||||
|
println!("{:?}", instruction);
|
||||||
|
println!(" before = {:?}", self.value_stack);
|
||||||
|
|
||||||
match self.run_instruction(function_context, instruction)? {
|
match self.run_instruction(function_context, instruction)? {
|
||||||
InstructionOutcome::RunNextInstruction => function_context.position += 1,
|
InstructionOutcome::RunNextInstruction => function_context.position += 1,
|
||||||
InstructionOutcome::Branch(target) => {
|
InstructionOutcome::Branch(target) => {
|
||||||
function_context.position = target.dst_pc as usize;
|
function_context.position = target.dst_pc as usize;
|
||||||
|
self.drop_keep(target.drop, target.keep)?;
|
||||||
assert!(target.keep <= 1);
|
|
||||||
let keep = if target.keep == 1 {
|
|
||||||
Some(function_context.value_stack_mut().pop())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let cur_stack_len = function_context.value_stack.len();
|
|
||||||
function_context.value_stack_mut().resize(cur_stack_len - target.drop as usize);
|
|
||||||
if let Some(keep) = keep {
|
|
||||||
function_context.value_stack_mut().push(keep)?;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
InstructionOutcome::ExecuteCall(func_ref) => {
|
InstructionOutcome::ExecuteCall(func_ref) => {
|
||||||
function_context.position += 1;
|
function_context.position += 1;
|
||||||
return Ok(RunResult::NestedCall(func_ref));
|
return Ok(RunResult::NestedCall(func_ref));
|
||||||
},
|
},
|
||||||
InstructionOutcome::Return => break,
|
InstructionOutcome::Return(drop, keep) => {
|
||||||
|
self.drop_keep(drop, keep)?;
|
||||||
|
break;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
println!(" after = {:?}", self.value_stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(RunResult::Return(match function_context.return_type {
|
Ok(RunResult::Return)
|
||||||
BlockType::Value(_) => {
|
|
||||||
let result = function_context
|
|
||||||
.value_stack_mut()
|
|
||||||
.pop();
|
|
||||||
Some(result)
|
|
||||||
},
|
|
||||||
BlockType::NoResult => None,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_instruction(&mut self, context: &mut FunctionContext, instruction: &isa::Instruction) -> Result<InstructionOutcome, TrapKind> {
|
fn run_instruction(&mut self, context: &mut FunctionContext, instruction: &isa::Instruction) -> Result<InstructionOutcome, TrapKind> {
|
||||||
|
@ -174,7 +196,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
&isa::Instruction::BrIfEqz(ref target) => self.run_br_eqz(context, target.clone()),
|
&isa::Instruction::BrIfEqz(ref target) => self.run_br_eqz(context, target.clone()),
|
||||||
&isa::Instruction::BrIfNez(ref target) => self.run_br_nez(context, target.clone()),
|
&isa::Instruction::BrIfNez(ref target) => self.run_br_nez(context, target.clone()),
|
||||||
&isa::Instruction::BrTable(ref targets) => self.run_br_table(context, targets),
|
&isa::Instruction::BrTable(ref targets) => self.run_br_table(context, targets),
|
||||||
&isa::Instruction::Return { drop, keep } => self.run_return(context),
|
&isa::Instruction::Return { drop, keep } => self.run_return(context, drop, keep),
|
||||||
|
|
||||||
&isa::Instruction::Call(index) => self.run_call(context, index),
|
&isa::Instruction::Call(index) => self.run_call(context, index),
|
||||||
&isa::Instruction::CallIndirect(index) => self.run_call_indirect(context, index),
|
&isa::Instruction::CallIndirect(index) => self.run_call_indirect(context, index),
|
||||||
|
@ -365,7 +387,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_br_nez(&mut self, context: &mut FunctionContext, target: isa::Target) -> Result<InstructionOutcome, TrapKind> {
|
fn run_br_nez(&mut self, context: &mut FunctionContext, target: isa::Target) -> Result<InstructionOutcome, TrapKind> {
|
||||||
let condition = context.value_stack_mut().pop_as();
|
let condition = self.value_stack.pop_as();
|
||||||
if condition {
|
if condition {
|
||||||
Ok(InstructionOutcome::Branch(target))
|
Ok(InstructionOutcome::Branch(target))
|
||||||
} else {
|
} else {
|
||||||
|
@ -374,7 +396,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_br_eqz(&mut self, context: &mut FunctionContext, target: isa::Target) -> Result<InstructionOutcome, TrapKind> {
|
fn run_br_eqz(&mut self, context: &mut FunctionContext, target: isa::Target) -> Result<InstructionOutcome, TrapKind> {
|
||||||
let condition = context.value_stack_mut().pop_as();
|
let condition = self.value_stack.pop_as();
|
||||||
if condition {
|
if condition {
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
} else {
|
} else {
|
||||||
|
@ -384,7 +406,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_br_table(&mut self, context: &mut FunctionContext, table: &[isa::Target]) -> Result<InstructionOutcome, TrapKind> {
|
fn run_br_table(&mut self, context: &mut FunctionContext, table: &[isa::Target]) -> Result<InstructionOutcome, TrapKind> {
|
||||||
let index: u32 = context.value_stack_mut()
|
let index: u32 = self.value_stack
|
||||||
.pop_as();
|
.pop_as();
|
||||||
|
|
||||||
let dst =
|
let dst =
|
||||||
|
@ -397,8 +419,8 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
Ok(InstructionOutcome::Branch(dst))
|
Ok(InstructionOutcome::Branch(dst))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_return(&mut self, _context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
|
fn run_return(&mut self, _context: &mut FunctionContext, drop: u32, keep: u8) -> Result<InstructionOutcome, TrapKind> {
|
||||||
Ok(InstructionOutcome::Return)
|
Ok(InstructionOutcome::Return(drop, keep))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_call(
|
fn run_call(
|
||||||
|
@ -418,8 +440,8 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
context: &mut FunctionContext,
|
context: &mut FunctionContext,
|
||||||
signature_idx: u32,
|
signature_idx: u32,
|
||||||
) -> Result<InstructionOutcome, TrapKind> {
|
) -> Result<InstructionOutcome, TrapKind> {
|
||||||
let table_func_idx: u32 = context
|
let table_func_idx: u32 = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.pop_as();
|
.pop_as();
|
||||||
let table = context
|
let table = context
|
||||||
.module()
|
.module()
|
||||||
|
@ -445,45 +467,45 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_drop(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
|
fn run_drop(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
|
||||||
let _ = context
|
let _ = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.pop();
|
.pop();
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_select(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
|
fn run_select(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
|
||||||
let (left, mid, right) = context
|
let (left, mid, right) = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.pop_triple();
|
.pop_triple();
|
||||||
|
|
||||||
let condition = right
|
let condition = right
|
||||||
.try_into()
|
.try_into()
|
||||||
.expect("Due to validation stack top should be I32");
|
.expect("Due to validation stack top should be I32");
|
||||||
let val = if condition { left } else { mid };
|
let val = if condition { left } else { mid };
|
||||||
context.value_stack_mut().push(val)?;
|
self.value_stack.push(val)?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_get_local(&mut self, context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, TrapKind> {
|
fn run_get_local(&mut self, context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, TrapKind> {
|
||||||
let val = context.get_local(index as usize);
|
let val = *self.value_stack.pick_mut(index as usize - 1);
|
||||||
context.value_stack_mut().push(val)?;
|
self.value_stack.push(val)?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_set_local(&mut self, context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, TrapKind> {
|
fn run_set_local(&mut self, context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, TrapKind> {
|
||||||
let arg = context
|
let val = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.pop();
|
.pop();
|
||||||
context.set_local(index as usize, arg);
|
*self.value_stack.pick_mut(index as usize - 1) = val;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_tee_local(&mut self, context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, TrapKind> {
|
fn run_tee_local(&mut self, context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, TrapKind> {
|
||||||
let arg = context
|
let val = self
|
||||||
.value_stack()
|
.value_stack
|
||||||
.top()
|
.top()
|
||||||
.clone();
|
.clone();
|
||||||
context.set_local(index as usize, arg);
|
*self.value_stack.pick_mut(index as usize - 1) = val;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -497,7 +519,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
.global_by_index(index)
|
.global_by_index(index)
|
||||||
.expect("Due to validation global should exists");
|
.expect("Due to validation global should exists");
|
||||||
let val = global.get();
|
let val = global.get();
|
||||||
context.value_stack_mut().push(val)?;
|
self.value_stack.push(val)?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -506,8 +528,8 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
context: &mut FunctionContext,
|
context: &mut FunctionContext,
|
||||||
index: u32,
|
index: u32,
|
||||||
) -> Result<InstructionOutcome, TrapKind> {
|
) -> Result<InstructionOutcome, TrapKind> {
|
||||||
let val = context
|
let val = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.pop();
|
.pop();
|
||||||
let global = context
|
let global = context
|
||||||
.module()
|
.module()
|
||||||
|
@ -519,8 +541,8 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
|
|
||||||
fn run_load<T>(&mut self, context: &mut FunctionContext, offset: u32) -> Result<InstructionOutcome, TrapKind>
|
fn run_load<T>(&mut self, context: &mut FunctionContext, offset: u32) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: LittleEndianConvert {
|
where RuntimeValue: From<T>, T: LittleEndianConvert {
|
||||||
let raw_address = context
|
let raw_address = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.pop_as();
|
.pop_as();
|
||||||
let address =
|
let address =
|
||||||
effective_address(
|
effective_address(
|
||||||
|
@ -534,14 +556,14 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
.map_err(|_| TrapKind::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())?;
|
self.value_stack.push(n.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_load_extend<T, U>(&mut self, context: &mut FunctionContext, offset: u32) -> Result<InstructionOutcome, TrapKind>
|
fn run_load_extend<T, U>(&mut self, context: &mut FunctionContext, 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 = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.pop_as();
|
.pop_as();
|
||||||
let address =
|
let address =
|
||||||
effective_address(
|
effective_address(
|
||||||
|
@ -556,8 +578,8 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
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();
|
||||||
context
|
self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.push(stack_value.into())
|
.push(stack_value.into())
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
|
@ -565,12 +587,12 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
|
|
||||||
fn run_store<T>(&mut self, context: &mut FunctionContext, offset: u32) -> Result<InstructionOutcome, TrapKind>
|
fn run_store<T>(&mut self, context: &mut FunctionContext, offset: u32) -> Result<InstructionOutcome, TrapKind>
|
||||||
where T: FromRuntimeValue, T: LittleEndianConvert {
|
where T: FromRuntimeValue, T: LittleEndianConvert {
|
||||||
let stack_value = context
|
let stack_value = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.pop_as::<T>()
|
.pop_as::<T>()
|
||||||
.into_little_endian();
|
.into_little_endian();
|
||||||
let raw_address = context
|
let raw_address = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.pop_as::<u32>();
|
.pop_as::<u32>();
|
||||||
let address =
|
let address =
|
||||||
effective_address(
|
effective_address(
|
||||||
|
@ -596,14 +618,14 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
T: WrapInto<U>,
|
T: WrapInto<U>,
|
||||||
U: LittleEndianConvert,
|
U: LittleEndianConvert,
|
||||||
{
|
{
|
||||||
let stack_value: T = context
|
let stack_value: T = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.pop()
|
.pop()
|
||||||
.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 = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.pop_as::<u32>();
|
.pop_as::<u32>();
|
||||||
let address =
|
let address =
|
||||||
effective_address(
|
effective_address(
|
||||||
|
@ -623,15 +645,15 @@ 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 s = m.current_size().0;
|
let s = m.current_size().0;
|
||||||
context
|
self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.push(RuntimeValue::I32(s as i32))?;
|
.push(RuntimeValue::I32(s as i32))?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_grow_memory(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
|
fn run_grow_memory(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
|
||||||
let pages: u32 = context
|
let pages: u32 = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.pop_as();
|
.pop_as();
|
||||||
let m = context.module()
|
let m = context.module()
|
||||||
.memory_by_index(DEFAULT_MEMORY_INDEX)
|
.memory_by_index(DEFAULT_MEMORY_INDEX)
|
||||||
|
@ -640,15 +662,15 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
Ok(Pages(new_size)) => new_size as u32,
|
Ok(Pages(new_size)) => new_size as u32,
|
||||||
Err(_) => u32::MAX, // Returns -1 (or 0xFFFFFFFF) in case of error.
|
Err(_) => u32::MAX, // Returns -1 (or 0xFFFFFFFF) in case of error.
|
||||||
};
|
};
|
||||||
context
|
self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.push(RuntimeValue::I32(m as i32))?;
|
.push(RuntimeValue::I32(m as i32))?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_const(&mut self, context: &mut FunctionContext, val: RuntimeValue) -> Result<InstructionOutcome, TrapKind> {
|
fn run_const(&mut self, context: &mut FunctionContext, val: RuntimeValue) -> Result<InstructionOutcome, TrapKind> {
|
||||||
context
|
self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.push(val)
|
.push(val)
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
|
@ -659,8 +681,8 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
T: FromRuntimeValue,
|
T: FromRuntimeValue,
|
||||||
F: FnOnce(T, T) -> bool,
|
F: FnOnce(T, T) -> bool,
|
||||||
{
|
{
|
||||||
let (left, right) = context
|
let (left, right) = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.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 v = if f(left, right) {
|
let v = if f(left, right) {
|
||||||
|
@ -668,17 +690,17 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
} else {
|
} else {
|
||||||
RuntimeValue::I32(0)
|
RuntimeValue::I32(0)
|
||||||
};
|
};
|
||||||
context.value_stack_mut().push(v)?;
|
self.value_stack.push(v)?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_eqz<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_eqz<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where T: FromRuntimeValue, T: PartialEq<T> + Default {
|
where T: FromRuntimeValue, T: PartialEq<T> + Default {
|
||||||
let v = context
|
let v = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.pop_as::<T>();
|
.pop_as::<T>();
|
||||||
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)?;
|
self.value_stack.push(v)?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -719,11 +741,11 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
T: FromRuntimeValue,
|
T: FromRuntimeValue,
|
||||||
RuntimeValue: From<U>
|
RuntimeValue: From<U>
|
||||||
{
|
{
|
||||||
let v = context
|
let v = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.pop_as::<T>();
|
.pop_as::<T>();
|
||||||
let v = f(v);
|
let v = f(v);
|
||||||
context.value_stack_mut().push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -744,140 +766,140 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
|
|
||||||
fn run_add<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_add<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: ArithmeticOps<T> + FromRuntimeValue {
|
where RuntimeValue: From<T>, T: ArithmeticOps<T> + FromRuntimeValue {
|
||||||
let (left, right) = context
|
let (left, right) = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.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 v = left.add(right);
|
let v = left.add(right);
|
||||||
context.value_stack_mut().push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_sub<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_sub<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: ArithmeticOps<T> + FromRuntimeValue {
|
where RuntimeValue: From<T>, T: ArithmeticOps<T> + FromRuntimeValue {
|
||||||
let (left, right) = context
|
let (left, right) = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.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 v = left.sub(right);
|
let v = left.sub(right);
|
||||||
context.value_stack_mut().push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_mul<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_mul<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: ArithmeticOps<T> + FromRuntimeValue {
|
where RuntimeValue: From<T>, T: ArithmeticOps<T> + FromRuntimeValue {
|
||||||
let (left, right) = context
|
let (left, right) = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.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 v = left.mul(right);
|
let v = left.mul(right);
|
||||||
context.value_stack_mut().push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_div<T, U>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_div<T, U>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: TransmuteInto<U> + FromRuntimeValue, U: ArithmeticOps<U> + TransmuteInto<T> {
|
where RuntimeValue: From<T>, T: TransmuteInto<U> + FromRuntimeValue, U: ArithmeticOps<U> + TransmuteInto<T> {
|
||||||
let (left, right) = context
|
let (left, right) = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.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)?;
|
let v = left.div(right)?;
|
||||||
let v = v.transmute_into();
|
let v = v.transmute_into();
|
||||||
context.value_stack_mut().push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_rem<T, U>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_rem<T, U>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: TransmuteInto<U> + FromRuntimeValue, U: Integer<U> + TransmuteInto<T> {
|
where RuntimeValue: From<T>, T: TransmuteInto<U> + FromRuntimeValue, U: Integer<U> + TransmuteInto<T> {
|
||||||
let (left, right) = context
|
let (left, right) = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.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)?;
|
let v = left.rem(right)?;
|
||||||
let v = v.transmute_into();
|
let v = v.transmute_into();
|
||||||
context.value_stack_mut().push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_and<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_and<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<<T as ops::BitAnd>::Output>, T: ops::BitAnd<T> + FromRuntimeValue {
|
where RuntimeValue: From<<T as ops::BitAnd>::Output>, T: ops::BitAnd<T> + FromRuntimeValue {
|
||||||
let (left, right) = context
|
let (left, right) = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.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 v = left.bitand(right);
|
let v = left.bitand(right);
|
||||||
context.value_stack_mut().push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_or<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_or<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<<T as ops::BitOr>::Output>, T: ops::BitOr<T> + FromRuntimeValue {
|
where RuntimeValue: From<<T as ops::BitOr>::Output>, T: ops::BitOr<T> + FromRuntimeValue {
|
||||||
let (left, right) = context
|
let (left, right) = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.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 v = left.bitor(right);
|
let v = left.bitor(right);
|
||||||
context.value_stack_mut().push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_xor<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_xor<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<<T as ops::BitXor>::Output>, T: ops::BitXor<T> + FromRuntimeValue {
|
where RuntimeValue: From<<T as ops::BitXor>::Output>, T: ops::BitXor<T> + FromRuntimeValue {
|
||||||
let (left, right) = context
|
let (left, right) = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.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 v = left.bitxor(right);
|
let v = left.bitxor(right);
|
||||||
context.value_stack_mut().push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_shl<T>(&mut self, context: &mut FunctionContext, mask: T) -> Result<InstructionOutcome, TrapKind>
|
fn run_shl<T>(&mut self, context: &mut FunctionContext, mask: T) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<<T as ops::Shl<T>>::Output>, T: ops::Shl<T> + ops::BitAnd<T, Output=T> + FromRuntimeValue {
|
where RuntimeValue: From<<T as ops::Shl<T>>::Output>, T: ops::Shl<T> + ops::BitAnd<T, Output=T> + FromRuntimeValue {
|
||||||
let (left, right) = context
|
let (left, right) = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.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 v = left.shl(right & mask);
|
let v = left.shl(right & mask);
|
||||||
context.value_stack_mut().push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_shr<T, U>(&mut self, context: &mut FunctionContext, mask: U) -> Result<InstructionOutcome, TrapKind>
|
fn run_shr<T, U>(&mut self, context: &mut FunctionContext, mask: U) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: TransmuteInto<U> + FromRuntimeValue, U: ops::Shr<U> + ops::BitAnd<U, Output=U>, <U as ops::Shr<U>>::Output: TransmuteInto<T> {
|
where RuntimeValue: From<T>, T: TransmuteInto<U> + FromRuntimeValue, U: ops::Shr<U> + ops::BitAnd<U, Output=U>, <U as ops::Shr<U>>::Output: TransmuteInto<T> {
|
||||||
let (left, right) = context
|
let (left, right) = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.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.shr(right & mask);
|
let v = left.shr(right & mask);
|
||||||
let v = v.transmute_into();
|
let v = v.transmute_into();
|
||||||
context.value_stack_mut().push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_rotl<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_rotl<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: Integer<T> + FromRuntimeValue {
|
where RuntimeValue: From<T>, T: Integer<T> + FromRuntimeValue {
|
||||||
let (left, right) = context
|
let (left, right) = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.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 v = left.rotl(right);
|
let v = left.rotl(right);
|
||||||
context.value_stack_mut().push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_rotr<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_rotr<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: Integer<T> + FromRuntimeValue
|
where RuntimeValue: From<T>, T: Integer<T> + FromRuntimeValue
|
||||||
{
|
{
|
||||||
let (left, right) = context
|
let (left, right) = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.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 v = left.rotr(right);
|
let v = left.rotr(right);
|
||||||
context.value_stack_mut().push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -928,34 +950,34 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
fn run_min<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_min<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue
|
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue
|
||||||
{
|
{
|
||||||
let (left, right) = context
|
let (left, right) = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.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 v = left.min(right);
|
let v = left.min(right);
|
||||||
context.value_stack_mut().push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_max<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_max<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue {
|
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue {
|
||||||
let (left, right) = context
|
let (left, right) = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.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 v = left.max(right);
|
let v = left.max(right);
|
||||||
context.value_stack_mut().push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_copysign<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_copysign<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue {
|
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue {
|
||||||
let (left, right) = context
|
let (left, right) = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.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 v = left.copysign(right);
|
let v = left.copysign(right);
|
||||||
context.value_stack_mut().push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -966,13 +988,13 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
|
|
||||||
fn run_trunc_to_int<T, U, V>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_trunc_to_int<T, U, V>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<V>, T: TryTruncateInto<U, TrapKind> + FromRuntimeValue, U: TransmuteInto<V>, {
|
where RuntimeValue: From<V>, T: TryTruncateInto<U, TrapKind> + FromRuntimeValue, U: TransmuteInto<V>, {
|
||||||
let v = context
|
let v = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.pop_as::<T>();
|
.pop_as::<T>();
|
||||||
|
|
||||||
v.try_truncate_into()
|
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| self.value_stack.push(v.into()))
|
||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -980,12 +1002,12 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
where
|
where
|
||||||
RuntimeValue: From<V>, T: ExtendInto<U> + FromRuntimeValue, U: TransmuteInto<V>
|
RuntimeValue: From<V>, T: ExtendInto<U> + FromRuntimeValue, U: TransmuteInto<V>
|
||||||
{
|
{
|
||||||
let v = context
|
let v = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.pop_as::<T>();
|
.pop_as::<T>();
|
||||||
|
|
||||||
let v = v.extend_into().transmute_into();
|
let v = v.extend_into().transmute_into();
|
||||||
context.value_stack_mut().push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
|
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
@ -994,12 +1016,12 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
where
|
where
|
||||||
RuntimeValue: From<U>, T: FromRuntimeValue, T: TransmuteInto<U>
|
RuntimeValue: From<U>, T: FromRuntimeValue, T: TransmuteInto<U>
|
||||||
{
|
{
|
||||||
let v = context
|
let v = self
|
||||||
.value_stack_mut()
|
.value_stack
|
||||||
.pop_as::<T>();
|
.pop_as::<T>();
|
||||||
|
|
||||||
let v = v.transmute_into();
|
let v = v.transmute_into();
|
||||||
context.value_stack_mut().push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
|
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
@ -1012,18 +1034,12 @@ struct FunctionContext {
|
||||||
/// Internal function reference.
|
/// Internal function reference.
|
||||||
pub function: FuncRef,
|
pub function: FuncRef,
|
||||||
pub module: ModuleRef,
|
pub module: ModuleRef,
|
||||||
/// Function return type.
|
|
||||||
pub return_type: BlockType,
|
|
||||||
/// Local variables.
|
|
||||||
pub locals: Vec<RuntimeValue>,
|
|
||||||
/// Values stack.
|
|
||||||
pub value_stack: ValueStack,
|
|
||||||
/// Current instruction position.
|
/// Current instruction position.
|
||||||
pub position: usize,
|
pub position: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionContext {
|
impl FunctionContext {
|
||||||
pub fn new(function: FuncRef, value_stack_limit: usize, signature: &Signature, args: Vec<RuntimeValue>) -> Self {
|
pub fn new(function: FuncRef) -> Self {
|
||||||
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"),
|
||||||
FuncInstanceInternal::Host { .. } => panic!("Host functions can't be called as internally defined functions; Thus FunctionContext can be created only with internally defined functions; qed"),
|
FuncInstanceInternal::Host { .. } => panic!("Host functions can't be called as internally defined functions; Thus FunctionContext can be created only with internally defined functions; qed"),
|
||||||
|
@ -1032,32 +1048,25 @@ impl FunctionContext {
|
||||||
is_initialized: false,
|
is_initialized: false,
|
||||||
function: function,
|
function: function,
|
||||||
module: ModuleRef(module),
|
module: ModuleRef(module),
|
||||||
return_type: signature.return_type().map(|vt| BlockType::Value(vt.into_elements())).unwrap_or(BlockType::NoResult),
|
|
||||||
value_stack: ValueStack::with_limit(value_stack_limit),
|
|
||||||
locals: args,
|
|
||||||
position: 0,
|
position: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn nested(&mut self, function: FuncRef) -> Result<Self, TrapKind> {
|
pub fn nested(&mut self, function: FuncRef) -> Result<Self, TrapKind> {
|
||||||
let (function_locals, module, function_return_type) = {
|
let module = {
|
||||||
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"),
|
||||||
FuncInstanceInternal::Host { .. } => panic!("Host functions can't be called as internally defined functions; Thus FunctionContext can be created only with internally defined functions; qed"),
|
FuncInstanceInternal::Host { .. } => panic!("Host functions can't be called as internally defined functions; Thus FunctionContext can be created only with internally defined functions; qed"),
|
||||||
};
|
};
|
||||||
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);
|
module
|
||||||
(function_locals, module, function_return_type)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(FunctionContext {
|
Ok(FunctionContext {
|
||||||
is_initialized: false,
|
is_initialized: false,
|
||||||
function: function,
|
function: function,
|
||||||
module: ModuleRef(module),
|
module: ModuleRef(module),
|
||||||
return_type: function_return_type,
|
|
||||||
value_stack: ValueStack::with_limit(self.value_stack.limit() - self.value_stack.len()),
|
|
||||||
locals: function_locals,
|
|
||||||
position: 0,
|
position: 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1066,40 +1075,28 @@ impl FunctionContext {
|
||||||
self.is_initialized
|
self.is_initialized
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initialize(&mut self, locals: &[Local]) {
|
pub fn initialize(&mut self, locals: &[Local], value_stack: &mut ValueStack) -> Result<(), TrapKind> {
|
||||||
debug_assert!(!self.is_initialized);
|
debug_assert!(!self.is_initialized);
|
||||||
self.is_initialized = true;
|
|
||||||
|
|
||||||
let locals = locals.iter()
|
let locals = locals.iter()
|
||||||
.flat_map(|l| repeat(l.value_type()).take(l.count() as usize))
|
.flat_map(|l| repeat(l.value_type()).take(l.count() as usize))
|
||||||
.map(::types::ValueType::from_elements)
|
.map(::types::ValueType::from_elements)
|
||||||
.map(RuntimeValue::default)
|
.map(RuntimeValue::default)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
self.locals.extend(locals);
|
|
||||||
|
// TODO: Replace with extend.
|
||||||
|
for local in locals {
|
||||||
|
value_stack.push(local)
|
||||||
|
.map_err(|_| TrapKind::StackOverflow)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.is_initialized = true;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn module(&self) -> ModuleRef {
|
pub fn module(&self) -> ModuleRef {
|
||||||
self.module.clone()
|
self.module.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_local(&mut self, index: usize, value: RuntimeValue) {
|
|
||||||
let l = self.locals.get_mut(index).expect("Due to validation local should exists");
|
|
||||||
*l = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_local(&mut self, index: usize) -> RuntimeValue {
|
|
||||||
self.locals.get(index)
|
|
||||||
.cloned()
|
|
||||||
.expect("Due to validation local should exists")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn value_stack(&self) -> &ValueStack {
|
|
||||||
&self.value_stack
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn value_stack_mut(&mut self) -> &mut ValueStack {
|
|
||||||
&mut self.value_stack
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for FunctionContext {
|
impl fmt::Debug for FunctionContext {
|
||||||
|
@ -1153,6 +1150,7 @@ pub fn check_function_args(signature: &Signature, args: &[RuntimeValue]) -> Resu
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct ValueStack {
|
struct ValueStack {
|
||||||
stack_with_limit: StackWithLimit<RuntimeValue>,
|
stack_with_limit: StackWithLimit<RuntimeValue>,
|
||||||
}
|
}
|
||||||
|
@ -1190,6 +1188,12 @@ impl ValueStack {
|
||||||
(left, mid, right)
|
(left, mid, right)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pick_mut(&mut self, depth: usize) -> &mut RuntimeValue {
|
||||||
|
self.stack_with_limit
|
||||||
|
.pick_mut(depth)
|
||||||
|
.expect("Due to validation this should succeed")
|
||||||
|
}
|
||||||
|
|
||||||
fn pop(&mut self) -> RuntimeValue {
|
fn pop(&mut self) -> RuntimeValue {
|
||||||
self.stack_with_limit.pop().expect("Due to validation stack shouldn't be empty")
|
self.stack_with_limit.pop().expect("Due to validation stack shouldn't be empty")
|
||||||
}
|
}
|
||||||
|
|
|
@ -307,18 +307,18 @@ impl Validator {
|
||||||
context.pop_label()?;
|
context.pop_label()?;
|
||||||
},
|
},
|
||||||
Br(depth) => {
|
Br(depth) => {
|
||||||
|
Validator::validate_br(context, depth)?;
|
||||||
|
|
||||||
let target = context.require_target(depth)?;
|
let target = context.require_target(depth)?;
|
||||||
context.sink.emit_br(target);
|
context.sink.emit_br(target);
|
||||||
|
|
||||||
Validator::validate_br(context, depth)?;
|
|
||||||
|
|
||||||
return Ok(InstructionOutcome::Unreachable);
|
return Ok(InstructionOutcome::Unreachable);
|
||||||
},
|
},
|
||||||
BrIf(depth) => {
|
BrIf(depth) => {
|
||||||
|
Validator::validate_br_if(context, depth)?;
|
||||||
|
|
||||||
let target = context.require_target(depth)?;
|
let target = context.require_target(depth)?;
|
||||||
context.sink.emit_br_nez(target);
|
context.sink.emit_br_nez(target);
|
||||||
|
|
||||||
Validator::validate_br_if(context, depth)?;
|
|
||||||
},
|
},
|
||||||
BrTable(ref table, default) => {
|
BrTable(ref table, default) => {
|
||||||
Validator::validate_br_table(context, table, default)?;
|
Validator::validate_br_table(context, table, default)?;
|
||||||
|
|
|
@ -628,8 +628,8 @@ fn if_else_branch_from_true_branch() {
|
||||||
isa::Instruction::I32Const(1),
|
isa::Instruction::I32Const(1),
|
||||||
isa::Instruction::BrIfNez(isa::Target {
|
isa::Instruction::BrIfNez(isa::Target {
|
||||||
dst_pc: 9,
|
dst_pc: 9,
|
||||||
drop: 1, // TODO: Is this correct?
|
drop: 0,
|
||||||
keep: 1, // TODO: Is this correct?
|
keep: 1,
|
||||||
}),
|
}),
|
||||||
isa::Instruction::Drop,
|
isa::Instruction::Drop,
|
||||||
isa::Instruction::I32Const(2),
|
isa::Instruction::I32Const(2),
|
||||||
|
@ -686,7 +686,7 @@ fn if_else_branch_from_false_branch() {
|
||||||
isa::Instruction::I32Const(1),
|
isa::Instruction::I32Const(1),
|
||||||
isa::Instruction::BrIfNez(isa::Target {
|
isa::Instruction::BrIfNez(isa::Target {
|
||||||
dst_pc: 9,
|
dst_pc: 9,
|
||||||
drop: 1, // TODO: Is this correct?
|
drop: 0,
|
||||||
keep: 1,
|
keep: 1,
|
||||||
}),
|
}),
|
||||||
isa::Instruction::Drop,
|
isa::Instruction::Drop,
|
||||||
|
@ -720,7 +720,7 @@ fn loop_() {
|
||||||
isa::Instruction::I32Const(1),
|
isa::Instruction::I32Const(1),
|
||||||
isa::Instruction::BrIfNez(isa::Target {
|
isa::Instruction::BrIfNez(isa::Target {
|
||||||
dst_pc: 0,
|
dst_pc: 0,
|
||||||
drop: 1,
|
drop: 0,
|
||||||
keep: 0,
|
keep: 0,
|
||||||
}),
|
}),
|
||||||
isa::Instruction::I32Const(2),
|
isa::Instruction::I32Const(2),
|
||||||
|
@ -840,7 +840,6 @@ fn brtable_returns_result() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn wabt_example() {
|
fn wabt_example() {
|
||||||
let code = compile(r#"
|
let code = compile(r#"
|
||||||
|
@ -864,7 +863,7 @@ fn wabt_example() {
|
||||||
isa::Instruction::BrIfNez(isa::Target {
|
isa::Instruction::BrIfNez(isa::Target {
|
||||||
dst_pc: 4,
|
dst_pc: 4,
|
||||||
keep: 0,
|
keep: 0,
|
||||||
drop: 1,
|
drop: 0,
|
||||||
}),
|
}),
|
||||||
isa::Instruction::I32Const(1),
|
isa::Instruction::I32Const(1),
|
||||||
isa::Instruction::Return {
|
isa::Instruction::Return {
|
||||||
|
@ -883,3 +882,4 @@ fn wabt_example() {
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue