WIP 2
This commit is contained in:
parent
5653e2809f
commit
d0e13db6f2
15
src/isa.rs
15
src/isa.rs
|
@ -51,17 +51,13 @@ pub struct Target {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Instruction {
|
pub enum Instruction {
|
||||||
/// Push a local variable or an argument from the specified depth.
|
/// Push a local variable or an argument from the specified depth.
|
||||||
GetLocal {
|
GetLocal(u32),
|
||||||
depth: u32
|
|
||||||
},
|
|
||||||
|
|
||||||
/// Pop a value and put it in at the specified depth.
|
/// Pop a value and put it in at the specified depth.
|
||||||
SetLocal {
|
SetLocal(u32),
|
||||||
depth: u32
|
|
||||||
},
|
|
||||||
|
|
||||||
/// Copy a value to the specified depth.
|
/// Copy a value to the specified depth.
|
||||||
TeeLocal { depth: u32 },
|
TeeLocal(u32),
|
||||||
|
|
||||||
/// Similar to the Wasm ones, but instead of a label depth
|
/// Similar to the Wasm ones, but instead of a label depth
|
||||||
/// they specify direct PC.
|
/// they specify direct PC.
|
||||||
|
@ -75,7 +71,10 @@ pub enum Instruction {
|
||||||
BrTable(Box<[Target]>),
|
BrTable(Box<[Target]>),
|
||||||
|
|
||||||
Unreachable,
|
Unreachable,
|
||||||
Return,
|
Return {
|
||||||
|
drop: u32,
|
||||||
|
keep: u8,
|
||||||
|
},
|
||||||
|
|
||||||
Call(u32),
|
Call(u32),
|
||||||
CallIndirect(u32),
|
CallIndirect(u32),
|
||||||
|
|
545
src/runner.rs
545
src/runner.rs
|
@ -3,8 +3,8 @@ use std::ops;
|
||||||
use std::{u32, usize};
|
use std::{u32, usize};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::VecDeque;
|
||||||
use parity_wasm::elements::{Opcode, BlockType, Local};
|
use parity_wasm::elements::{BlockType, Local};
|
||||||
use {Error, Trap, TrapKind, Signature};
|
use {Error, Trap, TrapKind, Signature};
|
||||||
use module::ModuleRef;
|
use module::ModuleRef;
|
||||||
use func::{FuncRef, FuncInstance, FuncInstanceInternal};
|
use func::{FuncRef, FuncInstance, FuncInstanceInternal};
|
||||||
|
@ -13,10 +13,11 @@ use value::{
|
||||||
ArithmeticOps, Integer, Float, LittleEndianConvert, TransmuteInto,
|
ArithmeticOps, Integer, Float, LittleEndianConvert, TransmuteInto,
|
||||||
};
|
};
|
||||||
use host::Externals;
|
use host::Externals;
|
||||||
use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX, BlockFrame, BlockFrameType};
|
use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX};
|
||||||
use common::stack::StackWithLimit;
|
use common::stack::StackWithLimit;
|
||||||
use memory_units::Pages;
|
use memory_units::Pages;
|
||||||
use nan_preserving_float::{F32, F64};
|
use nan_preserving_float::{F32, F64};
|
||||||
|
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;
|
||||||
|
@ -32,12 +33,10 @@ pub struct Interpreter<'a, E: Externals + 'a> {
|
||||||
pub enum InstructionOutcome {
|
pub enum InstructionOutcome {
|
||||||
/// Continue with next instruction.
|
/// Continue with next instruction.
|
||||||
RunNextInstruction,
|
RunNextInstruction,
|
||||||
/// Branch to given frame.
|
/// Branch to an instruction at the given position.
|
||||||
Branch(usize),
|
Branch(isa::Target),
|
||||||
/// Execute function call.
|
/// Execute function call.
|
||||||
ExecuteCall(FuncRef),
|
ExecuteCall(FuncRef),
|
||||||
/// End current frame.
|
|
||||||
End,
|
|
||||||
/// Return from current function block.
|
/// Return from current function block.
|
||||||
Return,
|
Return,
|
||||||
}
|
}
|
||||||
|
@ -61,7 +60,6 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
let context = FunctionContext::new(
|
let context = FunctionContext::new(
|
||||||
func.clone(),
|
func.clone(),
|
||||||
DEFAULT_VALUE_STACK_LIMIT,
|
DEFAULT_VALUE_STACK_LIMIT,
|
||||||
DEFAULT_FRAME_STACK_LIMIT,
|
|
||||||
func.signature(),
|
func.signature(),
|
||||||
args.into_iter().cloned().collect(),
|
args.into_iter().cloned().collect(),
|
||||||
);
|
);
|
||||||
|
@ -84,10 +82,12 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
if !function_context.is_initialized() {
|
if !function_context.is_initialized() {
|
||||||
let return_type = function_context.return_type;
|
let return_type = function_context.return_type;
|
||||||
function_context.initialize(&function_body.locals);
|
function_context.initialize(&function_body.locals);
|
||||||
function_context.push_frame(BlockFrameType::Function, return_type).map_err(Trap::new)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let function_return = self.do_run_function(&mut function_context, function_body.opcodes.elements(), &function_body.labels).map_err(Trap::new)?;
|
let function_return = self.do_run_function(
|
||||||
|
&mut function_context,
|
||||||
|
&function_body.code.code,
|
||||||
|
).map_err(Trap::new)?;
|
||||||
|
|
||||||
match function_return {
|
match function_return {
|
||||||
RunResult::Return(return_value) => {
|
RunResult::Return(return_value) => {
|
||||||
|
@ -127,33 +127,32 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_run_function(&mut self, function_context: &mut FunctionContext, function_body: &[Opcode]) -> Result<RunResult, TrapKind> {
|
fn do_run_function(&mut self, function_context: &mut FunctionContext, instructions: &[isa::Instruction]) -> Result<RunResult, TrapKind> {
|
||||||
loop {
|
loop {
|
||||||
let instruction = &function_body[function_context.position];
|
let instruction = &instructions[function_context.position];
|
||||||
|
|
||||||
match self.run_instruction(function_context, function_labels, instruction)? {
|
match self.run_instruction(function_context, instruction)? {
|
||||||
InstructionOutcome::RunNextInstruction => function_context.position += 1,
|
InstructionOutcome::RunNextInstruction => function_context.position += 1,
|
||||||
InstructionOutcome::Branch(mut index) => {
|
InstructionOutcome::Branch(target) => {
|
||||||
// discard index - 1 blocks
|
function_context.position = target.dst_pc as usize;
|
||||||
while index >= 1 {
|
|
||||||
function_context.discard_frame();
|
|
||||||
index -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
function_context.pop_frame(true)?;
|
assert!(target.keep <= 1);
|
||||||
if function_context.frame_stack().is_empty() {
|
let keep = if target.keep == 1 {
|
||||||
break;
|
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::End => {
|
|
||||||
if function_context.frame_stack().is_empty() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
InstructionOutcome::Return => break,
|
InstructionOutcome::Return => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,197 +168,193 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_instruction(&mut self, context: &mut FunctionContext, labels: &HashMap<usize, usize>, opcode: &Opcode) -> Result<InstructionOutcome, TrapKind> {
|
fn run_instruction(&mut self, context: &mut FunctionContext, instruction: &isa::Instruction) -> Result<InstructionOutcome, TrapKind> {
|
||||||
match opcode {
|
match instruction {
|
||||||
&Opcode::Unreachable => self.run_unreachable(context),
|
&isa::Instruction::Unreachable => self.run_unreachable(context),
|
||||||
&Opcode::Nop => self.run_nop(context),
|
|
||||||
&Opcode::Block(block_type) => self.run_block(context, labels, block_type),
|
|
||||||
&Opcode::Loop(block_type) => self.run_loop(context, labels, block_type),
|
|
||||||
&Opcode::If(block_type) => self.run_if(context, labels, block_type),
|
|
||||||
&Opcode::Else => self.run_else(context, labels),
|
|
||||||
&Opcode::End => self.run_end(context),
|
|
||||||
&Opcode::Br(idx) => self.run_br(context, idx),
|
|
||||||
&Opcode::BrIf(idx) => self.run_br_if(context, idx),
|
|
||||||
&Opcode::BrTable(ref table, default) => self.run_br_table(context, table, default),
|
|
||||||
&Opcode::Return => self.run_return(context),
|
|
||||||
|
|
||||||
&Opcode::Call(index) => self.run_call(context, index),
|
&isa::Instruction::Br(ref target) => self.run_br(context, target.clone()),
|
||||||
&Opcode::CallIndirect(index, _reserved) => self.run_call_indirect(context, index),
|
&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::BrTable(ref targets) => self.run_br_table(context, targets),
|
||||||
|
&isa::Instruction::Return { drop, keep } => self.run_return(context),
|
||||||
|
|
||||||
&Opcode::Drop => self.run_drop(context),
|
&isa::Instruction::Call(index) => self.run_call(context, index),
|
||||||
&Opcode::Select => self.run_select(context),
|
&isa::Instruction::CallIndirect(index) => self.run_call_indirect(context, index),
|
||||||
|
|
||||||
&Opcode::GetLocal(index) => self.run_get_local(context, index),
|
&isa::Instruction::Drop => self.run_drop(context),
|
||||||
&Opcode::SetLocal(index) => self.run_set_local(context, index),
|
&isa::Instruction::Select => self.run_select(context),
|
||||||
&Opcode::TeeLocal(index) => self.run_tee_local(context, index),
|
|
||||||
&Opcode::GetGlobal(index) => self.run_get_global(context, index),
|
|
||||||
&Opcode::SetGlobal(index) => self.run_set_global(context, index),
|
|
||||||
|
|
||||||
&Opcode::I32Load(align, offset) => self.run_load::<i32>(context, align, offset),
|
&isa::Instruction::GetLocal(depth) => self.run_get_local(context, depth),
|
||||||
&Opcode::I64Load(align, offset) => self.run_load::<i64>(context, align, offset),
|
&isa::Instruction::SetLocal(depth) => self.run_set_local(context, depth),
|
||||||
&Opcode::F32Load(align, offset) => self.run_load::<F32>(context, align, offset),
|
&isa::Instruction::TeeLocal(depth) => self.run_tee_local(context, depth),
|
||||||
&Opcode::F64Load(align, offset) => self.run_load::<F64>(context, align, offset),
|
&isa::Instruction::GetGlobal(index) => self.run_get_global(context, index),
|
||||||
&Opcode::I32Load8S(align, offset) => self.run_load_extend::<i8, i32>(context, align, offset),
|
&isa::Instruction::SetGlobal(index) => self.run_set_global(context, index),
|
||||||
&Opcode::I32Load8U(align, offset) => self.run_load_extend::<u8, i32>(context, align, offset),
|
|
||||||
&Opcode::I32Load16S(align, offset) => self.run_load_extend::<i16, i32>(context, align, offset),
|
|
||||||
&Opcode::I32Load16U(align, offset) => self.run_load_extend::<u16, i32>(context, align, offset),
|
|
||||||
&Opcode::I64Load8S(align, offset) => self.run_load_extend::<i8, i64>(context, align, offset),
|
|
||||||
&Opcode::I64Load8U(align, offset) => self.run_load_extend::<u8, i64>(context, align, offset),
|
|
||||||
&Opcode::I64Load16S(align, offset) => self.run_load_extend::<i16, i64>(context, align, offset),
|
|
||||||
&Opcode::I64Load16U(align, offset) => self.run_load_extend::<u16, i64>(context, align, offset),
|
|
||||||
&Opcode::I64Load32S(align, offset) => self.run_load_extend::<i32, i64>(context, align, offset),
|
|
||||||
&Opcode::I64Load32U(align, offset) => self.run_load_extend::<u32, i64>(context, align, offset),
|
|
||||||
|
|
||||||
&Opcode::I32Store(align, offset) => self.run_store::<i32>(context, align, offset),
|
&isa::Instruction::I32Load(offset) => self.run_load::<i32>(context, offset),
|
||||||
&Opcode::I64Store(align, offset) => self.run_store::<i64>(context, align, offset),
|
&isa::Instruction::I64Load(offset) => self.run_load::<i64>(context, offset),
|
||||||
&Opcode::F32Store(align, offset) => self.run_store::<F32>(context, align, offset),
|
&isa::Instruction::F32Load(offset) => self.run_load::<F32>(context, offset),
|
||||||
&Opcode::F64Store(align, offset) => self.run_store::<F64>(context, align, offset),
|
&isa::Instruction::F64Load(offset) => self.run_load::<F64>(context, offset),
|
||||||
&Opcode::I32Store8(align, offset) => self.run_store_wrap::<i32, i8>(context, align, offset),
|
&isa::Instruction::I32Load8S(offset) => self.run_load_extend::<i8, i32>(context, offset),
|
||||||
&Opcode::I32Store16(align, offset) => self.run_store_wrap::<i32, i16>(context, align, offset),
|
&isa::Instruction::I32Load8U(offset) => self.run_load_extend::<u8, i32>(context, offset),
|
||||||
&Opcode::I64Store8(align, offset) => self.run_store_wrap::<i64, i8>(context, align, offset),
|
&isa::Instruction::I32Load16S(offset) => self.run_load_extend::<i16, i32>(context, offset),
|
||||||
&Opcode::I64Store16(align, offset) => self.run_store_wrap::<i64, i16>(context, align, offset),
|
&isa::Instruction::I32Load16U(offset) => self.run_load_extend::<u16, i32>(context, offset),
|
||||||
&Opcode::I64Store32(align, offset) => self.run_store_wrap::<i64, i32>(context, align, offset),
|
&isa::Instruction::I64Load8S(offset) => self.run_load_extend::<i8, i64>(context, offset),
|
||||||
|
&isa::Instruction::I64Load8U(offset) => self.run_load_extend::<u8, i64>(context, offset),
|
||||||
|
&isa::Instruction::I64Load16S(offset) => self.run_load_extend::<i16, i64>(context, offset),
|
||||||
|
&isa::Instruction::I64Load16U(offset) => self.run_load_extend::<u16, i64>(context, offset),
|
||||||
|
&isa::Instruction::I64Load32S(offset) => self.run_load_extend::<i32, i64>(context, offset),
|
||||||
|
&isa::Instruction::I64Load32U(offset) => self.run_load_extend::<u32, i64>(context, offset),
|
||||||
|
|
||||||
&Opcode::CurrentMemory(_) => self.run_current_memory(context),
|
&isa::Instruction::I32Store(offset) => self.run_store::<i32>(context, offset),
|
||||||
&Opcode::GrowMemory(_) => self.run_grow_memory(context),
|
&isa::Instruction::I64Store(offset) => self.run_store::<i64>(context, offset),
|
||||||
|
&isa::Instruction::F32Store(offset) => self.run_store::<F32>(context, offset),
|
||||||
|
&isa::Instruction::F64Store(offset) => self.run_store::<F64>(context, offset),
|
||||||
|
&isa::Instruction::I32Store8(offset) => self.run_store_wrap::<i32, i8>(context, offset),
|
||||||
|
&isa::Instruction::I32Store16(offset) => self.run_store_wrap::<i32, i16>(context, offset),
|
||||||
|
&isa::Instruction::I64Store8(offset) => self.run_store_wrap::<i64, i8>(context, offset),
|
||||||
|
&isa::Instruction::I64Store16(offset) => self.run_store_wrap::<i64, i16>(context, offset),
|
||||||
|
&isa::Instruction::I64Store32(offset) => self.run_store_wrap::<i64, i32>(context, offset),
|
||||||
|
|
||||||
&Opcode::I32Const(val) => self.run_const(context, val.into()),
|
&isa::Instruction::CurrentMemory => self.run_current_memory(context),
|
||||||
&Opcode::I64Const(val) => self.run_const(context, val.into()),
|
&isa::Instruction::GrowMemory => self.run_grow_memory(context),
|
||||||
&Opcode::F32Const(val) => self.run_const(context, RuntimeValue::decode_f32(val)),
|
|
||||||
&Opcode::F64Const(val) => self.run_const(context, RuntimeValue::decode_f64(val)),
|
|
||||||
|
|
||||||
&Opcode::I32Eqz => self.run_eqz::<i32>(context),
|
&isa::Instruction::I32Const(val) => self.run_const(context, val.into()),
|
||||||
&Opcode::I32Eq => self.run_eq::<i32>(context),
|
&isa::Instruction::I64Const(val) => self.run_const(context, val.into()),
|
||||||
&Opcode::I32Ne => self.run_ne::<i32>(context),
|
&isa::Instruction::F32Const(val) => self.run_const(context, RuntimeValue::decode_f32(val)),
|
||||||
&Opcode::I32LtS => self.run_lt::<i32>(context),
|
&isa::Instruction::F64Const(val) => self.run_const(context, RuntimeValue::decode_f64(val)),
|
||||||
&Opcode::I32LtU => self.run_lt::<u32>(context),
|
|
||||||
&Opcode::I32GtS => self.run_gt::<i32>(context),
|
|
||||||
&Opcode::I32GtU => self.run_gt::<u32>(context),
|
|
||||||
&Opcode::I32LeS => self.run_lte::<i32>(context),
|
|
||||||
&Opcode::I32LeU => self.run_lte::<u32>(context),
|
|
||||||
&Opcode::I32GeS => self.run_gte::<i32>(context),
|
|
||||||
&Opcode::I32GeU => self.run_gte::<u32>(context),
|
|
||||||
|
|
||||||
&Opcode::I64Eqz => self.run_eqz::<i64>(context),
|
&isa::Instruction::I32Eqz => self.run_eqz::<i32>(context),
|
||||||
&Opcode::I64Eq => self.run_eq::<i64>(context),
|
&isa::Instruction::I32Eq => self.run_eq::<i32>(context),
|
||||||
&Opcode::I64Ne => self.run_ne::<i64>(context),
|
&isa::Instruction::I32Ne => self.run_ne::<i32>(context),
|
||||||
&Opcode::I64LtS => self.run_lt::<i64>(context),
|
&isa::Instruction::I32LtS => self.run_lt::<i32>(context),
|
||||||
&Opcode::I64LtU => self.run_lt::<u64>(context),
|
&isa::Instruction::I32LtU => self.run_lt::<u32>(context),
|
||||||
&Opcode::I64GtS => self.run_gt::<i64>(context),
|
&isa::Instruction::I32GtS => self.run_gt::<i32>(context),
|
||||||
&Opcode::I64GtU => self.run_gt::<u64>(context),
|
&isa::Instruction::I32GtU => self.run_gt::<u32>(context),
|
||||||
&Opcode::I64LeS => self.run_lte::<i64>(context),
|
&isa::Instruction::I32LeS => self.run_lte::<i32>(context),
|
||||||
&Opcode::I64LeU => self.run_lte::<u64>(context),
|
&isa::Instruction::I32LeU => self.run_lte::<u32>(context),
|
||||||
&Opcode::I64GeS => self.run_gte::<i64>(context),
|
&isa::Instruction::I32GeS => self.run_gte::<i32>(context),
|
||||||
&Opcode::I64GeU => self.run_gte::<u64>(context),
|
&isa::Instruction::I32GeU => self.run_gte::<u32>(context),
|
||||||
|
|
||||||
&Opcode::F32Eq => self.run_eq::<F32>(context),
|
&isa::Instruction::I64Eqz => self.run_eqz::<i64>(context),
|
||||||
&Opcode::F32Ne => self.run_ne::<F32>(context),
|
&isa::Instruction::I64Eq => self.run_eq::<i64>(context),
|
||||||
&Opcode::F32Lt => self.run_lt::<F32>(context),
|
&isa::Instruction::I64Ne => self.run_ne::<i64>(context),
|
||||||
&Opcode::F32Gt => self.run_gt::<F32>(context),
|
&isa::Instruction::I64LtS => self.run_lt::<i64>(context),
|
||||||
&Opcode::F32Le => self.run_lte::<F32>(context),
|
&isa::Instruction::I64LtU => self.run_lt::<u64>(context),
|
||||||
&Opcode::F32Ge => self.run_gte::<F32>(context),
|
&isa::Instruction::I64GtS => self.run_gt::<i64>(context),
|
||||||
|
&isa::Instruction::I64GtU => self.run_gt::<u64>(context),
|
||||||
|
&isa::Instruction::I64LeS => self.run_lte::<i64>(context),
|
||||||
|
&isa::Instruction::I64LeU => self.run_lte::<u64>(context),
|
||||||
|
&isa::Instruction::I64GeS => self.run_gte::<i64>(context),
|
||||||
|
&isa::Instruction::I64GeU => self.run_gte::<u64>(context),
|
||||||
|
|
||||||
&Opcode::F64Eq => self.run_eq::<F64>(context),
|
&isa::Instruction::F32Eq => self.run_eq::<F32>(context),
|
||||||
&Opcode::F64Ne => self.run_ne::<F64>(context),
|
&isa::Instruction::F32Ne => self.run_ne::<F32>(context),
|
||||||
&Opcode::F64Lt => self.run_lt::<F64>(context),
|
&isa::Instruction::F32Lt => self.run_lt::<F32>(context),
|
||||||
&Opcode::F64Gt => self.run_gt::<F64>(context),
|
&isa::Instruction::F32Gt => self.run_gt::<F32>(context),
|
||||||
&Opcode::F64Le => self.run_lte::<F64>(context),
|
&isa::Instruction::F32Le => self.run_lte::<F32>(context),
|
||||||
&Opcode::F64Ge => self.run_gte::<F64>(context),
|
&isa::Instruction::F32Ge => self.run_gte::<F32>(context),
|
||||||
|
|
||||||
&Opcode::I32Clz => self.run_clz::<i32>(context),
|
&isa::Instruction::F64Eq => self.run_eq::<F64>(context),
|
||||||
&Opcode::I32Ctz => self.run_ctz::<i32>(context),
|
&isa::Instruction::F64Ne => self.run_ne::<F64>(context),
|
||||||
&Opcode::I32Popcnt => self.run_popcnt::<i32>(context),
|
&isa::Instruction::F64Lt => self.run_lt::<F64>(context),
|
||||||
&Opcode::I32Add => self.run_add::<i32>(context),
|
&isa::Instruction::F64Gt => self.run_gt::<F64>(context),
|
||||||
&Opcode::I32Sub => self.run_sub::<i32>(context),
|
&isa::Instruction::F64Le => self.run_lte::<F64>(context),
|
||||||
&Opcode::I32Mul => self.run_mul::<i32>(context),
|
&isa::Instruction::F64Ge => self.run_gte::<F64>(context),
|
||||||
&Opcode::I32DivS => self.run_div::<i32, i32>(context),
|
|
||||||
&Opcode::I32DivU => self.run_div::<i32, u32>(context),
|
|
||||||
&Opcode::I32RemS => self.run_rem::<i32, i32>(context),
|
|
||||||
&Opcode::I32RemU => self.run_rem::<i32, u32>(context),
|
|
||||||
&Opcode::I32And => self.run_and::<i32>(context),
|
|
||||||
&Opcode::I32Or => self.run_or::<i32>(context),
|
|
||||||
&Opcode::I32Xor => self.run_xor::<i32>(context),
|
|
||||||
&Opcode::I32Shl => self.run_shl::<i32>(context, 0x1F),
|
|
||||||
&Opcode::I32ShrS => self.run_shr::<i32, i32>(context, 0x1F),
|
|
||||||
&Opcode::I32ShrU => self.run_shr::<i32, u32>(context, 0x1F),
|
|
||||||
&Opcode::I32Rotl => self.run_rotl::<i32>(context),
|
|
||||||
&Opcode::I32Rotr => self.run_rotr::<i32>(context),
|
|
||||||
|
|
||||||
&Opcode::I64Clz => self.run_clz::<i64>(context),
|
&isa::Instruction::I32Clz => self.run_clz::<i32>(context),
|
||||||
&Opcode::I64Ctz => self.run_ctz::<i64>(context),
|
&isa::Instruction::I32Ctz => self.run_ctz::<i32>(context),
|
||||||
&Opcode::I64Popcnt => self.run_popcnt::<i64>(context),
|
&isa::Instruction::I32Popcnt => self.run_popcnt::<i32>(context),
|
||||||
&Opcode::I64Add => self.run_add::<i64>(context),
|
&isa::Instruction::I32Add => self.run_add::<i32>(context),
|
||||||
&Opcode::I64Sub => self.run_sub::<i64>(context),
|
&isa::Instruction::I32Sub => self.run_sub::<i32>(context),
|
||||||
&Opcode::I64Mul => self.run_mul::<i64>(context),
|
&isa::Instruction::I32Mul => self.run_mul::<i32>(context),
|
||||||
&Opcode::I64DivS => self.run_div::<i64, i64>(context),
|
&isa::Instruction::I32DivS => self.run_div::<i32, i32>(context),
|
||||||
&Opcode::I64DivU => self.run_div::<i64, u64>(context),
|
&isa::Instruction::I32DivU => self.run_div::<i32, u32>(context),
|
||||||
&Opcode::I64RemS => self.run_rem::<i64, i64>(context),
|
&isa::Instruction::I32RemS => self.run_rem::<i32, i32>(context),
|
||||||
&Opcode::I64RemU => self.run_rem::<i64, u64>(context),
|
&isa::Instruction::I32RemU => self.run_rem::<i32, u32>(context),
|
||||||
&Opcode::I64And => self.run_and::<i64>(context),
|
&isa::Instruction::I32And => self.run_and::<i32>(context),
|
||||||
&Opcode::I64Or => self.run_or::<i64>(context),
|
&isa::Instruction::I32Or => self.run_or::<i32>(context),
|
||||||
&Opcode::I64Xor => self.run_xor::<i64>(context),
|
&isa::Instruction::I32Xor => self.run_xor::<i32>(context),
|
||||||
&Opcode::I64Shl => self.run_shl::<i64>(context, 0x3F),
|
&isa::Instruction::I32Shl => self.run_shl::<i32>(context, 0x1F),
|
||||||
&Opcode::I64ShrS => self.run_shr::<i64, i64>(context, 0x3F),
|
&isa::Instruction::I32ShrS => self.run_shr::<i32, i32>(context, 0x1F),
|
||||||
&Opcode::I64ShrU => self.run_shr::<i64, u64>(context, 0x3F),
|
&isa::Instruction::I32ShrU => self.run_shr::<i32, u32>(context, 0x1F),
|
||||||
&Opcode::I64Rotl => self.run_rotl::<i64>(context),
|
&isa::Instruction::I32Rotl => self.run_rotl::<i32>(context),
|
||||||
&Opcode::I64Rotr => self.run_rotr::<i64>(context),
|
&isa::Instruction::I32Rotr => self.run_rotr::<i32>(context),
|
||||||
|
|
||||||
&Opcode::F32Abs => self.run_abs::<F32>(context),
|
&isa::Instruction::I64Clz => self.run_clz::<i64>(context),
|
||||||
&Opcode::F32Neg => self.run_neg::<F32>(context),
|
&isa::Instruction::I64Ctz => self.run_ctz::<i64>(context),
|
||||||
&Opcode::F32Ceil => self.run_ceil::<F32>(context),
|
&isa::Instruction::I64Popcnt => self.run_popcnt::<i64>(context),
|
||||||
&Opcode::F32Floor => self.run_floor::<F32>(context),
|
&isa::Instruction::I64Add => self.run_add::<i64>(context),
|
||||||
&Opcode::F32Trunc => self.run_trunc::<F32>(context),
|
&isa::Instruction::I64Sub => self.run_sub::<i64>(context),
|
||||||
&Opcode::F32Nearest => self.run_nearest::<F32>(context),
|
&isa::Instruction::I64Mul => self.run_mul::<i64>(context),
|
||||||
&Opcode::F32Sqrt => self.run_sqrt::<F32>(context),
|
&isa::Instruction::I64DivS => self.run_div::<i64, i64>(context),
|
||||||
&Opcode::F32Add => self.run_add::<F32>(context),
|
&isa::Instruction::I64DivU => self.run_div::<i64, u64>(context),
|
||||||
&Opcode::F32Sub => self.run_sub::<F32>(context),
|
&isa::Instruction::I64RemS => self.run_rem::<i64, i64>(context),
|
||||||
&Opcode::F32Mul => self.run_mul::<F32>(context),
|
&isa::Instruction::I64RemU => self.run_rem::<i64, u64>(context),
|
||||||
&Opcode::F32Div => self.run_div::<F32, F32>(context),
|
&isa::Instruction::I64And => self.run_and::<i64>(context),
|
||||||
&Opcode::F32Min => self.run_min::<F32>(context),
|
&isa::Instruction::I64Or => self.run_or::<i64>(context),
|
||||||
&Opcode::F32Max => self.run_max::<F32>(context),
|
&isa::Instruction::I64Xor => self.run_xor::<i64>(context),
|
||||||
&Opcode::F32Copysign => self.run_copysign::<F32>(context),
|
&isa::Instruction::I64Shl => self.run_shl::<i64>(context, 0x3F),
|
||||||
|
&isa::Instruction::I64ShrS => self.run_shr::<i64, i64>(context, 0x3F),
|
||||||
|
&isa::Instruction::I64ShrU => self.run_shr::<i64, u64>(context, 0x3F),
|
||||||
|
&isa::Instruction::I64Rotl => self.run_rotl::<i64>(context),
|
||||||
|
&isa::Instruction::I64Rotr => self.run_rotr::<i64>(context),
|
||||||
|
|
||||||
&Opcode::F64Abs => self.run_abs::<F64>(context),
|
&isa::Instruction::F32Abs => self.run_abs::<F32>(context),
|
||||||
&Opcode::F64Neg => self.run_neg::<F64>(context),
|
&isa::Instruction::F32Neg => self.run_neg::<F32>(context),
|
||||||
&Opcode::F64Ceil => self.run_ceil::<F64>(context),
|
&isa::Instruction::F32Ceil => self.run_ceil::<F32>(context),
|
||||||
&Opcode::F64Floor => self.run_floor::<F64>(context),
|
&isa::Instruction::F32Floor => self.run_floor::<F32>(context),
|
||||||
&Opcode::F64Trunc => self.run_trunc::<F64>(context),
|
&isa::Instruction::F32Trunc => self.run_trunc::<F32>(context),
|
||||||
&Opcode::F64Nearest => self.run_nearest::<F64>(context),
|
&isa::Instruction::F32Nearest => self.run_nearest::<F32>(context),
|
||||||
&Opcode::F64Sqrt => self.run_sqrt::<F64>(context),
|
&isa::Instruction::F32Sqrt => self.run_sqrt::<F32>(context),
|
||||||
&Opcode::F64Add => self.run_add::<F64>(context),
|
&isa::Instruction::F32Add => self.run_add::<F32>(context),
|
||||||
&Opcode::F64Sub => self.run_sub::<F64>(context),
|
&isa::Instruction::F32Sub => self.run_sub::<F32>(context),
|
||||||
&Opcode::F64Mul => self.run_mul::<F64>(context),
|
&isa::Instruction::F32Mul => self.run_mul::<F32>(context),
|
||||||
&Opcode::F64Div => self.run_div::<F64, F64>(context),
|
&isa::Instruction::F32Div => self.run_div::<F32, F32>(context),
|
||||||
&Opcode::F64Min => self.run_min::<F64>(context),
|
&isa::Instruction::F32Min => self.run_min::<F32>(context),
|
||||||
&Opcode::F64Max => self.run_max::<F64>(context),
|
&isa::Instruction::F32Max => self.run_max::<F32>(context),
|
||||||
&Opcode::F64Copysign => self.run_copysign::<F64>(context),
|
&isa::Instruction::F32Copysign => self.run_copysign::<F32>(context),
|
||||||
|
|
||||||
&Opcode::I32WrapI64 => self.run_wrap::<i64, i32>(context),
|
&isa::Instruction::F64Abs => self.run_abs::<F64>(context),
|
||||||
&Opcode::I32TruncSF32 => self.run_trunc_to_int::<F32, i32, i32>(context),
|
&isa::Instruction::F64Neg => self.run_neg::<F64>(context),
|
||||||
&Opcode::I32TruncUF32 => self.run_trunc_to_int::<F32, u32, i32>(context),
|
&isa::Instruction::F64Ceil => self.run_ceil::<F64>(context),
|
||||||
&Opcode::I32TruncSF64 => self.run_trunc_to_int::<F64, i32, i32>(context),
|
&isa::Instruction::F64Floor => self.run_floor::<F64>(context),
|
||||||
&Opcode::I32TruncUF64 => self.run_trunc_to_int::<F64, u32, i32>(context),
|
&isa::Instruction::F64Trunc => self.run_trunc::<F64>(context),
|
||||||
&Opcode::I64ExtendSI32 => self.run_extend::<i32, i64, i64>(context),
|
&isa::Instruction::F64Nearest => self.run_nearest::<F64>(context),
|
||||||
&Opcode::I64ExtendUI32 => self.run_extend::<u32, u64, i64>(context),
|
&isa::Instruction::F64Sqrt => self.run_sqrt::<F64>(context),
|
||||||
&Opcode::I64TruncSF32 => self.run_trunc_to_int::<F32, i64, i64>(context),
|
&isa::Instruction::F64Add => self.run_add::<F64>(context),
|
||||||
&Opcode::I64TruncUF32 => self.run_trunc_to_int::<F32, u64, i64>(context),
|
&isa::Instruction::F64Sub => self.run_sub::<F64>(context),
|
||||||
&Opcode::I64TruncSF64 => self.run_trunc_to_int::<F64, i64, i64>(context),
|
&isa::Instruction::F64Mul => self.run_mul::<F64>(context),
|
||||||
&Opcode::I64TruncUF64 => self.run_trunc_to_int::<F64, u64, i64>(context),
|
&isa::Instruction::F64Div => self.run_div::<F64, F64>(context),
|
||||||
&Opcode::F32ConvertSI32 => self.run_extend::<i32, F32, F32>(context),
|
&isa::Instruction::F64Min => self.run_min::<F64>(context),
|
||||||
&Opcode::F32ConvertUI32 => self.run_extend::<u32, F32, F32>(context),
|
&isa::Instruction::F64Max => self.run_max::<F64>(context),
|
||||||
&Opcode::F32ConvertSI64 => self.run_wrap::<i64, F32>(context),
|
&isa::Instruction::F64Copysign => self.run_copysign::<F64>(context),
|
||||||
&Opcode::F32ConvertUI64 => self.run_wrap::<u64, F32>(context),
|
|
||||||
&Opcode::F32DemoteF64 => self.run_wrap::<F64, F32>(context),
|
|
||||||
&Opcode::F64ConvertSI32 => self.run_extend::<i32, F64, F64>(context),
|
|
||||||
&Opcode::F64ConvertUI32 => self.run_extend::<u32, F64, F64>(context),
|
|
||||||
&Opcode::F64ConvertSI64 => self.run_extend::<i64, F64, F64>(context),
|
|
||||||
&Opcode::F64ConvertUI64 => self.run_extend::<u64, F64, F64>(context),
|
|
||||||
&Opcode::F64PromoteF32 => self.run_extend::<F32, F64, F64>(context),
|
|
||||||
|
|
||||||
&Opcode::I32ReinterpretF32 => self.run_reinterpret::<F32, i32>(context),
|
&isa::Instruction::I32WrapI64 => self.run_wrap::<i64, i32>(context),
|
||||||
&Opcode::I64ReinterpretF64 => self.run_reinterpret::<F64, i64>(context),
|
&isa::Instruction::I32TruncSF32 => self.run_trunc_to_int::<F32, i32, i32>(context),
|
||||||
&Opcode::F32ReinterpretI32 => self.run_reinterpret::<i32, F32>(context),
|
&isa::Instruction::I32TruncUF32 => self.run_trunc_to_int::<F32, u32, i32>(context),
|
||||||
&Opcode::F64ReinterpretI64 => self.run_reinterpret::<i64, F64>(context),
|
&isa::Instruction::I32TruncSF64 => self.run_trunc_to_int::<F64, i32, i32>(context),
|
||||||
|
&isa::Instruction::I32TruncUF64 => self.run_trunc_to_int::<F64, u32, i32>(context),
|
||||||
|
&isa::Instruction::I64ExtendSI32 => self.run_extend::<i32, i64, i64>(context),
|
||||||
|
&isa::Instruction::I64ExtendUI32 => self.run_extend::<u32, u64, i64>(context),
|
||||||
|
&isa::Instruction::I64TruncSF32 => self.run_trunc_to_int::<F32, i64, i64>(context),
|
||||||
|
&isa::Instruction::I64TruncUF32 => self.run_trunc_to_int::<F32, u64, i64>(context),
|
||||||
|
&isa::Instruction::I64TruncSF64 => self.run_trunc_to_int::<F64, i64, i64>(context),
|
||||||
|
&isa::Instruction::I64TruncUF64 => self.run_trunc_to_int::<F64, u64, i64>(context),
|
||||||
|
&isa::Instruction::F32ConvertSI32 => self.run_extend::<i32, F32, F32>(context),
|
||||||
|
&isa::Instruction::F32ConvertUI32 => self.run_extend::<u32, F32, F32>(context),
|
||||||
|
&isa::Instruction::F32ConvertSI64 => self.run_wrap::<i64, F32>(context),
|
||||||
|
&isa::Instruction::F32ConvertUI64 => self.run_wrap::<u64, F32>(context),
|
||||||
|
&isa::Instruction::F32DemoteF64 => self.run_wrap::<F64, F32>(context),
|
||||||
|
&isa::Instruction::F64ConvertSI32 => self.run_extend::<i32, F64, F64>(context),
|
||||||
|
&isa::Instruction::F64ConvertUI32 => self.run_extend::<u32, F64, F64>(context),
|
||||||
|
&isa::Instruction::F64ConvertSI64 => self.run_extend::<i64, F64, F64>(context),
|
||||||
|
&isa::Instruction::F64ConvertUI64 => self.run_extend::<u64, F64, F64>(context),
|
||||||
|
&isa::Instruction::F64PromoteF32 => self.run_extend::<F32, F64, F64>(context),
|
||||||
|
|
||||||
|
&isa::Instruction::I32ReinterpretF32 => self.run_reinterpret::<F32, i32>(context),
|
||||||
|
&isa::Instruction::I64ReinterpretF64 => self.run_reinterpret::<F64, i64>(context),
|
||||||
|
&isa::Instruction::F32ReinterpretI32 => self.run_reinterpret::<i32, F32>(context),
|
||||||
|
&isa::Instruction::F64ReinterpretI64 => self.run_reinterpret::<i64, F64>(context),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,68 +362,41 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
Err(TrapKind::Unreachable)
|
Err(TrapKind::Unreachable)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_nop(&mut self, _context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
|
fn run_br(&mut self, _context: &mut FunctionContext, target: isa::Target) -> Result<InstructionOutcome, TrapKind> {
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::Branch(target))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_block(&mut self, context: &mut FunctionContext, labels: &HashMap<usize, usize>, block_type: BlockType) -> Result<InstructionOutcome, TrapKind> {
|
fn run_br_nez(&mut self, context: &mut FunctionContext, target: isa::Target) -> Result<InstructionOutcome, TrapKind> {
|
||||||
context.push_frame(labels, BlockFrameType::Block, block_type)?;
|
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_loop(&mut self, context: &mut FunctionContext, labels: &HashMap<usize, usize>, block_type: BlockType) -> Result<InstructionOutcome, TrapKind> {
|
|
||||||
context.push_frame(labels, BlockFrameType::Loop, block_type)?;
|
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_if(&mut self, context: &mut FunctionContext, labels: &HashMap<usize, usize>, block_type: BlockType) -> Result<InstructionOutcome, TrapKind> {
|
|
||||||
let condition: bool = context
|
|
||||||
.value_stack_mut()
|
|
||||||
.pop_as();
|
|
||||||
let block_frame_type = if condition { BlockFrameType::IfTrue } else {
|
|
||||||
let else_pos = labels[&context.position];
|
|
||||||
if !labels.contains_key(&else_pos) {
|
|
||||||
context.position = else_pos;
|
|
||||||
return Ok(InstructionOutcome::RunNextInstruction);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.position = else_pos;
|
|
||||||
BlockFrameType::IfFalse
|
|
||||||
};
|
|
||||||
context.push_frame(labels, block_frame_type, block_type)?;
|
|
||||||
|
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_else(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
|
|
||||||
let end_pos = labels[&context.position];
|
|
||||||
context.pop_frame(false)?;
|
|
||||||
context.position = end_pos;
|
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_end(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
|
|
||||||
context.pop_frame(false)?;
|
|
||||||
Ok(InstructionOutcome::End)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_br(&mut self, _context: &mut FunctionContext, label_idx: u32) -> Result<InstructionOutcome, TrapKind> {
|
|
||||||
Ok(InstructionOutcome::Branch(label_idx as usize))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_br_if(&mut self, context: &mut FunctionContext, label_idx: u32) -> Result<InstructionOutcome, TrapKind> {
|
|
||||||
let condition = context.value_stack_mut().pop_as();
|
let condition = context.value_stack_mut().pop_as();
|
||||||
if condition {
|
if condition {
|
||||||
Ok(InstructionOutcome::Branch(label_idx as usize))
|
Ok(InstructionOutcome::Branch(target))
|
||||||
} else {
|
} else {
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_br_table(&mut self, context: &mut FunctionContext, table: &[u32], default: u32) -> 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();
|
||||||
|
if condition {
|
||||||
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
|
} else {
|
||||||
|
|
||||||
|
Ok(InstructionOutcome::Branch(target))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = context.value_stack_mut()
|
||||||
.pop_as();
|
.pop_as();
|
||||||
Ok(InstructionOutcome::Branch(table.get(index as usize).cloned().unwrap_or(default) as usize))
|
|
||||||
|
let dst =
|
||||||
|
if (index as usize) < table.len() - 1 {
|
||||||
|
table[index as usize].clone()
|
||||||
|
} else {
|
||||||
|
let len = table.len();
|
||||||
|
table[len - 1].clone()
|
||||||
|
};
|
||||||
|
Ok(InstructionOutcome::Branch(dst))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_return(&mut self, _context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
|
fn run_return(&mut self, _context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
|
||||||
|
@ -551,7 +519,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, 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 = context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
|
@ -572,7 +540,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_load_extend<T, U>(&mut self, context: &mut FunctionContext, _align: u32, 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 = context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
|
@ -597,7 +565,7 @@ 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, 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 = context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
|
@ -623,7 +591,6 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
fn run_store_wrap<T, U>(
|
fn run_store_wrap<T, U>(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: &mut FunctionContext,
|
context: &mut FunctionContext,
|
||||||
_align: u32,
|
|
||||||
offset: u32,
|
offset: u32,
|
||||||
) -> Result<InstructionOutcome, TrapKind>
|
) -> Result<InstructionOutcome, TrapKind>
|
||||||
where
|
where
|
||||||
|
@ -1053,14 +1020,12 @@ struct FunctionContext {
|
||||||
pub locals: Vec<RuntimeValue>,
|
pub locals: Vec<RuntimeValue>,
|
||||||
/// Values stack.
|
/// Values stack.
|
||||||
pub value_stack: ValueStack,
|
pub value_stack: ValueStack,
|
||||||
/// Blocks frames stack.
|
|
||||||
pub frame_stack: StackWithLimit<BlockFrame>,
|
|
||||||
/// 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, frame_stack_limit: usize, signature: &Signature, args: Vec<RuntimeValue>) -> Self {
|
pub fn new(function: FuncRef, value_stack_limit: usize, signature: &Signature, args: Vec<RuntimeValue>) -> 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"),
|
||||||
|
@ -1071,7 +1036,6 @@ impl FunctionContext {
|
||||||
module: ModuleRef(module),
|
module: ModuleRef(module),
|
||||||
return_type: signature.return_type().map(|vt| BlockType::Value(vt.into_elements())).unwrap_or(BlockType::NoResult),
|
return_type: signature.return_type().map(|vt| BlockType::Value(vt.into_elements())).unwrap_or(BlockType::NoResult),
|
||||||
value_stack: ValueStack::with_limit(value_stack_limit),
|
value_stack: ValueStack::with_limit(value_stack_limit),
|
||||||
frame_stack: StackWithLimit::with_limit(frame_stack_limit),
|
|
||||||
locals: args,
|
locals: args,
|
||||||
position: 0,
|
position: 0,
|
||||||
}
|
}
|
||||||
|
@ -1095,7 +1059,6 @@ impl FunctionContext {
|
||||||
module: ModuleRef(module),
|
module: ModuleRef(module),
|
||||||
return_type: function_return_type,
|
return_type: function_return_type,
|
||||||
value_stack: ValueStack::with_limit(self.value_stack.limit() - self.value_stack.len()),
|
value_stack: ValueStack::with_limit(self.value_stack.limit() - self.value_stack.len()),
|
||||||
frame_stack: StackWithLimit::with_limit(self.frame_stack.limit() - self.frame_stack.len()),
|
|
||||||
locals: function_locals,
|
locals: function_locals,
|
||||||
position: 0,
|
position: 0,
|
||||||
})
|
})
|
||||||
|
@ -1139,66 +1102,6 @@ impl FunctionContext {
|
||||||
pub fn value_stack_mut(&mut self) -> &mut ValueStack {
|
pub fn value_stack_mut(&mut self) -> &mut ValueStack {
|
||||||
&mut self.value_stack
|
&mut self.value_stack
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn frame_stack(&self) -> &StackWithLimit<BlockFrame> {
|
|
||||||
&self.frame_stack
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push_frame(&mut self, frame_type: BlockFrameType, block_type: BlockType) -> Result<(), TrapKind> {
|
|
||||||
let begin_position = self.position;
|
|
||||||
let branch_position = match frame_type {
|
|
||||||
BlockFrameType::Function => usize::MAX,
|
|
||||||
BlockFrameType::Loop => begin_position,
|
|
||||||
BlockFrameType::IfTrue => {
|
|
||||||
let else_pos = labels[&begin_position];
|
|
||||||
1usize + match labels.get(&else_pos) {
|
|
||||||
Some(end_pos) => *end_pos,
|
|
||||||
None => else_pos,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => labels[&begin_position] + 1,
|
|
||||||
};
|
|
||||||
let end_position = match frame_type {
|
|
||||||
BlockFrameType::Function => usize::MAX,
|
|
||||||
_ => labels[&begin_position] + 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
self.frame_stack.push(BlockFrame {
|
|
||||||
frame_type: frame_type,
|
|
||||||
block_type: block_type,
|
|
||||||
begin_position: begin_position,
|
|
||||||
branch_position: branch_position,
|
|
||||||
end_position: end_position,
|
|
||||||
value_stack_len: self.value_stack.len(),
|
|
||||||
polymorphic_stack: false,
|
|
||||||
}).map_err(|_| TrapKind::StackOverflow)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn discard_frame(&mut self) {
|
|
||||||
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<(), TrapKind> {
|
|
||||||
let frame = self.frame_stack
|
|
||||||
.pop()
|
|
||||||
.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 {
|
|
||||||
BlockType::Value(_) if frame.frame_type != BlockFrameType::Loop || !is_branch =>
|
|
||||||
Some(self.value_stack.pop()),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
self.value_stack.resize(frame.value_stack_len);
|
|
||||||
self.position = if is_branch { frame.branch_position } else { frame.end_position };
|
|
||||||
if let Some(frame_value) = frame_value {
|
|
||||||
self.value_stack.push(frame_value)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for FunctionContext {
|
impl fmt::Debug for FunctionContext {
|
||||||
|
|
|
@ -108,11 +108,22 @@ impl Validator {
|
||||||
let func_label = context.sink.new_label();
|
let func_label = context.sink.new_label();
|
||||||
context.push_label(BlockFrameType::Function, result_ty, func_label)?;
|
context.push_label(BlockFrameType::Function, result_ty, func_label)?;
|
||||||
Validator::validate_function_block(&mut context, body.code().elements())?;
|
Validator::validate_function_block(&mut context, body.code().elements())?;
|
||||||
|
|
||||||
|
|
||||||
while !context.frame_stack.is_empty() {
|
while !context.frame_stack.is_empty() {
|
||||||
// TODO: resolve labels?
|
let branch_label = context.top_label()?.branch_label;
|
||||||
context.pop_label()?;
|
context.sink.resolve_label(branch_label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Emit explicit return.
|
||||||
|
// let (drop, keep) = context.drop_keep_return()?;
|
||||||
|
// TODO:
|
||||||
|
|
||||||
|
context.sink.emit(isa::Instruction::Return {
|
||||||
|
drop: 0,
|
||||||
|
keep: 0,
|
||||||
|
});
|
||||||
|
|
||||||
Ok(context.into_code())
|
Ok(context.into_code())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,7 +250,11 @@ impl Validator {
|
||||||
},
|
},
|
||||||
Return => {
|
Return => {
|
||||||
Validator::validate_return(context)?;
|
Validator::validate_return(context)?;
|
||||||
context.sink.emit(isa::Instruction::Return);
|
let (drop, keep) = context.drop_keep_return()?;
|
||||||
|
context.sink.emit(isa::Instruction::Return {
|
||||||
|
drop,
|
||||||
|
keep,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
Call(index) => {
|
Call(index) => {
|
||||||
|
@ -266,7 +281,7 @@ impl Validator {
|
||||||
let depth = context.relative_local_depth(index)?;
|
let depth = context.relative_local_depth(index)?;
|
||||||
Validator::validate_get_local(context, index)?;
|
Validator::validate_get_local(context, index)?;
|
||||||
context.sink.emit(
|
context.sink.emit(
|
||||||
isa::Instruction::GetLocal { depth },
|
isa::Instruction::GetLocal(depth),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
SetLocal(index) => {
|
SetLocal(index) => {
|
||||||
|
@ -275,7 +290,7 @@ impl Validator {
|
||||||
let depth = context.relative_local_depth(index)?;
|
let depth = context.relative_local_depth(index)?;
|
||||||
Validator::validate_set_local(context, index)?;
|
Validator::validate_set_local(context, index)?;
|
||||||
context.sink.emit(
|
context.sink.emit(
|
||||||
isa::Instruction::SetLocal { depth },
|
isa::Instruction::SetLocal(depth),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
TeeLocal(index) => {
|
TeeLocal(index) => {
|
||||||
|
@ -284,7 +299,7 @@ impl Validator {
|
||||||
let depth = context.relative_local_depth(index)?;
|
let depth = context.relative_local_depth(index)?;
|
||||||
Validator::validate_tee_local(context, index)?;
|
Validator::validate_tee_local(context, index)?;
|
||||||
context.sink.emit(
|
context.sink.emit(
|
||||||
isa::Instruction::TeeLocal { depth },
|
isa::Instruction::TeeLocal(depth),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
GetGlobal(index) => {
|
GetGlobal(index) => {
|
||||||
|
@ -1396,7 +1411,7 @@ impl<'a> FunctionValidationContext<'a> {
|
||||||
})?)
|
})?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop_label(&mut self) -> Result<InstructionOutcome, Error> {
|
fn pop_label(&mut self) -> Result<(), Error> {
|
||||||
// Don't pop frame yet. This is essential since we still might pop values from the value stack
|
// Don't pop frame yet. This is essential since we still might pop values from the value stack
|
||||||
// and this in turn requires current frame to check whether or not we've reached
|
// and this in turn requires current frame to check whether or not we've reached
|
||||||
// unreachable.
|
// unreachable.
|
||||||
|
@ -1421,7 +1436,7 @@ impl<'a> FunctionValidationContext<'a> {
|
||||||
self.push_value(value_type.into())?;
|
self.push_value(value_type.into())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(InstructionOutcome::ValidateNextInstruction)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn require_label(&self, idx: u32) -> Result<&BlockFrame, Error> {
|
fn require_label(&self, idx: u32) -> Result<&BlockFrame, Error> {
|
||||||
|
@ -1456,6 +1471,14 @@ impl<'a> FunctionValidationContext<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn drop_keep_return(&self) -> Result<(u32, u8), Error> {
|
||||||
|
// TODO: Refactor
|
||||||
|
let deepest = self.frame_stack.len();
|
||||||
|
let target = self.require_target(deepest as u32)?;
|
||||||
|
|
||||||
|
Ok((target.drop, target.keep))
|
||||||
|
}
|
||||||
|
|
||||||
fn relative_local_depth(&mut self, idx: u32) -> Result<u32, Error> {
|
fn relative_local_depth(&mut self, idx: u32) -> Result<u32, Error> {
|
||||||
// TODO: Comment stack layout
|
// TODO: Comment stack layout
|
||||||
let value_stack_height = self.value_stack.len() as u32;
|
let value_stack_height = self.value_stack.len() as u32;
|
||||||
|
|
Loading…
Reference in New Issue