From d0e13db6f25d8846147f38cd1361b2858cd3361b Mon Sep 17 00:00:00 2001 From: Sergey Pepyakin Date: Wed, 13 Jun 2018 11:32:44 +0300 Subject: [PATCH] WIP 2 --- src/isa.rs | 15 +- src/runner.rs | 545 +++++++++++++++++------------------------ src/validation/func.rs | 39 ++- 3 files changed, 262 insertions(+), 337 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index c01dc2b..4c7f73a 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -51,17 +51,13 @@ pub struct Target { #[derive(Debug, Clone)] pub enum Instruction { /// Push a local variable or an argument from the specified depth. - GetLocal { - depth: u32 - }, + GetLocal(u32), /// Pop a value and put it in at the specified depth. - SetLocal { - depth: u32 - }, + SetLocal(u32), /// Copy a value to the specified depth. - TeeLocal { depth: u32 }, + TeeLocal(u32), /// Similar to the Wasm ones, but instead of a label depth /// they specify direct PC. @@ -75,7 +71,10 @@ pub enum Instruction { BrTable(Box<[Target]>), Unreachable, - Return, + Return { + drop: u32, + keep: u8, + }, Call(u32), CallIndirect(u32), diff --git a/src/runner.rs b/src/runner.rs index 83c7e16..4cbb17f 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -3,8 +3,8 @@ use std::ops; use std::{u32, usize}; use std::fmt; use std::iter::repeat; -use std::collections::{HashMap, VecDeque}; -use parity_wasm::elements::{Opcode, BlockType, Local}; +use std::collections::VecDeque; +use parity_wasm::elements::{BlockType, Local}; use {Error, Trap, TrapKind, Signature}; use module::ModuleRef; use func::{FuncRef, FuncInstance, FuncInstanceInternal}; @@ -13,10 +13,11 @@ use value::{ ArithmeticOps, Integer, Float, LittleEndianConvert, TransmuteInto, }; 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 memory_units::Pages; use nan_preserving_float::{F32, F64}; +use isa; /// Maximum number of entries in value stack. pub const DEFAULT_VALUE_STACK_LIMIT: usize = 16384; @@ -32,12 +33,10 @@ pub struct Interpreter<'a, E: Externals + 'a> { pub enum InstructionOutcome { /// Continue with next instruction. RunNextInstruction, - /// Branch to given frame. - Branch(usize), + /// Branch to an instruction at the given position. + Branch(isa::Target), /// Execute function call. ExecuteCall(FuncRef), - /// End current frame. - End, /// Return from current function block. Return, } @@ -61,7 +60,6 @@ impl<'a, E: Externals> Interpreter<'a, E> { let context = FunctionContext::new( func.clone(), DEFAULT_VALUE_STACK_LIMIT, - DEFAULT_FRAME_STACK_LIMIT, func.signature(), args.into_iter().cloned().collect(), ); @@ -84,10 +82,12 @@ impl<'a, E: Externals> Interpreter<'a, E> { if !function_context.is_initialized() { let return_type = function_context.return_type; 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 { 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 { + fn do_run_function(&mut self, function_context: &mut FunctionContext, instructions: &[isa::Instruction]) -> Result { 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::Branch(mut index) => { - // discard index - 1 blocks - while index >= 1 { - function_context.discard_frame(); - index -= 1; - } + InstructionOutcome::Branch(target) => { + function_context.position = target.dst_pc as usize; - function_context.pop_frame(true)?; - if function_context.frame_stack().is_empty() { - break; + assert!(target.keep <= 1); + let keep = if target.keep == 1 { + Some(function_context.value_stack_mut().pop()) + } else { + None + }; + + let cur_stack_len = function_context.value_stack.len(); + function_context.value_stack_mut().resize(cur_stack_len - target.drop as usize); + if let Some(keep) = keep { + function_context.value_stack_mut().push(keep)?; } }, InstructionOutcome::ExecuteCall(func_ref) => { function_context.position += 1; return Ok(RunResult::NestedCall(func_ref)); }, - InstructionOutcome::End => { - if function_context.frame_stack().is_empty() { - 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, opcode: &Opcode) -> Result { - match opcode { - &Opcode::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), + fn run_instruction(&mut self, context: &mut FunctionContext, instruction: &isa::Instruction) -> Result { + match instruction { + &isa::Instruction::Unreachable => self.run_unreachable(context), - &Opcode::Call(index) => self.run_call(context, index), - &Opcode::CallIndirect(index, _reserved) => self.run_call_indirect(context, index), + &isa::Instruction::Br(ref target) => self.run_br(context, target.clone()), + &isa::Instruction::BrIfEqz(ref target) => self.run_br_eqz(context, target.clone()), + &isa::Instruction::BrIfNez(ref target) => self.run_br_nez(context, target.clone()), + &isa::Instruction::BrTable(ref targets) => self.run_br_table(context, targets), + &isa::Instruction::Return { drop, keep } => self.run_return(context), - &Opcode::Drop => self.run_drop(context), - &Opcode::Select => self.run_select(context), + &isa::Instruction::Call(index) => self.run_call(context, index), + &isa::Instruction::CallIndirect(index) => self.run_call_indirect(context, index), - &Opcode::GetLocal(index) => self.run_get_local(context, index), - &Opcode::SetLocal(index) => self.run_set_local(context, index), - &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), + &isa::Instruction::Drop => self.run_drop(context), + &isa::Instruction::Select => self.run_select(context), - &Opcode::I32Load(align, offset) => self.run_load::(context, align, offset), - &Opcode::I64Load(align, offset) => self.run_load::(context, align, offset), - &Opcode::F32Load(align, offset) => self.run_load::(context, align, offset), - &Opcode::F64Load(align, offset) => self.run_load::(context, align, offset), - &Opcode::I32Load8S(align, offset) => self.run_load_extend::(context, align, offset), - &Opcode::I32Load8U(align, offset) => self.run_load_extend::(context, align, offset), - &Opcode::I32Load16S(align, offset) => self.run_load_extend::(context, align, offset), - &Opcode::I32Load16U(align, offset) => self.run_load_extend::(context, align, offset), - &Opcode::I64Load8S(align, offset) => self.run_load_extend::(context, align, offset), - &Opcode::I64Load8U(align, offset) => self.run_load_extend::(context, align, offset), - &Opcode::I64Load16S(align, offset) => self.run_load_extend::(context, align, offset), - &Opcode::I64Load16U(align, offset) => self.run_load_extend::(context, align, offset), - &Opcode::I64Load32S(align, offset) => self.run_load_extend::(context, align, offset), - &Opcode::I64Load32U(align, offset) => self.run_load_extend::(context, align, offset), + &isa::Instruction::GetLocal(depth) => self.run_get_local(context, depth), + &isa::Instruction::SetLocal(depth) => self.run_set_local(context, depth), + &isa::Instruction::TeeLocal(depth) => self.run_tee_local(context, depth), + &isa::Instruction::GetGlobal(index) => self.run_get_global(context, index), + &isa::Instruction::SetGlobal(index) => self.run_set_global(context, index), - &Opcode::I32Store(align, offset) => self.run_store::(context, align, offset), - &Opcode::I64Store(align, offset) => self.run_store::(context, align, offset), - &Opcode::F32Store(align, offset) => self.run_store::(context, align, offset), - &Opcode::F64Store(align, offset) => self.run_store::(context, align, offset), - &Opcode::I32Store8(align, offset) => self.run_store_wrap::(context, align, offset), - &Opcode::I32Store16(align, offset) => self.run_store_wrap::(context, align, offset), - &Opcode::I64Store8(align, offset) => self.run_store_wrap::(context, align, offset), - &Opcode::I64Store16(align, offset) => self.run_store_wrap::(context, align, offset), - &Opcode::I64Store32(align, offset) => self.run_store_wrap::(context, align, offset), + &isa::Instruction::I32Load(offset) => self.run_load::(context, offset), + &isa::Instruction::I64Load(offset) => self.run_load::(context, offset), + &isa::Instruction::F32Load(offset) => self.run_load::(context, offset), + &isa::Instruction::F64Load(offset) => self.run_load::(context, offset), + &isa::Instruction::I32Load8S(offset) => self.run_load_extend::(context, offset), + &isa::Instruction::I32Load8U(offset) => self.run_load_extend::(context, offset), + &isa::Instruction::I32Load16S(offset) => self.run_load_extend::(context, offset), + &isa::Instruction::I32Load16U(offset) => self.run_load_extend::(context, offset), + &isa::Instruction::I64Load8S(offset) => self.run_load_extend::(context, offset), + &isa::Instruction::I64Load8U(offset) => self.run_load_extend::(context, offset), + &isa::Instruction::I64Load16S(offset) => self.run_load_extend::(context, offset), + &isa::Instruction::I64Load16U(offset) => self.run_load_extend::(context, offset), + &isa::Instruction::I64Load32S(offset) => self.run_load_extend::(context, offset), + &isa::Instruction::I64Load32U(offset) => self.run_load_extend::(context, offset), - &Opcode::CurrentMemory(_) => self.run_current_memory(context), - &Opcode::GrowMemory(_) => self.run_grow_memory(context), + &isa::Instruction::I32Store(offset) => self.run_store::(context, offset), + &isa::Instruction::I64Store(offset) => self.run_store::(context, offset), + &isa::Instruction::F32Store(offset) => self.run_store::(context, offset), + &isa::Instruction::F64Store(offset) => self.run_store::(context, offset), + &isa::Instruction::I32Store8(offset) => self.run_store_wrap::(context, offset), + &isa::Instruction::I32Store16(offset) => self.run_store_wrap::(context, offset), + &isa::Instruction::I64Store8(offset) => self.run_store_wrap::(context, offset), + &isa::Instruction::I64Store16(offset) => self.run_store_wrap::(context, offset), + &isa::Instruction::I64Store32(offset) => self.run_store_wrap::(context, offset), - &Opcode::I32Const(val) => self.run_const(context, val.into()), - &Opcode::I64Const(val) => self.run_const(context, val.into()), - &Opcode::F32Const(val) => self.run_const(context, RuntimeValue::decode_f32(val)), - &Opcode::F64Const(val) => self.run_const(context, RuntimeValue::decode_f64(val)), + &isa::Instruction::CurrentMemory => self.run_current_memory(context), + &isa::Instruction::GrowMemory => self.run_grow_memory(context), - &Opcode::I32Eqz => self.run_eqz::(context), - &Opcode::I32Eq => self.run_eq::(context), - &Opcode::I32Ne => self.run_ne::(context), - &Opcode::I32LtS => self.run_lt::(context), - &Opcode::I32LtU => self.run_lt::(context), - &Opcode::I32GtS => self.run_gt::(context), - &Opcode::I32GtU => self.run_gt::(context), - &Opcode::I32LeS => self.run_lte::(context), - &Opcode::I32LeU => self.run_lte::(context), - &Opcode::I32GeS => self.run_gte::(context), - &Opcode::I32GeU => self.run_gte::(context), + &isa::Instruction::I32Const(val) => self.run_const(context, val.into()), + &isa::Instruction::I64Const(val) => self.run_const(context, val.into()), + &isa::Instruction::F32Const(val) => self.run_const(context, RuntimeValue::decode_f32(val)), + &isa::Instruction::F64Const(val) => self.run_const(context, RuntimeValue::decode_f64(val)), - &Opcode::I64Eqz => self.run_eqz::(context), - &Opcode::I64Eq => self.run_eq::(context), - &Opcode::I64Ne => self.run_ne::(context), - &Opcode::I64LtS => self.run_lt::(context), - &Opcode::I64LtU => self.run_lt::(context), - &Opcode::I64GtS => self.run_gt::(context), - &Opcode::I64GtU => self.run_gt::(context), - &Opcode::I64LeS => self.run_lte::(context), - &Opcode::I64LeU => self.run_lte::(context), - &Opcode::I64GeS => self.run_gte::(context), - &Opcode::I64GeU => self.run_gte::(context), + &isa::Instruction::I32Eqz => self.run_eqz::(context), + &isa::Instruction::I32Eq => self.run_eq::(context), + &isa::Instruction::I32Ne => self.run_ne::(context), + &isa::Instruction::I32LtS => self.run_lt::(context), + &isa::Instruction::I32LtU => self.run_lt::(context), + &isa::Instruction::I32GtS => self.run_gt::(context), + &isa::Instruction::I32GtU => self.run_gt::(context), + &isa::Instruction::I32LeS => self.run_lte::(context), + &isa::Instruction::I32LeU => self.run_lte::(context), + &isa::Instruction::I32GeS => self.run_gte::(context), + &isa::Instruction::I32GeU => self.run_gte::(context), - &Opcode::F32Eq => self.run_eq::(context), - &Opcode::F32Ne => self.run_ne::(context), - &Opcode::F32Lt => self.run_lt::(context), - &Opcode::F32Gt => self.run_gt::(context), - &Opcode::F32Le => self.run_lte::(context), - &Opcode::F32Ge => self.run_gte::(context), + &isa::Instruction::I64Eqz => self.run_eqz::(context), + &isa::Instruction::I64Eq => self.run_eq::(context), + &isa::Instruction::I64Ne => self.run_ne::(context), + &isa::Instruction::I64LtS => self.run_lt::(context), + &isa::Instruction::I64LtU => self.run_lt::(context), + &isa::Instruction::I64GtS => self.run_gt::(context), + &isa::Instruction::I64GtU => self.run_gt::(context), + &isa::Instruction::I64LeS => self.run_lte::(context), + &isa::Instruction::I64LeU => self.run_lte::(context), + &isa::Instruction::I64GeS => self.run_gte::(context), + &isa::Instruction::I64GeU => self.run_gte::(context), - &Opcode::F64Eq => self.run_eq::(context), - &Opcode::F64Ne => self.run_ne::(context), - &Opcode::F64Lt => self.run_lt::(context), - &Opcode::F64Gt => self.run_gt::(context), - &Opcode::F64Le => self.run_lte::(context), - &Opcode::F64Ge => self.run_gte::(context), + &isa::Instruction::F32Eq => self.run_eq::(context), + &isa::Instruction::F32Ne => self.run_ne::(context), + &isa::Instruction::F32Lt => self.run_lt::(context), + &isa::Instruction::F32Gt => self.run_gt::(context), + &isa::Instruction::F32Le => self.run_lte::(context), + &isa::Instruction::F32Ge => self.run_gte::(context), - &Opcode::I32Clz => self.run_clz::(context), - &Opcode::I32Ctz => self.run_ctz::(context), - &Opcode::I32Popcnt => self.run_popcnt::(context), - &Opcode::I32Add => self.run_add::(context), - &Opcode::I32Sub => self.run_sub::(context), - &Opcode::I32Mul => self.run_mul::(context), - &Opcode::I32DivS => self.run_div::(context), - &Opcode::I32DivU => self.run_div::(context), - &Opcode::I32RemS => self.run_rem::(context), - &Opcode::I32RemU => self.run_rem::(context), - &Opcode::I32And => self.run_and::(context), - &Opcode::I32Or => self.run_or::(context), - &Opcode::I32Xor => self.run_xor::(context), - &Opcode::I32Shl => self.run_shl::(context, 0x1F), - &Opcode::I32ShrS => self.run_shr::(context, 0x1F), - &Opcode::I32ShrU => self.run_shr::(context, 0x1F), - &Opcode::I32Rotl => self.run_rotl::(context), - &Opcode::I32Rotr => self.run_rotr::(context), + &isa::Instruction::F64Eq => self.run_eq::(context), + &isa::Instruction::F64Ne => self.run_ne::(context), + &isa::Instruction::F64Lt => self.run_lt::(context), + &isa::Instruction::F64Gt => self.run_gt::(context), + &isa::Instruction::F64Le => self.run_lte::(context), + &isa::Instruction::F64Ge => self.run_gte::(context), - &Opcode::I64Clz => self.run_clz::(context), - &Opcode::I64Ctz => self.run_ctz::(context), - &Opcode::I64Popcnt => self.run_popcnt::(context), - &Opcode::I64Add => self.run_add::(context), - &Opcode::I64Sub => self.run_sub::(context), - &Opcode::I64Mul => self.run_mul::(context), - &Opcode::I64DivS => self.run_div::(context), - &Opcode::I64DivU => self.run_div::(context), - &Opcode::I64RemS => self.run_rem::(context), - &Opcode::I64RemU => self.run_rem::(context), - &Opcode::I64And => self.run_and::(context), - &Opcode::I64Or => self.run_or::(context), - &Opcode::I64Xor => self.run_xor::(context), - &Opcode::I64Shl => self.run_shl::(context, 0x3F), - &Opcode::I64ShrS => self.run_shr::(context, 0x3F), - &Opcode::I64ShrU => self.run_shr::(context, 0x3F), - &Opcode::I64Rotl => self.run_rotl::(context), - &Opcode::I64Rotr => self.run_rotr::(context), + &isa::Instruction::I32Clz => self.run_clz::(context), + &isa::Instruction::I32Ctz => self.run_ctz::(context), + &isa::Instruction::I32Popcnt => self.run_popcnt::(context), + &isa::Instruction::I32Add => self.run_add::(context), + &isa::Instruction::I32Sub => self.run_sub::(context), + &isa::Instruction::I32Mul => self.run_mul::(context), + &isa::Instruction::I32DivS => self.run_div::(context), + &isa::Instruction::I32DivU => self.run_div::(context), + &isa::Instruction::I32RemS => self.run_rem::(context), + &isa::Instruction::I32RemU => self.run_rem::(context), + &isa::Instruction::I32And => self.run_and::(context), + &isa::Instruction::I32Or => self.run_or::(context), + &isa::Instruction::I32Xor => self.run_xor::(context), + &isa::Instruction::I32Shl => self.run_shl::(context, 0x1F), + &isa::Instruction::I32ShrS => self.run_shr::(context, 0x1F), + &isa::Instruction::I32ShrU => self.run_shr::(context, 0x1F), + &isa::Instruction::I32Rotl => self.run_rotl::(context), + &isa::Instruction::I32Rotr => self.run_rotr::(context), - &Opcode::F32Abs => self.run_abs::(context), - &Opcode::F32Neg => self.run_neg::(context), - &Opcode::F32Ceil => self.run_ceil::(context), - &Opcode::F32Floor => self.run_floor::(context), - &Opcode::F32Trunc => self.run_trunc::(context), - &Opcode::F32Nearest => self.run_nearest::(context), - &Opcode::F32Sqrt => self.run_sqrt::(context), - &Opcode::F32Add => self.run_add::(context), - &Opcode::F32Sub => self.run_sub::(context), - &Opcode::F32Mul => self.run_mul::(context), - &Opcode::F32Div => self.run_div::(context), - &Opcode::F32Min => self.run_min::(context), - &Opcode::F32Max => self.run_max::(context), - &Opcode::F32Copysign => self.run_copysign::(context), + &isa::Instruction::I64Clz => self.run_clz::(context), + &isa::Instruction::I64Ctz => self.run_ctz::(context), + &isa::Instruction::I64Popcnt => self.run_popcnt::(context), + &isa::Instruction::I64Add => self.run_add::(context), + &isa::Instruction::I64Sub => self.run_sub::(context), + &isa::Instruction::I64Mul => self.run_mul::(context), + &isa::Instruction::I64DivS => self.run_div::(context), + &isa::Instruction::I64DivU => self.run_div::(context), + &isa::Instruction::I64RemS => self.run_rem::(context), + &isa::Instruction::I64RemU => self.run_rem::(context), + &isa::Instruction::I64And => self.run_and::(context), + &isa::Instruction::I64Or => self.run_or::(context), + &isa::Instruction::I64Xor => self.run_xor::(context), + &isa::Instruction::I64Shl => self.run_shl::(context, 0x3F), + &isa::Instruction::I64ShrS => self.run_shr::(context, 0x3F), + &isa::Instruction::I64ShrU => self.run_shr::(context, 0x3F), + &isa::Instruction::I64Rotl => self.run_rotl::(context), + &isa::Instruction::I64Rotr => self.run_rotr::(context), - &Opcode::F64Abs => self.run_abs::(context), - &Opcode::F64Neg => self.run_neg::(context), - &Opcode::F64Ceil => self.run_ceil::(context), - &Opcode::F64Floor => self.run_floor::(context), - &Opcode::F64Trunc => self.run_trunc::(context), - &Opcode::F64Nearest => self.run_nearest::(context), - &Opcode::F64Sqrt => self.run_sqrt::(context), - &Opcode::F64Add => self.run_add::(context), - &Opcode::F64Sub => self.run_sub::(context), - &Opcode::F64Mul => self.run_mul::(context), - &Opcode::F64Div => self.run_div::(context), - &Opcode::F64Min => self.run_min::(context), - &Opcode::F64Max => self.run_max::(context), - &Opcode::F64Copysign => self.run_copysign::(context), + &isa::Instruction::F32Abs => self.run_abs::(context), + &isa::Instruction::F32Neg => self.run_neg::(context), + &isa::Instruction::F32Ceil => self.run_ceil::(context), + &isa::Instruction::F32Floor => self.run_floor::(context), + &isa::Instruction::F32Trunc => self.run_trunc::(context), + &isa::Instruction::F32Nearest => self.run_nearest::(context), + &isa::Instruction::F32Sqrt => self.run_sqrt::(context), + &isa::Instruction::F32Add => self.run_add::(context), + &isa::Instruction::F32Sub => self.run_sub::(context), + &isa::Instruction::F32Mul => self.run_mul::(context), + &isa::Instruction::F32Div => self.run_div::(context), + &isa::Instruction::F32Min => self.run_min::(context), + &isa::Instruction::F32Max => self.run_max::(context), + &isa::Instruction::F32Copysign => self.run_copysign::(context), - &Opcode::I32WrapI64 => self.run_wrap::(context), - &Opcode::I32TruncSF32 => self.run_trunc_to_int::(context), - &Opcode::I32TruncUF32 => self.run_trunc_to_int::(context), - &Opcode::I32TruncSF64 => self.run_trunc_to_int::(context), - &Opcode::I32TruncUF64 => self.run_trunc_to_int::(context), - &Opcode::I64ExtendSI32 => self.run_extend::(context), - &Opcode::I64ExtendUI32 => self.run_extend::(context), - &Opcode::I64TruncSF32 => self.run_trunc_to_int::(context), - &Opcode::I64TruncUF32 => self.run_trunc_to_int::(context), - &Opcode::I64TruncSF64 => self.run_trunc_to_int::(context), - &Opcode::I64TruncUF64 => self.run_trunc_to_int::(context), - &Opcode::F32ConvertSI32 => self.run_extend::(context), - &Opcode::F32ConvertUI32 => self.run_extend::(context), - &Opcode::F32ConvertSI64 => self.run_wrap::(context), - &Opcode::F32ConvertUI64 => self.run_wrap::(context), - &Opcode::F32DemoteF64 => self.run_wrap::(context), - &Opcode::F64ConvertSI32 => self.run_extend::(context), - &Opcode::F64ConvertUI32 => self.run_extend::(context), - &Opcode::F64ConvertSI64 => self.run_extend::(context), - &Opcode::F64ConvertUI64 => self.run_extend::(context), - &Opcode::F64PromoteF32 => self.run_extend::(context), + &isa::Instruction::F64Abs => self.run_abs::(context), + &isa::Instruction::F64Neg => self.run_neg::(context), + &isa::Instruction::F64Ceil => self.run_ceil::(context), + &isa::Instruction::F64Floor => self.run_floor::(context), + &isa::Instruction::F64Trunc => self.run_trunc::(context), + &isa::Instruction::F64Nearest => self.run_nearest::(context), + &isa::Instruction::F64Sqrt => self.run_sqrt::(context), + &isa::Instruction::F64Add => self.run_add::(context), + &isa::Instruction::F64Sub => self.run_sub::(context), + &isa::Instruction::F64Mul => self.run_mul::(context), + &isa::Instruction::F64Div => self.run_div::(context), + &isa::Instruction::F64Min => self.run_min::(context), + &isa::Instruction::F64Max => self.run_max::(context), + &isa::Instruction::F64Copysign => self.run_copysign::(context), - &Opcode::I32ReinterpretF32 => self.run_reinterpret::(context), - &Opcode::I64ReinterpretF64 => self.run_reinterpret::(context), - &Opcode::F32ReinterpretI32 => self.run_reinterpret::(context), - &Opcode::F64ReinterpretI64 => self.run_reinterpret::(context), + &isa::Instruction::I32WrapI64 => self.run_wrap::(context), + &isa::Instruction::I32TruncSF32 => self.run_trunc_to_int::(context), + &isa::Instruction::I32TruncUF32 => self.run_trunc_to_int::(context), + &isa::Instruction::I32TruncSF64 => self.run_trunc_to_int::(context), + &isa::Instruction::I32TruncUF64 => self.run_trunc_to_int::(context), + &isa::Instruction::I64ExtendSI32 => self.run_extend::(context), + &isa::Instruction::I64ExtendUI32 => self.run_extend::(context), + &isa::Instruction::I64TruncSF32 => self.run_trunc_to_int::(context), + &isa::Instruction::I64TruncUF32 => self.run_trunc_to_int::(context), + &isa::Instruction::I64TruncSF64 => self.run_trunc_to_int::(context), + &isa::Instruction::I64TruncUF64 => self.run_trunc_to_int::(context), + &isa::Instruction::F32ConvertSI32 => self.run_extend::(context), + &isa::Instruction::F32ConvertUI32 => self.run_extend::(context), + &isa::Instruction::F32ConvertSI64 => self.run_wrap::(context), + &isa::Instruction::F32ConvertUI64 => self.run_wrap::(context), + &isa::Instruction::F32DemoteF64 => self.run_wrap::(context), + &isa::Instruction::F64ConvertSI32 => self.run_extend::(context), + &isa::Instruction::F64ConvertUI32 => self.run_extend::(context), + &isa::Instruction::F64ConvertSI64 => self.run_extend::(context), + &isa::Instruction::F64ConvertUI64 => self.run_extend::(context), + &isa::Instruction::F64PromoteF32 => self.run_extend::(context), + + &isa::Instruction::I32ReinterpretF32 => self.run_reinterpret::(context), + &isa::Instruction::I64ReinterpretF64 => self.run_reinterpret::(context), + &isa::Instruction::F32ReinterpretI32 => self.run_reinterpret::(context), + &isa::Instruction::F64ReinterpretI64 => self.run_reinterpret::(context), } } @@ -367,68 +362,41 @@ impl<'a, E: Externals> Interpreter<'a, E> { Err(TrapKind::Unreachable) } - fn run_nop(&mut self, _context: &mut FunctionContext) -> Result { - Ok(InstructionOutcome::RunNextInstruction) + fn run_br(&mut self, _context: &mut FunctionContext, target: isa::Target) -> Result { + Ok(InstructionOutcome::Branch(target)) } - fn run_block(&mut self, context: &mut FunctionContext, labels: &HashMap, block_type: BlockType) -> Result { - context.push_frame(labels, BlockFrameType::Block, block_type)?; - Ok(InstructionOutcome::RunNextInstruction) - } - - fn run_loop(&mut self, context: &mut FunctionContext, labels: &HashMap, block_type: BlockType) -> Result { - context.push_frame(labels, BlockFrameType::Loop, block_type)?; - Ok(InstructionOutcome::RunNextInstruction) - } - - fn run_if(&mut self, context: &mut FunctionContext, labels: &HashMap, block_type: BlockType) -> Result { - 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 { - 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 { - context.pop_frame(false)?; - Ok(InstructionOutcome::End) - } - - fn run_br(&mut self, _context: &mut FunctionContext, label_idx: u32) -> Result { - Ok(InstructionOutcome::Branch(label_idx as usize)) - } - - fn run_br_if(&mut self, context: &mut FunctionContext, label_idx: u32) -> Result { + fn run_br_nez(&mut self, context: &mut FunctionContext, target: isa::Target) -> Result { let condition = context.value_stack_mut().pop_as(); if condition { - Ok(InstructionOutcome::Branch(label_idx as usize)) + Ok(InstructionOutcome::Branch(target)) } else { Ok(InstructionOutcome::RunNextInstruction) } } - fn run_br_table(&mut self, context: &mut FunctionContext, table: &[u32], default: u32) -> Result { + fn run_br_eqz(&mut self, context: &mut FunctionContext, target: isa::Target) -> Result { + 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 { let index: u32 = context.value_stack_mut() .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 { @@ -551,7 +519,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { Ok(InstructionOutcome::RunNextInstruction) } - fn run_load(&mut self, context: &mut FunctionContext, _align: u32, offset: u32) -> Result + fn run_load(&mut self, context: &mut FunctionContext, offset: u32) -> Result where RuntimeValue: From, T: LittleEndianConvert { let raw_address = context .value_stack_mut() @@ -572,7 +540,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { Ok(InstructionOutcome::RunNextInstruction) } - fn run_load_extend(&mut self, context: &mut FunctionContext, _align: u32, offset: u32) -> Result + fn run_load_extend(&mut self, context: &mut FunctionContext, offset: u32) -> Result where T: ExtendInto, RuntimeValue: From, T: LittleEndianConvert { let raw_address = context .value_stack_mut() @@ -597,7 +565,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_store(&mut self, context: &mut FunctionContext, _align: u32, offset: u32) -> Result + fn run_store(&mut self, context: &mut FunctionContext, offset: u32) -> Result where T: FromRuntimeValue, T: LittleEndianConvert { let stack_value = context .value_stack_mut() @@ -623,7 +591,6 @@ impl<'a, E: Externals> Interpreter<'a, E> { fn run_store_wrap( &mut self, context: &mut FunctionContext, - _align: u32, offset: u32, ) -> Result where @@ -1053,14 +1020,12 @@ struct FunctionContext { pub locals: Vec, /// Values stack. pub value_stack: ValueStack, - /// Blocks frames stack. - pub frame_stack: StackWithLimit, /// Current instruction position. pub position: usize, } impl FunctionContext { - pub fn new(function: FuncRef, value_stack_limit: usize, frame_stack_limit: usize, signature: &Signature, args: Vec) -> Self { + pub fn new(function: FuncRef, value_stack_limit: usize, signature: &Signature, args: Vec) -> Self { let module = match *function.as_internal() { 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"), @@ -1071,7 +1036,6 @@ impl FunctionContext { module: ModuleRef(module), return_type: signature.return_type().map(|vt| BlockType::Value(vt.into_elements())).unwrap_or(BlockType::NoResult), value_stack: ValueStack::with_limit(value_stack_limit), - frame_stack: StackWithLimit::with_limit(frame_stack_limit), locals: args, position: 0, } @@ -1095,7 +1059,6 @@ impl FunctionContext { module: ModuleRef(module), return_type: function_return_type, 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, position: 0, }) @@ -1139,66 +1102,6 @@ impl FunctionContext { pub fn value_stack_mut(&mut self) -> &mut ValueStack { &mut self.value_stack } - - pub fn frame_stack(&self) -> &StackWithLimit { - &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 { diff --git a/src/validation/func.rs b/src/validation/func.rs index 700d732..c1eaed4 100644 --- a/src/validation/func.rs +++ b/src/validation/func.rs @@ -108,11 +108,22 @@ impl Validator { let func_label = context.sink.new_label(); context.push_label(BlockFrameType::Function, result_ty, func_label)?; Validator::validate_function_block(&mut context, body.code().elements())?; + + while !context.frame_stack.is_empty() { - // TODO: resolve labels? - context.pop_label()?; + let branch_label = context.top_label()?.branch_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()) } @@ -239,7 +250,11 @@ impl Validator { }, Return => { 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) => { @@ -266,7 +281,7 @@ impl Validator { let depth = context.relative_local_depth(index)?; Validator::validate_get_local(context, index)?; context.sink.emit( - isa::Instruction::GetLocal { depth }, + isa::Instruction::GetLocal(depth), ); }, SetLocal(index) => { @@ -275,7 +290,7 @@ impl Validator { let depth = context.relative_local_depth(index)?; Validator::validate_set_local(context, index)?; context.sink.emit( - isa::Instruction::SetLocal { depth }, + isa::Instruction::SetLocal(depth), ); }, TeeLocal(index) => { @@ -284,7 +299,7 @@ impl Validator { let depth = context.relative_local_depth(index)?; Validator::validate_tee_local(context, index)?; context.sink.emit( - isa::Instruction::TeeLocal { depth }, + isa::Instruction::TeeLocal(depth), ); }, GetGlobal(index) => { @@ -1396,7 +1411,7 @@ impl<'a> FunctionValidationContext<'a> { })?) } - fn pop_label(&mut self) -> Result { + 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 // and this in turn requires current frame to check whether or not we've reached // unreachable. @@ -1421,7 +1436,7 @@ impl<'a> FunctionValidationContext<'a> { self.push_value(value_type.into())?; } - Ok(InstructionOutcome::ValidateNextInstruction) + Ok(()) } 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 { // TODO: Comment stack layout let value_stack_height = self.value_stack.len() as u32;