2017-04-21 14:35:12 +03:00
|
|
|
use std::mem;
|
|
|
|
use std::ops;
|
|
|
|
use std::u32;
|
2017-04-27 14:22:02 +03:00
|
|
|
use std::fmt::Display;
|
2017-04-26 12:37:27 +03:00
|
|
|
use elements::{Opcode, BlockType, FunctionType};
|
2017-04-21 14:35:12 +03:00
|
|
|
use interpreter::Error;
|
|
|
|
use interpreter::module::{ModuleInstance, ItemIndex};
|
2017-04-26 12:37:27 +03:00
|
|
|
use interpreter::stack::StackWithLimit;
|
2017-04-26 15:41:22 +03:00
|
|
|
use interpreter::utils::{to_little_endian_bytes, from_little_endian_bytes};
|
2017-04-21 14:35:12 +03:00
|
|
|
use interpreter::value::{RuntimeValue, TryInto, WrapInto, TryTruncateInto, ExtendInto, TransmuteInto,
|
|
|
|
ArithmeticOps, Integer, Float};
|
2017-04-26 12:37:27 +03:00
|
|
|
use interpreter::variable::VariableInstance;
|
2017-04-21 14:35:12 +03:00
|
|
|
|
|
|
|
const DEFAULT_MEMORY_INDEX: u32 = 0;
|
2017-04-26 15:41:22 +03:00
|
|
|
const DEFAULT_TABLE_INDEX: u32 = 0;
|
2017-04-21 14:35:12 +03:00
|
|
|
|
|
|
|
pub struct Interpreter;
|
|
|
|
|
|
|
|
/// Function execution context.
|
2017-04-26 12:37:27 +03:00
|
|
|
pub struct FunctionContext<'a> {
|
2017-04-21 14:35:12 +03:00
|
|
|
/// Module instance.
|
2017-04-26 12:37:27 +03:00
|
|
|
module: &'a ModuleInstance,
|
|
|
|
/// Function return type.
|
|
|
|
return_type: BlockType,
|
|
|
|
/// Local variables.
|
|
|
|
locals: Vec<VariableInstance>,
|
2017-04-21 14:35:12 +03:00
|
|
|
/// Values stack.
|
2017-04-26 12:37:27 +03:00
|
|
|
value_stack: StackWithLimit<RuntimeValue>,
|
2017-04-21 14:35:12 +03:00
|
|
|
/// Blocks frames stack.
|
2017-04-26 12:37:27 +03:00
|
|
|
frame_stack: StackWithLimit<BlockFrame>,
|
2017-04-21 14:35:12 +03:00
|
|
|
/// Current instruction position.
|
|
|
|
position: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
2017-04-26 12:37:27 +03:00
|
|
|
pub enum InstructionOutcome {
|
2017-04-21 14:35:12 +03:00
|
|
|
/// Continue with current instruction.
|
|
|
|
RunInstruction,
|
|
|
|
/// Continue with next instruction.
|
|
|
|
RunNextInstruction,
|
2017-04-27 14:22:02 +03:00
|
|
|
/// Branch to given frame.
|
|
|
|
Branch(usize),
|
|
|
|
/// End current frame.
|
|
|
|
End,
|
2017-04-21 14:35:12 +03:00
|
|
|
/// Return from current function block.
|
|
|
|
Return,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
2017-04-26 12:37:27 +03:00
|
|
|
pub struct BlockFrame {
|
2017-04-21 14:35:12 +03:00
|
|
|
// A label for reference from branch instructions.
|
2017-04-27 14:22:02 +03:00
|
|
|
branch_position: usize,
|
|
|
|
// A label for reference from end instructions.
|
|
|
|
end_position: usize,
|
2017-04-21 14:35:12 +03:00
|
|
|
// A limit integer value, which is an index into the value stack indicating where to reset it to on a branch to that label.
|
|
|
|
value_limit: usize,
|
|
|
|
// A signature, which is a block signature type indicating the number and types of result values of the region.
|
|
|
|
signature: BlockType,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Interpreter {
|
2017-04-26 12:37:27 +03:00
|
|
|
pub fn run_function(context: &mut FunctionContext, body: &[Opcode]) -> Result<Option<RuntimeValue>, Error> {
|
|
|
|
Interpreter::execute_block(context, body)?;
|
|
|
|
match context.return_type {
|
|
|
|
BlockType::Value(_) => Ok(Some(context.value_stack_mut().pop()?)),
|
2017-04-21 14:35:12 +03:00
|
|
|
BlockType::NoResult => Ok(None),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_instruction(context: &mut FunctionContext, opcode: &Opcode) -> Result<InstructionOutcome, Error> {
|
|
|
|
match opcode {
|
|
|
|
&Opcode::Unreachable => Interpreter::run_unreachable(context),
|
|
|
|
&Opcode::Nop => Interpreter::run_nop(context),
|
|
|
|
&Opcode::Block(block_type, ref ops) => Interpreter::run_block(context, block_type, ops.elements()),
|
|
|
|
&Opcode::Loop(block_type, ref ops) => Interpreter::run_loop(context, block_type, ops.elements()),
|
|
|
|
&Opcode::If(block_type, ref ops) => Interpreter::run_if(context, block_type, ops.elements()),
|
|
|
|
&Opcode::Else => Interpreter::run_else(context),
|
|
|
|
&Opcode::End => Interpreter::run_end(context),
|
|
|
|
&Opcode::Br(idx) => Interpreter::run_br(context, idx),
|
|
|
|
&Opcode::BrIf(idx) => Interpreter::run_br_if(context, idx),
|
|
|
|
&Opcode::BrTable(ref table, default) => Interpreter::run_br_table(context, table, default),
|
|
|
|
&Opcode::Return => Interpreter::run_return(context),
|
|
|
|
|
|
|
|
&Opcode::Call(index) => Interpreter::run_call(context, index),
|
|
|
|
&Opcode::CallIndirect(index, reserved) => Interpreter::run_call_indirect(context, index),
|
|
|
|
|
|
|
|
&Opcode::Drop => Interpreter::run_drop(context),
|
|
|
|
&Opcode::Select => Interpreter::run_select(context),
|
|
|
|
|
|
|
|
&Opcode::GetLocal(index) => Interpreter::run_get_local(context, index),
|
|
|
|
&Opcode::SetLocal(index) => Interpreter::run_set_local(context, index),
|
|
|
|
&Opcode::TeeLocal(index) => Interpreter::run_tee_local(context, index),
|
|
|
|
&Opcode::GetGlobal(index) => Interpreter::run_get_global(context, index),
|
|
|
|
&Opcode::SetGlobal(index) => Interpreter::run_set_global(context, index),
|
|
|
|
|
|
|
|
&Opcode::I32Load(offset, align) => Interpreter::run_load::<i32>(context, offset, align),
|
|
|
|
&Opcode::I64Load(offset, align) => Interpreter::run_load::<i64>(context, offset, align),
|
|
|
|
&Opcode::F32Load(offset, align) => Interpreter::run_load::<f32>(context, offset, align),
|
|
|
|
&Opcode::F64Load(offset, align) => Interpreter::run_load::<f64>(context, offset, align),
|
|
|
|
&Opcode::I32Load8S(offset, align) => Interpreter::run_load_extend::<i8, i32>(context, offset, align),
|
|
|
|
&Opcode::I32Load8U(offset, align) => Interpreter::run_load_extend::<u8, i32>(context, offset, align),
|
|
|
|
&Opcode::I32Load16S(offset, align) => Interpreter::run_load_extend::<i16, i32>(context, offset, align),
|
|
|
|
&Opcode::I32Load16U(offset, align) => Interpreter::run_load_extend::<u16, i32>(context, offset, align),
|
|
|
|
&Opcode::I64Load8S(offset, align) => Interpreter::run_load_extend::<i8, i64>(context, offset, align),
|
|
|
|
&Opcode::I64Load8U(offset, align) => Interpreter::run_load_extend::<u8, i64>(context, offset, align),
|
|
|
|
&Opcode::I64Load16S(offset, align) => Interpreter::run_load_extend::<i16, i64>(context, offset, align),
|
|
|
|
&Opcode::I64Load16U(offset, align) => Interpreter::run_load_extend::<u16, i64>(context, offset, align),
|
|
|
|
&Opcode::I64Load32S(offset, align) => Interpreter::run_load_extend::<i32, i64>(context, offset, align),
|
|
|
|
&Opcode::I64Load32U(offset, align) => Interpreter::run_load_extend::<u32, i64>(context, offset, align),
|
|
|
|
|
|
|
|
&Opcode::I32Store(offset, align) => Interpreter::run_store::<i32>(context, offset, align),
|
|
|
|
&Opcode::I64Store(offset, align) => Interpreter::run_store::<i64>(context, offset, align),
|
|
|
|
&Opcode::F32Store(offset, align) => Interpreter::run_store::<f32>(context, offset, align),
|
|
|
|
&Opcode::F64Store(offset, align) => Interpreter::run_store::<f64>(context, offset, align),
|
|
|
|
&Opcode::I32Store8(offset, align) => Interpreter::run_store_wrap::<i32, i8>(context, offset, align),
|
|
|
|
&Opcode::I32Store16(offset, align) => Interpreter::run_store_wrap::<i32, i16>(context, offset, align),
|
|
|
|
&Opcode::I64Store8(offset, align) => Interpreter::run_store_wrap::<i64, i8>(context, offset, align),
|
|
|
|
&Opcode::I64Store16(offset, align) => Interpreter::run_store_wrap::<i64, i16>(context, offset, align),
|
|
|
|
&Opcode::I64Store32(offset, align) => Interpreter::run_store_wrap::<i64, i32>(context, offset, align),
|
|
|
|
|
|
|
|
&Opcode::CurrentMemory(_) => Interpreter::run_current_memory(context),
|
|
|
|
&Opcode::GrowMemory(_) => Interpreter::run_grow_memory(context),
|
|
|
|
|
|
|
|
&Opcode::I32Const(val) => Interpreter::run_const(context, val.into()),
|
|
|
|
&Opcode::I64Const(val) => Interpreter::run_const(context, val.into()),
|
|
|
|
&Opcode::F32Const(val) => Interpreter::run_const(context, RuntimeValue::decode_f32(val)),
|
|
|
|
&Opcode::F64Const(val) => Interpreter::run_const(context, RuntimeValue::decode_f64(val)),
|
|
|
|
|
|
|
|
&Opcode::I32Eqz => Interpreter::run_eqz::<i32>(context),
|
|
|
|
&Opcode::I32Eq => Interpreter::run_eq::<i32>(context),
|
|
|
|
&Opcode::I32Ne => Interpreter::run_ne::<i32>(context),
|
|
|
|
&Opcode::I32LtS => Interpreter::run_lt::<i32>(context),
|
|
|
|
&Opcode::I32LtU => Interpreter::run_lt::<u32>(context),
|
|
|
|
&Opcode::I32GtS => Interpreter::run_gt::<i32>(context),
|
|
|
|
&Opcode::I32GtU => Interpreter::run_gt::<u32>(context),
|
|
|
|
&Opcode::I32LeS => Interpreter::run_lte::<i32>(context),
|
|
|
|
&Opcode::I32LeU => Interpreter::run_lte::<u32>(context),
|
|
|
|
&Opcode::I32GeS => Interpreter::run_gte::<i32>(context),
|
|
|
|
&Opcode::I32GeU => Interpreter::run_gte::<u32>(context),
|
|
|
|
|
|
|
|
&Opcode::I64Eqz => Interpreter::run_eqz::<i64>(context),
|
|
|
|
&Opcode::I64Eq => Interpreter::run_eq::<i64>(context),
|
|
|
|
&Opcode::I64Ne => Interpreter::run_ne::<i64>(context),
|
|
|
|
&Opcode::I64LtS => Interpreter::run_lt::<i64>(context),
|
|
|
|
&Opcode::I64LtU => Interpreter::run_lt::<u64>(context),
|
|
|
|
&Opcode::I64GtS => Interpreter::run_gt::<i64>(context),
|
|
|
|
&Opcode::I64GtU => Interpreter::run_gt::<u64>(context),
|
|
|
|
&Opcode::I64LeS => Interpreter::run_lte::<i64>(context),
|
|
|
|
&Opcode::I64LeU => Interpreter::run_lte::<u64>(context),
|
|
|
|
&Opcode::I64GeS => Interpreter::run_gte::<i64>(context),
|
|
|
|
&Opcode::I64GeU => Interpreter::run_gte::<u64>(context),
|
|
|
|
|
|
|
|
&Opcode::F32Eq => Interpreter::run_eq::<f32>(context),
|
|
|
|
&Opcode::F32Ne => Interpreter::run_ne::<f32>(context),
|
|
|
|
&Opcode::F32Lt => Interpreter::run_lt::<f32>(context),
|
|
|
|
&Opcode::F32Gt => Interpreter::run_gt::<f32>(context),
|
|
|
|
&Opcode::F32Le => Interpreter::run_lte::<f32>(context),
|
|
|
|
&Opcode::F32Ge => Interpreter::run_gte::<f32>(context),
|
|
|
|
|
|
|
|
&Opcode::F64Eq => Interpreter::run_eq::<f64>(context),
|
|
|
|
&Opcode::F64Ne => Interpreter::run_ne::<f64>(context),
|
|
|
|
&Opcode::F64Lt => Interpreter::run_lt::<f64>(context),
|
|
|
|
&Opcode::F64Gt => Interpreter::run_gt::<f64>(context),
|
|
|
|
&Opcode::F64Le => Interpreter::run_lte::<f64>(context),
|
|
|
|
&Opcode::F64Ge => Interpreter::run_gte::<f64>(context),
|
|
|
|
|
|
|
|
&Opcode::I32Clz => Interpreter::run_clz::<i32>(context),
|
|
|
|
&Opcode::I32Ctz => Interpreter::run_ctz::<i32>(context),
|
|
|
|
&Opcode::I32Popcnt => Interpreter::run_popcnt::<i32>(context),
|
|
|
|
&Opcode::I32Add => Interpreter::run_add::<i32>(context),
|
|
|
|
&Opcode::I32Sub => Interpreter::run_sub::<i32>(context),
|
|
|
|
&Opcode::I32Mul => Interpreter::run_mul::<i32>(context),
|
|
|
|
&Opcode::I32DivS => Interpreter::run_div::<i32, i32>(context),
|
|
|
|
&Opcode::I32DivU => Interpreter::run_div::<i32, u32>(context),
|
|
|
|
&Opcode::I32RemS => Interpreter::run_rem::<i32, i32>(context),
|
|
|
|
&Opcode::I32RemU => Interpreter::run_rem::<i32, u32>(context),
|
|
|
|
&Opcode::I32And => Interpreter::run_and::<i32>(context),
|
|
|
|
&Opcode::I32Or => Interpreter::run_or::<i32>(context),
|
|
|
|
&Opcode::I32Xor => Interpreter::run_xor::<i32>(context),
|
|
|
|
&Opcode::I32Shl => Interpreter::run_shl::<i32>(context),
|
|
|
|
&Opcode::I32ShrS => Interpreter::run_shr::<i32, i32>(context),
|
|
|
|
&Opcode::I32ShrU => Interpreter::run_shr::<i32, u32>(context),
|
|
|
|
&Opcode::I32Rotl => Interpreter::run_rotl::<i32>(context),
|
|
|
|
&Opcode::I32Rotr => Interpreter::run_rotr::<i32>(context),
|
|
|
|
|
|
|
|
&Opcode::I64Clz => Interpreter::run_clz::<i64>(context),
|
|
|
|
&Opcode::I64Ctz => Interpreter::run_ctz::<i64>(context),
|
|
|
|
&Opcode::I64Popcnt => Interpreter::run_popcnt::<i64>(context),
|
|
|
|
&Opcode::I64Add => Interpreter::run_add::<i64>(context),
|
|
|
|
&Opcode::I64Sub => Interpreter::run_sub::<i64>(context),
|
|
|
|
&Opcode::I64Mul => Interpreter::run_mul::<i64>(context),
|
|
|
|
&Opcode::I64DivS => Interpreter::run_div::<i64, i64>(context),
|
|
|
|
&Opcode::I64DivU => Interpreter::run_div::<i64, u64>(context),
|
|
|
|
&Opcode::I64RemS => Interpreter::run_rem::<i64, i64>(context),
|
|
|
|
&Opcode::I64RemU => Interpreter::run_rem::<i64, u64>(context),
|
|
|
|
&Opcode::I64And => Interpreter::run_and::<i64>(context),
|
|
|
|
&Opcode::I64Or => Interpreter::run_or::<i64>(context),
|
|
|
|
&Opcode::I64Xor => Interpreter::run_xor::<i64>(context),
|
|
|
|
&Opcode::I64Shl => Interpreter::run_shl::<i64>(context),
|
|
|
|
&Opcode::I64ShrS => Interpreter::run_shr::<i64, i64>(context),
|
|
|
|
&Opcode::I64ShrU => Interpreter::run_shr::<i64, u64>(context),
|
|
|
|
&Opcode::I64Rotl => Interpreter::run_rotl::<i64>(context),
|
|
|
|
&Opcode::I64Rotr => Interpreter::run_rotr::<i64>(context),
|
|
|
|
|
|
|
|
&Opcode::F32Abs => Interpreter::run_abs::<f32>(context),
|
|
|
|
&Opcode::F32Neg => Interpreter::run_neg::<f32>(context),
|
|
|
|
&Opcode::F32Ceil => Interpreter::run_ceil::<f32>(context),
|
|
|
|
&Opcode::F32Floor => Interpreter::run_floor::<f32>(context),
|
|
|
|
&Opcode::F32Trunc => Interpreter::run_trunc::<f32>(context),
|
|
|
|
&Opcode::F32Nearest => Interpreter::run_nearest::<f32>(context),
|
|
|
|
&Opcode::F32Sqrt => Interpreter::run_sqrt::<f32>(context),
|
|
|
|
&Opcode::F32Add => Interpreter::run_add::<f32>(context),
|
|
|
|
&Opcode::F32Sub => Interpreter::run_sub::<f32>(context),
|
|
|
|
&Opcode::F32Mul => Interpreter::run_mul::<f32>(context),
|
|
|
|
&Opcode::F32Div => Interpreter::run_div::<f32, f32>(context),
|
|
|
|
&Opcode::F32Min => Interpreter::run_min::<f32>(context),
|
|
|
|
&Opcode::F32Max => Interpreter::run_max::<f32>(context),
|
|
|
|
&Opcode::F32Copysign => Interpreter::run_copysign::<f32>(context),
|
|
|
|
|
|
|
|
&Opcode::F64Abs => Interpreter::run_abs::<f64>(context),
|
|
|
|
&Opcode::F64Neg => Interpreter::run_neg::<f64>(context),
|
|
|
|
&Opcode::F64Ceil => Interpreter::run_ceil::<f64>(context),
|
|
|
|
&Opcode::F64Floor => Interpreter::run_floor::<f64>(context),
|
|
|
|
&Opcode::F64Trunc => Interpreter::run_trunc::<f64>(context),
|
|
|
|
&Opcode::F64Nearest => Interpreter::run_nearest::<f64>(context),
|
|
|
|
&Opcode::F64Sqrt => Interpreter::run_sqrt::<f64>(context),
|
|
|
|
&Opcode::F64Add => Interpreter::run_add::<f64>(context),
|
|
|
|
&Opcode::F64Sub => Interpreter::run_sub::<f64>(context),
|
|
|
|
&Opcode::F64Mul => Interpreter::run_mul::<f64>(context),
|
|
|
|
&Opcode::F64Div => Interpreter::run_div::<f64, f64>(context),
|
|
|
|
&Opcode::F64Min => Interpreter::run_min::<f64>(context),
|
|
|
|
&Opcode::F64Max => Interpreter::run_max::<f64>(context),
|
|
|
|
&Opcode::F64Copysign => Interpreter::run_copysign::<f64>(context),
|
|
|
|
|
|
|
|
&Opcode::I32WarpI64 => Interpreter::run_wrap::<i64, i32>(context),
|
|
|
|
&Opcode::I32TruncSF32 => Interpreter::run_trunc_to_int::<f32, i32, i32>(context),
|
|
|
|
&Opcode::I32TruncUF32 => Interpreter::run_trunc_to_int::<f32, u32, i32>(context),
|
|
|
|
&Opcode::I32TruncSF64 => Interpreter::run_trunc_to_int::<f64, i32, i32>(context),
|
|
|
|
&Opcode::I32TruncUF64 => Interpreter::run_trunc_to_int::<f64, u32, i32>(context),
|
|
|
|
&Opcode::I64ExtendSI32 => Interpreter::run_extend::<i32, i64, i64>(context),
|
|
|
|
&Opcode::I64ExtendUI32 => Interpreter::run_extend::<u32, u64, i64>(context),
|
|
|
|
&Opcode::I64TruncSF32 => Interpreter::run_trunc_to_int::<f32, i64, i64>(context),
|
|
|
|
&Opcode::I64TruncUF32 => Interpreter::run_trunc_to_int::<f32, u64, i64>(context),
|
|
|
|
&Opcode::I64TruncSF64 => Interpreter::run_trunc_to_int::<f64, i64, i64>(context),
|
|
|
|
&Opcode::I64TruncUF64 => Interpreter::run_trunc_to_int::<f64, u64, i64>(context),
|
|
|
|
&Opcode::F32ConvertSI32 => Interpreter::run_extend::<i32, f32, f32>(context),
|
|
|
|
&Opcode::F32ConvertUI32 => Interpreter::run_extend::<u32, f32, f32>(context),
|
|
|
|
&Opcode::F32ConvertSI64 => Interpreter::run_wrap::<i64, f32>(context),
|
|
|
|
&Opcode::F32ConvertUI64 => Interpreter::run_wrap::<u64, f32>(context),
|
|
|
|
&Opcode::F32DemoteF64 => Interpreter::run_wrap::<f64, f32>(context),
|
|
|
|
&Opcode::F64ConvertSI32 => Interpreter::run_extend::<i32, f64, f64>(context),
|
|
|
|
&Opcode::F64ConvertUI32 => Interpreter::run_extend::<u32, f64, f64>(context),
|
|
|
|
&Opcode::F64ConvertSI64 => Interpreter::run_extend::<i64, f64, f64>(context),
|
|
|
|
&Opcode::F64ConvertUI64 => Interpreter::run_extend::<u64, f64, f64>(context),
|
|
|
|
&Opcode::F64PromoteF32 => Interpreter::run_extend::<f32, f64, f64>(context),
|
|
|
|
|
|
|
|
&Opcode::I32ReinterpretF32 => Interpreter::run_reinterpret::<f32, i32>(context),
|
|
|
|
&Opcode::I64ReinterpretF64 => Interpreter::run_reinterpret::<f64, i64>(context),
|
|
|
|
&Opcode::F32ReinterpretI32 => Interpreter::run_reinterpret::<i32, f32>(context),
|
|
|
|
&Opcode::F64ReinterpretI64 => Interpreter::run_reinterpret::<i64, f64>(context),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_unreachable(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> {
|
2017-04-26 15:41:22 +03:00
|
|
|
Err(Error::Trap("programmatic".into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn run_nop(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> {
|
|
|
|
Ok(InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_block(context: &mut FunctionContext, block_type: BlockType, body: &[Opcode]) -> Result<InstructionOutcome, Error> {
|
|
|
|
let frame_position = context.position + 1;
|
2017-04-27 14:22:02 +03:00
|
|
|
context.push_frame(frame_position, frame_position, block_type.clone())?;
|
2017-04-26 12:37:27 +03:00
|
|
|
Interpreter::execute_block(context, body)
|
2017-04-21 14:35:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn run_loop(context: &mut FunctionContext, block_type: BlockType, body: &[Opcode]) -> Result<InstructionOutcome, Error> {
|
|
|
|
let frame_position = context.position;
|
2017-04-27 14:22:02 +03:00
|
|
|
context.push_frame(frame_position, frame_position + 1, block_type.clone())?;
|
2017-04-26 12:37:27 +03:00
|
|
|
Interpreter::execute_block(context, body)
|
2017-04-21 14:35:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn run_if(context: &mut FunctionContext, block_type: BlockType, body: &[Opcode]) -> Result<InstructionOutcome, Error> {
|
|
|
|
let body_len = body.len();
|
|
|
|
let else_index = body.iter().position(|op| *op == Opcode::Else).unwrap_or(body_len - 1);
|
2017-04-26 12:37:27 +03:00
|
|
|
let (begin_index, end_index) = if context.value_stack_mut().pop_as()? {
|
2017-04-21 14:35:12 +03:00
|
|
|
(0, else_index + 1)
|
|
|
|
} else {
|
|
|
|
(else_index + 1, body_len)
|
|
|
|
};
|
|
|
|
|
|
|
|
if begin_index != end_index {
|
|
|
|
let frame_position = context.position + 1;
|
2017-04-27 14:22:02 +03:00
|
|
|
context.push_frame(frame_position, frame_position, block_type.clone())?;
|
2017-04-26 12:37:27 +03:00
|
|
|
Interpreter::execute_block(context, &body[begin_index..end_index])
|
2017-04-21 14:35:12 +03:00
|
|
|
} else {
|
|
|
|
Ok(InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_else(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> {
|
2017-04-27 14:22:02 +03:00
|
|
|
Ok(InstructionOutcome::End)
|
2017-04-21 14:35:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn run_end(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> {
|
2017-04-27 14:22:02 +03:00
|
|
|
Ok(InstructionOutcome::End)
|
2017-04-21 14:35:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn run_br(context: &mut FunctionContext, label_idx: u32) -> Result<InstructionOutcome, Error> {
|
2017-04-27 14:22:02 +03:00
|
|
|
Ok(InstructionOutcome::Branch(label_idx as usize))
|
2017-04-21 14:35:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn run_br_if(context: &mut FunctionContext, label_idx: u32) -> Result<InstructionOutcome, Error> {
|
2017-04-26 12:37:27 +03:00
|
|
|
if context.value_stack_mut().pop_as()? {
|
2017-04-27 14:22:02 +03:00
|
|
|
Ok(InstructionOutcome::Branch(label_idx as usize))
|
2017-04-21 14:35:12 +03:00
|
|
|
} else {
|
|
|
|
Ok(InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_br_table(context: &mut FunctionContext, table: &Vec<u32>, default: u32) -> Result<InstructionOutcome, Error> {
|
2017-04-26 12:37:27 +03:00
|
|
|
let index: u32 = context.value_stack_mut().pop_as()?;
|
2017-04-27 14:22:02 +03:00
|
|
|
Ok(InstructionOutcome::Branch(table.get(index as usize).cloned().unwrap_or(default) as usize))
|
2017-04-21 14:35:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn run_return(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> {
|
|
|
|
Ok(InstructionOutcome::Return)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_call(context: &mut FunctionContext, func_idx: u32) -> Result<InstructionOutcome, Error> {
|
2017-04-26 15:41:22 +03:00
|
|
|
context.call_function(func_idx)
|
|
|
|
.and_then(|r| r.map(|r| context.value_stack_mut().push(r)).unwrap_or(Ok(())))
|
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
2017-04-21 14:35:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn run_call_indirect(context: &mut FunctionContext, type_idx: u32) -> Result<InstructionOutcome, Error> {
|
2017-04-26 15:41:22 +03:00
|
|
|
let table_func_idx: u32 = context.value_stack_mut().pop_as()?;
|
|
|
|
context.call_function_indirect(DEFAULT_TABLE_INDEX, type_idx, table_func_idx)
|
|
|
|
.and_then(|r| r.map(|r| context.value_stack_mut().push(r)).unwrap_or(Ok(())))
|
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
2017-04-21 14:35:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn run_drop(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_select(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_triple()
|
2017-04-21 14:35:12 +03:00
|
|
|
.and_then(|(left, mid, right)|
|
|
|
|
match (left, mid, right.try_into()) {
|
|
|
|
(left, mid, Ok(condition)) => Ok((left, mid, condition)),
|
2017-04-26 12:37:27 +03:00
|
|
|
_ => Err(Error::Stack("expected to get int value from stack".into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
}
|
|
|
|
)
|
|
|
|
.map(|(left, mid, condition)| if condition { left } else { mid })
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|val| context.value_stack_mut().push(val))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_get_local(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Error> {
|
|
|
|
context.get_local(index as usize)
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|value| context.value_stack_mut().push(value))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_set_local(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Error> {
|
2017-04-26 12:37:27 +03:00
|
|
|
let arg = context.value_stack_mut().pop()?;
|
2017-04-21 14:35:12 +03:00
|
|
|
context.set_local(index as usize, arg)
|
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_tee_local(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Error> {
|
2017-04-26 12:37:27 +03:00
|
|
|
let arg = context.value_stack().top()?.clone();
|
2017-04-21 14:35:12 +03:00
|
|
|
context.set_local(index as usize, arg)
|
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_get_global(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Error> {
|
|
|
|
context.module()
|
|
|
|
.global(ItemIndex::IndexSpace(index))
|
2017-04-26 12:37:27 +03:00
|
|
|
.and_then(|g| context.value_stack_mut().push(g.get()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_set_global(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Error> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop()
|
2017-04-21 14:35:12 +03:00
|
|
|
.and_then(|v| context.module().global(ItemIndex::IndexSpace(index)).and_then(|g| g.set(v)))
|
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_load<T>(context: &mut FunctionContext, offset: u32, align: u32) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<T> {
|
|
|
|
context.module()
|
|
|
|
.memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX))
|
|
|
|
.and_then(|m| m.get(effective_address(offset, align)?, 4))
|
|
|
|
.map(|b| from_little_endian_bytes::<T>(&b))
|
2017-04-26 12:37:27 +03:00
|
|
|
.and_then(|n| context.value_stack_mut().push(n.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_load_extend<T, U>(context: &mut FunctionContext, offset: u32, align: u32) -> Result<InstructionOutcome, Error>
|
|
|
|
where T: ExtendInto<U>, RuntimeValue: From<U> {
|
|
|
|
let stack_value: U = context.module()
|
|
|
|
.memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX))
|
|
|
|
.and_then(|m| m.get(effective_address(offset, align)?, mem::size_of::<T>()))
|
|
|
|
.map(|b| from_little_endian_bytes::<T>(&b))
|
|
|
|
.map(|v| v.extend_into())?;
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.push(stack_value.into())
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_store<T>(context: &mut FunctionContext, offset: u32, align: u32) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: TryInto<T, Error> {
|
|
|
|
let stack_value = context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|n| to_little_endian_bytes::<T>(n))?;
|
|
|
|
context.module()
|
|
|
|
.memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX))
|
|
|
|
.and_then(|m| m.set(effective_address(offset, align)?, &stack_value))
|
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_store_wrap<T, U>(context: &mut FunctionContext, offset: u32, align: u32) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: TryInto<T, Error>, T: WrapInto<U> {
|
2017-04-26 12:37:27 +03:00
|
|
|
let stack_value: T = context.value_stack_mut().pop().and_then(|v| v.try_into())?;
|
2017-04-21 14:35:12 +03:00
|
|
|
let stack_value = to_little_endian_bytes::<U>(stack_value.wrap_into());
|
|
|
|
context.module()
|
|
|
|
.memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX))
|
|
|
|
.and_then(|m| m.set(effective_address(offset, align)?, &stack_value))
|
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_current_memory(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> {
|
|
|
|
context.module()
|
|
|
|
.memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX))
|
|
|
|
.map(|m| m.size())
|
2017-04-26 12:37:27 +03:00
|
|
|
.and_then(|s| context.value_stack_mut().push(RuntimeValue::I64(s as i64)))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_grow_memory(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> {
|
2017-04-26 12:37:27 +03:00
|
|
|
let pages: u32 = context.value_stack_mut().pop_as()?;
|
2017-04-21 14:35:12 +03:00
|
|
|
context.module()
|
|
|
|
.memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX))
|
|
|
|
.and_then(|m| m.grow(pages))
|
2017-04-26 12:37:27 +03:00
|
|
|
.and_then(|m| context.value_stack_mut().push(RuntimeValue::I32(m as i32)))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_const(context: &mut FunctionContext, val: RuntimeValue) -> Result<InstructionOutcome, Error> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.push(val)
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_eqz<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> + Default {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|v| RuntimeValue::I32(if v == Default::default() { 1 } else { 0 }))
|
2017-04-26 12:37:27 +03:00
|
|
|
.and_then(|v| context.value_stack_mut().push(v))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_eq<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_pair_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|(left, right)| RuntimeValue::I32(if left == right { 1 } else { 0 }))
|
2017-04-26 12:37:27 +03:00
|
|
|
.and_then(|v| context.value_stack_mut().push(v))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_ne<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_pair_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|(left, right)| RuntimeValue::I32(if left != right { 1 } else { 0 }))
|
2017-04-26 12:37:27 +03:00
|
|
|
.and_then(|v| context.value_stack_mut().push(v))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_lt<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
2017-04-27 14:22:02 +03:00
|
|
|
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> + Display {
|
2017-04-21 14:35:12 +03:00
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_pair_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|(left, right)| RuntimeValue::I32(if left < right { 1 } else { 0 }))
|
2017-04-26 12:37:27 +03:00
|
|
|
.and_then(|v| context.value_stack_mut().push(v))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_gt<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_pair_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|(left, right)| RuntimeValue::I32(if left > right { 1 } else { 0 }))
|
2017-04-26 12:37:27 +03:00
|
|
|
.and_then(|v| context.value_stack_mut().push(v))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_lte<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_pair_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|(left, right)| RuntimeValue::I32(if left <= right { 1 } else { 0 }))
|
2017-04-26 12:37:27 +03:00
|
|
|
.and_then(|v| context.value_stack_mut().push(v))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_gte<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_pair_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|(left, right)| RuntimeValue::I32(if left >= right { 1 } else { 0 }))
|
2017-04-26 12:37:27 +03:00
|
|
|
.and_then(|v| context.value_stack_mut().push(v))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_clz<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|v| v.leading_zeros())
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_ctz<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|v| v.trailing_zeros())
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_popcnt<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|v| v.count_ones())
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_add<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_pair_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|(left, right)| left.add(right))
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_sub<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_pair_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|(left, right)| left.sub(right))
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_mul<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_pair_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|(left, right)| left.mul(right))
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_div<T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U>, U: ArithmeticOps<U> + TransmuteInto<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_pair_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|(left, right)| (left.transmute_into(), right.transmute_into()))
|
|
|
|
.map(|(left, right)| left.div(right))
|
|
|
|
.map(|v| v.transmute_into())
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_rem<T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U>, U: Integer<U> + TransmuteInto<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_pair_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|(left, right)| (left.transmute_into(), right.transmute_into()))
|
|
|
|
.map(|(left, right)| left.rem(right))
|
|
|
|
.map(|v| v.transmute_into())
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_and<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<<T as ops::BitAnd>::Output> + TryInto<T, Error>, T: ops::BitAnd<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_pair_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|(left, right)| left.bitand(right))
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_or<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<<T as ops::BitOr>::Output> + TryInto<T, Error>, T: ops::BitOr<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_pair_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|(left, right)| left.bitor(right))
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_xor<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<<T as ops::BitXor>::Output> + TryInto<T, Error>, T: ops::BitXor<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_pair_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|(left, right)| left.bitxor(right))
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_shl<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<<T as ops::Shl<T>>::Output> + TryInto<T, Error>, T: ops::Shl<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_pair_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|(left, right)| left.shl(right))
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_shr<T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U>, U: ops::Shr<U>, <U as ops::Shr<U>>::Output: TransmuteInto<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_pair_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|(left, right)| (left.transmute_into(), right.transmute_into()))
|
|
|
|
.map(|(left, right)| left.shr(right))
|
|
|
|
.map(|v| v.transmute_into())
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_rotl<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_pair_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|(left, right)| left.rotl(right))
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_rotr<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_pair_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|(left, right)| left.rotr(right))
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_abs<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|v| v.abs())
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_neg<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<<T as ops::Neg>::Output> + TryInto<T, Error>, T: ops::Neg {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|v| v.neg())
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_ceil<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|v| v.ceil())
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_floor<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|v| v.floor())
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_trunc<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|v| v.trunc())
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_nearest<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|v| v.round())
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_sqrt<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|v| v.sqrt())
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_min<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_pair_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|(left, right)| left.min(right))
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_max<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_pair_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|(left, right)| left.max(right))
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_copysign<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
|
|
|
Err(Error::NotImplemented)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_wrap<T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<U> + TryInto<T, Error>, T: WrapInto<U> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|v| v.wrap_into())
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_trunc_to_int<T, U, V>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<V> + TryInto<T, Error>, T: TryTruncateInto<U, Error>, U: TransmuteInto<V>, {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.and_then(|v| v.try_truncate_into())
|
|
|
|
.map(|v| v.transmute_into())
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_extend<T, U, V>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<V> + TryInto<T, Error>, T: ExtendInto<U>, U: TransmuteInto<V> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|v| v.extend_into())
|
|
|
|
.map(|v| v.transmute_into())
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|v| context.value_stack_mut().push(v.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_reinterpret<T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
|
|
|
where RuntimeValue: From<U>, RuntimeValue: TryInto<T, Error>, T: TransmuteInto<U> {
|
|
|
|
context
|
2017-04-26 12:37:27 +03:00
|
|
|
.value_stack_mut()
|
|
|
|
.pop_as::<T>()
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(TransmuteInto::transmute_into)
|
2017-04-26 12:37:27 +03:00
|
|
|
.and_then(|val| context.value_stack_mut().push(val.into()))
|
2017-04-21 14:35:12 +03:00
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
|
|
|
}
|
|
|
|
|
2017-04-26 12:37:27 +03:00
|
|
|
fn execute_block(context: &mut FunctionContext, body: &[Opcode]) -> Result<InstructionOutcome, Error> {
|
2017-04-21 14:35:12 +03:00
|
|
|
debug_assert!(!context.frame_stack.is_empty());
|
|
|
|
|
|
|
|
// run instructions
|
|
|
|
context.position = 0;
|
|
|
|
loop {
|
|
|
|
let instruction = &body[context.position];
|
2017-04-26 12:37:27 +03:00
|
|
|
|
|
|
|
println!("=== RUNNING {:?}", instruction); // TODO: trace
|
2017-04-21 14:35:12 +03:00
|
|
|
match Interpreter::run_instruction(context, instruction)? {
|
|
|
|
InstructionOutcome::RunInstruction => (),
|
|
|
|
InstructionOutcome::RunNextInstruction => context.position += 1,
|
2017-04-27 14:22:02 +03:00
|
|
|
InstructionOutcome::Branch(index) => {
|
2017-04-21 14:35:12 +03:00
|
|
|
if index != 0 {
|
2017-04-27 14:22:02 +03:00
|
|
|
context.discard_frame()?;
|
|
|
|
return Ok(InstructionOutcome::Branch(index - 1));
|
2017-04-21 14:35:12 +03:00
|
|
|
} else {
|
2017-04-27 14:22:02 +03:00
|
|
|
context.pop_frame(true)?;
|
2017-04-21 14:35:12 +03:00
|
|
|
return Ok(InstructionOutcome::RunInstruction);
|
|
|
|
}
|
|
|
|
},
|
2017-04-27 14:22:02 +03:00
|
|
|
InstructionOutcome::End => {
|
|
|
|
context.pop_frame(false)?;
|
|
|
|
return Ok(InstructionOutcome::RunInstruction);
|
|
|
|
},
|
2017-04-21 14:35:12 +03:00
|
|
|
InstructionOutcome::Return => return Ok(InstructionOutcome::Return),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> FunctionContext<'a> {
|
2017-04-26 12:37:27 +03:00
|
|
|
pub fn new(module: &'a ModuleInstance, value_stack_limit: usize, frame_stack_limit: usize, function: &FunctionType, body: &[Opcode], args: Vec<VariableInstance>) -> Result<Self, Error> {
|
2017-04-21 14:35:12 +03:00
|
|
|
let mut context = FunctionContext {
|
|
|
|
module: module,
|
2017-04-26 12:37:27 +03:00
|
|
|
return_type: function.return_type().map(|vt| BlockType::Value(vt)).unwrap_or(BlockType::NoResult),
|
|
|
|
value_stack: StackWithLimit::with_limit(value_stack_limit),
|
|
|
|
frame_stack: StackWithLimit::with_limit(frame_stack_limit),
|
|
|
|
locals: args,
|
2017-04-21 14:35:12 +03:00
|
|
|
position: 0,
|
|
|
|
};
|
2017-04-27 14:22:02 +03:00
|
|
|
context.push_frame(body.len() - 1, body.len() - 1, match function.return_type() {
|
2017-04-21 14:35:12 +03:00
|
|
|
Some(value_type) => BlockType::Value(value_type),
|
|
|
|
None => BlockType::NoResult,
|
|
|
|
})?;
|
|
|
|
Ok(context)
|
|
|
|
}
|
|
|
|
|
2017-04-26 12:37:27 +03:00
|
|
|
pub fn module(&self) -> &ModuleInstance {
|
2017-04-21 14:35:12 +03:00
|
|
|
self.module
|
|
|
|
}
|
|
|
|
|
2017-04-26 15:41:22 +03:00
|
|
|
pub fn call_function(&mut self, index: u32) -> Result<Option<RuntimeValue>, Error> {
|
|
|
|
self.module.call_function(self, ItemIndex::IndexSpace(index))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn call_function_indirect(&mut self, table_index: u32, type_index: u32, func_index: u32) -> Result<Option<RuntimeValue>, Error> {
|
|
|
|
self.module.call_function_indirect(self, ItemIndex::IndexSpace(table_index), type_index, func_index)
|
|
|
|
}
|
|
|
|
|
2017-04-21 14:35:12 +03:00
|
|
|
pub fn set_local(&mut self, index: usize, value: RuntimeValue) -> Result<InstructionOutcome, Error> {
|
|
|
|
self.locals.get_mut(index)
|
|
|
|
.ok_or(Error::Local(format!("expected to have local with index {}", index)))
|
2017-04-26 12:37:27 +03:00
|
|
|
.and_then(|l| l.set(value))
|
|
|
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
2017-04-21 14:35:12 +03:00
|
|
|
}
|
|
|
|
|
2017-04-26 12:37:27 +03:00
|
|
|
pub fn get_local(&mut self, index: usize) -> Result<RuntimeValue, Error> {
|
2017-04-21 14:35:12 +03:00
|
|
|
self.locals.get(index)
|
|
|
|
.ok_or(Error::Local(format!("expected to have local with index {}", index)))
|
2017-04-26 12:37:27 +03:00
|
|
|
.map(|l| l.get())
|
2017-04-21 14:35:12 +03:00
|
|
|
}
|
|
|
|
|
2017-04-26 12:37:27 +03:00
|
|
|
pub fn value_stack(&self) -> &StackWithLimit<RuntimeValue> {
|
|
|
|
&self.value_stack
|
2017-04-21 14:35:12 +03:00
|
|
|
}
|
|
|
|
|
2017-04-26 12:37:27 +03:00
|
|
|
pub fn value_stack_mut(&mut self) -> &mut StackWithLimit<RuntimeValue> {
|
|
|
|
&mut self.value_stack
|
2017-04-21 14:35:12 +03:00
|
|
|
}
|
|
|
|
|
2017-04-26 12:37:27 +03:00
|
|
|
pub fn frame_stack(&self) -> &StackWithLimit<BlockFrame> {
|
|
|
|
&self.frame_stack
|
2017-04-21 14:35:12 +03:00
|
|
|
}
|
|
|
|
|
2017-04-27 14:22:02 +03:00
|
|
|
pub fn push_frame(&mut self, branch_position: usize, end_position: usize, signature: BlockType) -> Result<(), Error> {
|
2017-04-26 12:37:27 +03:00
|
|
|
self.frame_stack.push(BlockFrame {
|
2017-04-27 14:22:02 +03:00
|
|
|
branch_position: branch_position,
|
|
|
|
end_position: end_position,
|
2017-04-21 14:35:12 +03:00
|
|
|
value_limit: self.value_stack.len(),
|
|
|
|
signature: signature,
|
2017-04-26 12:37:27 +03:00
|
|
|
})
|
2017-04-21 14:35:12 +03:00
|
|
|
}
|
|
|
|
|
2017-04-27 14:22:02 +03:00
|
|
|
pub fn discard_frame(&mut self) -> Result<(), Error> {
|
|
|
|
self.frame_stack.pop()
|
|
|
|
.map(|_| ())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn pop_frame(&mut self, is_branch: bool) -> Result<(), Error> {
|
2017-04-26 12:37:27 +03:00
|
|
|
let frame = self.frame_stack.pop()?;
|
2017-04-21 14:35:12 +03:00
|
|
|
if frame.value_limit > self.value_stack.len() {
|
2017-04-26 12:37:27 +03:00
|
|
|
return Err(Error::Stack("invalid stack len".into()));
|
2017-04-21 14:35:12 +03:00
|
|
|
}
|
2017-04-26 12:37:27 +03:00
|
|
|
|
2017-04-21 14:35:12 +03:00
|
|
|
let frame_value = match frame.signature {
|
2017-04-26 12:37:27 +03:00
|
|
|
BlockType::Value(_) => Some(self.value_stack.pop()?),
|
2017-04-21 14:35:12 +03:00
|
|
|
BlockType::NoResult => None,
|
|
|
|
};
|
|
|
|
self.value_stack.resize(frame.value_limit, RuntimeValue::I32(0));
|
2017-04-27 14:22:02 +03:00
|
|
|
self.position = if is_branch { frame.branch_position } else { frame.end_position };
|
2017-04-21 14:35:12 +03:00
|
|
|
if let Some(frame_value) = frame_value {
|
2017-04-26 12:37:27 +03:00
|
|
|
self.value_stack.push(frame_value)?;
|
2017-04-21 14:35:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BlockFrame {
|
|
|
|
pub fn invalid() -> Self {
|
|
|
|
BlockFrame {
|
2017-04-27 14:22:02 +03:00
|
|
|
branch_position: usize::max_value(),
|
|
|
|
end_position: usize::max_value(),
|
2017-04-21 14:35:12 +03:00
|
|
|
value_limit: usize::max_value(),
|
|
|
|
signature: BlockType::NoResult,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn effective_address(offset: u32, align: u32) -> Result<u32, Error> {
|
|
|
|
if align == 0 {
|
|
|
|
Ok(offset)
|
|
|
|
} else {
|
|
|
|
1u32.checked_shl(align - 1)
|
|
|
|
.and_then(|align| align.checked_add(offset))
|
|
|
|
.ok_or(Error::Interpreter("invalid memory alignment".into()))
|
|
|
|
}
|
|
|
|
}
|