From 9e9b573d8499276a1e382a19a9c6b16150decad1 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 13 Jun 2017 13:28:05 +0300 Subject: [PATCH 01/11] br_table --- spec/src/fixtures.rs | 2 +- src/interpreter/validator.rs | 29 ++++++++++++++++++++++------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/spec/src/fixtures.rs b/spec/src/fixtures.rs index 72be5e1..6d36470 100644 --- a/spec/src/fixtures.rs +++ b/spec/src/fixtures.rs @@ -20,7 +20,7 @@ run_test!("block-end-label-mismatch.fail", wasm_block_end_label_mismatch_fail, f run_test!("block-end-label-superfluous.fail", wasm_block_end_label_superfluous_fail, fail); run_test!("block", wasm_block); run_test!("br_if", wasm_br_if); -// TODO: run_test!("br_table", wasm_br_table); +run_test!("br_table", wasm_br_table); run_test!("br", wasm_br); run_test!("break-drop", wasm_break_drop); // TODO: run_test!("call_indirect", wasm_call_indirect); diff --git a/src/interpreter/validator.rs b/src/interpreter/validator.rs index 891e4f2..795b26d 100644 --- a/src/interpreter/validator.rs +++ b/src/interpreter/validator.rs @@ -432,17 +432,32 @@ impl Validator { } fn validate_br_table(context: &mut FunctionValidationContext, table: &Vec, default: u32) -> Result { - let default_block_type = context.require_label(default)?.block_type; - for label in table { - let label_block_type = context.require_label(*label)?.block_type; - if default_block_type != label_block_type { - return Err(Error::Validation(format!("Default label in br_table points to block of type {:?}, while other points to {:?}", default_block_type, label_block_type))); + let mut required_block_type = None; + + { + let default_block = context.require_label(default)?; + if !default_block.is_loop { + required_block_type = Some(default_block.block_type); + } + + for label in table { + let label_block = context.require_label(*label)?; + if !label_block.is_loop { + if let Some(required_block_type) = required_block_type { + if required_block_type != label_block.block_type { + return Err(Error::Validation(format!("Labels in br_table points to block of different types: {:?} and {:?}", required_block_type, label_block.block_type))); + } + } + required_block_type = Some(label_block.block_type); + } } } context.pop_value(ValueType::I32.into())?; - if let BlockType::Value(value_type) = default_block_type { - context.tee_value(value_type.into())?; + if let Some(required_block_type) = required_block_type { + if let BlockType::Value(value_type) = required_block_type { + context.tee_value(value_type.into())?; + } } Ok(InstructionOutcome::Unreachable) From b8405955c19ecc7495d856a83b796bda21a5851f Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 13 Jun 2017 17:16:38 +0300 Subject: [PATCH 02/11] get rid of block-level recursion --- src/interpreter/module.rs | 2 +- src/interpreter/runner.rs | 170 +++++++++++++++------------- src/interpreter/validator.rs | 207 +++++++++++++++++++++++------------ 3 files changed, 233 insertions(+), 146 deletions(-) diff --git a/src/interpreter/module.rs b/src/interpreter/module.rs index 6523282..2f12fc6 100644 --- a/src/interpreter/module.rs +++ b/src/interpreter/module.rs @@ -314,7 +314,7 @@ impl ModuleInstanceInterface for ModuleInstance { locals.extend(function_body.locals().iter().flat_map(|l| repeat(l.value_type()).take(l.count() as usize))); let mut context = FunctionValidationContext::new(&self.module, &self.imports, &locals, DEFAULT_VALUE_STACK_LIMIT, DEFAULT_FRAME_STACK_LIMIT, &function_type); let block_type = function_type.return_type().map(BlockType::Value).unwrap_or(BlockType::NoResult); - Validator::validate_block(&mut context, false, block_type, function_body.code().elements(), Opcode::End)?; + Validator::validate_function(&mut context, block_type, function_body.code().elements())?; } } diff --git a/src/interpreter/runner.rs b/src/interpreter/runner.rs index f2a5833..014b534 100644 --- a/src/interpreter/runner.rs +++ b/src/interpreter/runner.rs @@ -3,7 +3,7 @@ use std::ops; use std::u32; use std::sync::Arc; use std::fmt::Display; -use std::collections::HashMap; +use std::collections::{HashMap, VecDeque}; use elements::{Opcode, BlockType, FunctionType}; use interpreter::Error; use interpreter::module::{ModuleInstance, ModuleInstanceInterface, CallerContext, ItemIndex}; @@ -41,7 +41,7 @@ pub struct FunctionContext<'a> { } #[derive(Debug, Clone)] -pub enum InstructionOutcome { +pub enum InstructionOutcome<'a> { /// Continue with current instruction. RunInstruction, /// Continue with next instruction. @@ -52,6 +52,8 @@ pub enum InstructionOutcome { End, /// Return from current function block. Return, + /// Execute block. + ExecuteBlock(&'a [Opcode]), } #[derive(Debug, Clone)] @@ -80,7 +82,7 @@ impl Interpreter { } } - fn run_instruction(context: &mut FunctionContext, opcode: &Opcode) -> Result { + fn run_instruction<'a>(context: &mut FunctionContext, opcode: &'a Opcode) -> Result, Error> { match opcode { &Opcode::Unreachable => Interpreter::run_unreachable(context), &Opcode::Nop => Interpreter::run_nop(context), @@ -274,27 +276,27 @@ impl Interpreter { } } - fn run_unreachable(_context: &mut FunctionContext) -> Result { + fn run_unreachable<'a>(_context: &mut FunctionContext) -> Result, Error> { Err(Error::Trap("programmatic".into())) } - fn run_nop(_context: &mut FunctionContext) -> Result { + fn run_nop<'a>(_context: &mut FunctionContext) -> Result, Error> { Ok(InstructionOutcome::RunNextInstruction) } - fn run_block(context: &mut FunctionContext, block_type: BlockType, body: &[Opcode]) -> Result { + fn run_block<'a>(context: &mut FunctionContext, block_type: BlockType, body: &'a [Opcode]) -> Result, Error> { let frame_position = context.position + 1; context.push_frame(false, frame_position, frame_position, block_type.clone())?; - Interpreter::execute_block(context, body) + Ok(InstructionOutcome::ExecuteBlock(body)) } - fn run_loop(context: &mut FunctionContext, block_type: BlockType, body: &[Opcode]) -> Result { + fn run_loop<'a>(context: &mut FunctionContext, block_type: BlockType, body: &'a [Opcode]) -> Result, Error> { let frame_position = context.position; context.push_frame(true, frame_position, frame_position + 1, block_type.clone())?; - Interpreter::execute_block(context, body) + Ok(InstructionOutcome::ExecuteBlock(body)) } - fn run_if(context: &mut FunctionContext, block_type: BlockType, body: &[Opcode]) -> Result { + fn run_if<'a>(context: &mut FunctionContext, block_type: BlockType, body: &'a [Opcode]) -> Result, Error> { let body_len = body.len(); let else_index = body.iter().position(|op| *op == Opcode::Else).unwrap_or(body_len - 1); let (begin_index, end_index) = if context.value_stack_mut().pop_as()? { @@ -306,25 +308,25 @@ impl Interpreter { if begin_index != end_index { let frame_position = context.position + 1; context.push_frame(false, frame_position, frame_position, block_type.clone())?; - Interpreter::execute_block(context, &body[begin_index..end_index]) + Ok(InstructionOutcome::ExecuteBlock(&body[begin_index..end_index])) } else { Ok(InstructionOutcome::RunNextInstruction) } } - fn run_else(_context: &mut FunctionContext) -> Result { + fn run_else<'a>(_context: &mut FunctionContext) -> Result, Error> { Ok(InstructionOutcome::End) } - fn run_end(_context: &mut FunctionContext) -> Result { + fn run_end<'a>(_context: &mut FunctionContext) -> Result, Error> { Ok(InstructionOutcome::End) } - fn run_br(_context: &mut FunctionContext, label_idx: u32) -> Result { + fn run_br<'a>(_context: &mut FunctionContext, label_idx: u32) -> Result, Error> { Ok(InstructionOutcome::Branch(label_idx as usize)) } - fn run_br_if(context: &mut FunctionContext, label_idx: u32) -> Result { + fn run_br_if<'a>(context: &mut FunctionContext, label_idx: u32) -> Result, Error> { if context.value_stack_mut().pop_as()? { Ok(InstructionOutcome::Branch(label_idx as usize)) } else { @@ -332,36 +334,36 @@ impl Interpreter { } } - fn run_br_table(context: &mut FunctionContext, table: &Vec, default: u32) -> Result { + fn run_br_table<'a>(context: &mut FunctionContext, table: &Vec, default: u32) -> Result, Error> { let index: u32 = context.value_stack_mut().pop_as()?; Ok(InstructionOutcome::Branch(table.get(index as usize).cloned().unwrap_or(default) as usize)) } - fn run_return(_context: &mut FunctionContext) -> Result { + fn run_return<'a>(_context: &mut FunctionContext) -> Result, Error> { Ok(InstructionOutcome::Return) } - fn run_call(context: &mut FunctionContext, func_idx: u32) -> Result { + fn run_call<'a>(context: &mut FunctionContext, func_idx: u32) -> Result, Error> { context.call_function(func_idx) .and_then(|r| r.map(|r| context.value_stack_mut().push(r)).unwrap_or(Ok(()))) .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_call_indirect(context: &mut FunctionContext, type_idx: u32) -> Result { + fn run_call_indirect<'a>(context: &mut FunctionContext, type_idx: u32) -> Result, Error> { 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) } - fn run_drop(context: &mut FunctionContext) -> Result { + fn run_drop<'a>(context: &mut FunctionContext) -> Result, Error> { context .value_stack_mut() .pop() .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_select(context: &mut FunctionContext) -> Result { + fn run_select<'a>(context: &mut FunctionContext) -> Result, Error> { context .value_stack_mut() .pop_triple() @@ -376,32 +378,32 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_get_local(context: &mut FunctionContext, index: u32) -> Result { + fn run_get_local<'a>(context: &mut FunctionContext, index: u32) -> Result, Error> { context.get_local(index as usize) .map(|value| context.value_stack_mut().push(value)) .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_set_local(context: &mut FunctionContext, index: u32) -> Result { + fn run_set_local<'a>(context: &mut FunctionContext, index: u32) -> Result, Error> { let arg = context.value_stack_mut().pop()?; context.set_local(index as usize, arg) .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_tee_local(context: &mut FunctionContext, index: u32) -> Result { + fn run_tee_local<'a>(context: &mut FunctionContext, index: u32) -> Result, Error> { let arg = context.value_stack().top()?.clone(); context.set_local(index as usize, arg) .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_get_global(context: &mut FunctionContext, index: u32) -> Result { + fn run_get_global<'a>(context: &mut FunctionContext, index: u32) -> Result, Error> { context.module() .global(ItemIndex::IndexSpace(index), None) .and_then(|g| context.value_stack_mut().push(g.get())) .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_set_global(context: &mut FunctionContext, index: u32) -> Result { + fn run_set_global<'a>(context: &mut FunctionContext, index: u32) -> Result, Error> { context .value_stack_mut() .pop() @@ -409,7 +411,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_load(context: &mut FunctionContext, _align: u32, offset: u32) -> Result + fn run_load<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result, Error> where RuntimeValue: From, T: LittleEndianConvert { let address = effective_address(offset, context.value_stack_mut().pop_as()?)?; context.module() @@ -420,7 +422,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_load_extend(context: &mut FunctionContext, _align: u32, offset: u32) -> Result + fn run_load_extend<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result, Error> where T: ExtendInto, RuntimeValue: From, T: LittleEndianConvert { let address = effective_address(offset, context.value_stack_mut().pop_as()?)?; let stack_value: U = context.module() @@ -434,7 +436,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_store(context: &mut FunctionContext, _align: u32, offset: u32) -> Result + fn run_store<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result, Error> where RuntimeValue: TryInto, T: LittleEndianConvert { let stack_value = context .value_stack_mut() @@ -447,7 +449,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_store_wrap(context: &mut FunctionContext, _align: u32, offset: u32) -> Result + fn run_store_wrap<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result, Error> where RuntimeValue: TryInto, T: WrapInto, U: LittleEndianConvert { let stack_value: T = context.value_stack_mut().pop().and_then(|v| v.try_into())?; let stack_value = stack_value.wrap_into().into_little_endian(); @@ -458,7 +460,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_current_memory(context: &mut FunctionContext) -> Result { + fn run_current_memory<'a>(context: &mut FunctionContext) -> Result, Error> { context.module() .memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX)) .map(|m| m.size()) @@ -466,7 +468,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_grow_memory(context: &mut FunctionContext) -> Result { + fn run_grow_memory<'a>(context: &mut FunctionContext) -> Result, Error> { let pages: u32 = context.value_stack_mut().pop_as()?; context.module() .memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX)) @@ -475,14 +477,14 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_const(context: &mut FunctionContext, val: RuntimeValue) -> Result { + fn run_const<'a>(context: &mut FunctionContext, val: RuntimeValue) -> Result, Error> { context .value_stack_mut() .push(val) .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_eqz(context: &mut FunctionContext) -> Result + fn run_eqz<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: TryInto, T: PartialEq + Default { context .value_stack_mut() @@ -492,7 +494,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_eq(context: &mut FunctionContext) -> Result + fn run_eq<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: TryInto, T: PartialEq { context .value_stack_mut() @@ -502,7 +504,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_ne(context: &mut FunctionContext) -> Result + fn run_ne<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: TryInto, T: PartialEq { context .value_stack_mut() @@ -512,7 +514,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_lt(context: &mut FunctionContext) -> Result + fn run_lt<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: TryInto, T: PartialOrd + Display { context .value_stack_mut() @@ -522,7 +524,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_gt(context: &mut FunctionContext) -> Result + fn run_gt<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: TryInto, T: PartialOrd { context .value_stack_mut() @@ -532,7 +534,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_lte(context: &mut FunctionContext) -> Result + fn run_lte<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: TryInto, T: PartialOrd { context .value_stack_mut() @@ -542,7 +544,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_gte(context: &mut FunctionContext) -> Result + fn run_gte<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: TryInto, T: PartialOrd { context .value_stack_mut() @@ -552,7 +554,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_clz(context: &mut FunctionContext) -> Result + fn run_clz<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Integer { context .value_stack_mut() @@ -562,7 +564,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_ctz(context: &mut FunctionContext) -> Result + fn run_ctz<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Integer { context .value_stack_mut() @@ -572,7 +574,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_popcnt(context: &mut FunctionContext) -> Result + fn run_popcnt<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Integer { context .value_stack_mut() @@ -582,7 +584,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_add(context: &mut FunctionContext) -> Result + fn run_add<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: ArithmeticOps { context .value_stack_mut() @@ -592,7 +594,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_sub(context: &mut FunctionContext) -> Result + fn run_sub<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: ArithmeticOps { context .value_stack_mut() @@ -602,7 +604,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_mul(context: &mut FunctionContext) -> Result + fn run_mul<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: ArithmeticOps { context .value_stack_mut() @@ -612,7 +614,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_div(context: &mut FunctionContext) -> Result + fn run_div<'a, T, U>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: TransmuteInto + Display, U: ArithmeticOps + TransmuteInto { context .value_stack_mut() @@ -624,7 +626,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_rem(context: &mut FunctionContext) -> Result + fn run_rem<'a, T, U>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: TransmuteInto, U: Integer + TransmuteInto { context .value_stack_mut() @@ -636,7 +638,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_and(context: &mut FunctionContext) -> Result + fn run_and<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From<::Output> + TryInto, T: ops::BitAnd { context .value_stack_mut() @@ -646,7 +648,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_or(context: &mut FunctionContext) -> Result + fn run_or<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From<::Output> + TryInto, T: ops::BitOr { context .value_stack_mut() @@ -656,7 +658,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_xor(context: &mut FunctionContext) -> Result + fn run_xor<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From<::Output> + TryInto, T: ops::BitXor { context .value_stack_mut() @@ -666,7 +668,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_shl(context: &mut FunctionContext) -> Result + fn run_shl<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From<>::Output> + TryInto, T: ops::Shl { context .value_stack_mut() @@ -676,7 +678,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_shr(context: &mut FunctionContext) -> Result + fn run_shr<'a, T, U>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: TransmuteInto, U: ops::Shr, >::Output: TransmuteInto { context .value_stack_mut() @@ -688,7 +690,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_rotl(context: &mut FunctionContext) -> Result + fn run_rotl<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Integer { context .value_stack_mut() @@ -698,7 +700,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_rotr(context: &mut FunctionContext) -> Result + fn run_rotr<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Integer { context .value_stack_mut() @@ -708,7 +710,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_abs(context: &mut FunctionContext) -> Result + fn run_abs<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -718,7 +720,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_neg(context: &mut FunctionContext) -> Result + fn run_neg<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From<::Output> + TryInto, T: ops::Neg { context .value_stack_mut() @@ -728,7 +730,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_ceil(context: &mut FunctionContext) -> Result + fn run_ceil<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -738,7 +740,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_floor(context: &mut FunctionContext) -> Result + fn run_floor<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -748,7 +750,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_trunc(context: &mut FunctionContext) -> Result + fn run_trunc<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -758,7 +760,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_nearest(context: &mut FunctionContext) -> Result + fn run_nearest<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -768,7 +770,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_sqrt(context: &mut FunctionContext) -> Result + fn run_sqrt<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -778,7 +780,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_min(context: &mut FunctionContext) -> Result + fn run_min<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -788,7 +790,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_max(context: &mut FunctionContext) -> Result + fn run_max<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -798,7 +800,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_copysign(context: &mut FunctionContext) -> Result + fn run_copysign<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -808,7 +810,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_wrap(context: &mut FunctionContext) -> Result + fn run_wrap<'a, T, U>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: WrapInto { context .value_stack_mut() @@ -818,7 +820,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_trunc_to_int(context: &mut FunctionContext) -> Result + fn run_trunc_to_int<'a, T, U, V>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: TryTruncateInto, U: TransmuteInto, { context .value_stack_mut() @@ -829,7 +831,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_extend(context: &mut FunctionContext) -> Result + fn run_extend<'a, T, U, V>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: ExtendInto, U: TransmuteInto { context .value_stack_mut() @@ -840,7 +842,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_reinterpret(context: &mut FunctionContext) -> Result + fn run_reinterpret<'a, T, U>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From, RuntimeValue: TryInto, T: TransmuteInto { context .value_stack_mut() @@ -850,10 +852,11 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn execute_block(context: &mut FunctionContext, body: &[Opcode]) -> Result { + fn execute_block<'a>(context: &mut FunctionContext, mut body: &[Opcode]) -> Result, Error> { debug_assert!(!context.frame_stack.is_empty()); // run instructions + let mut block_stack = VecDeque::new(); context.position = 0; loop { let instruction = &body[context.position]; @@ -862,20 +865,33 @@ impl Interpreter { match Interpreter::run_instruction(context, instruction)? { InstructionOutcome::RunInstruction => (), InstructionOutcome::RunNextInstruction => context.position += 1, - InstructionOutcome::Branch(index) => { - if index != 0 { + InstructionOutcome::Branch(mut index) => { + while index >= 1 { context.discard_frame()?; - return Ok(InstructionOutcome::Branch(index - 1)); - } else { - context.pop_frame(true)?; - return Ok(InstructionOutcome::RunInstruction); + // there is block in block stack for each frame in context + assert!(block_stack.pop_back().is_some()); + index -= 1; } + + body = match block_stack.pop_back() { + Some(body) => body, + None => return Ok(InstructionOutcome::Return), + }; + context.pop_frame(true)?; }, InstructionOutcome::End => { + body = match block_stack.pop_back() { + Some(body) => body, + None => return Ok(InstructionOutcome::Return), + }; context.pop_frame(false)?; - return Ok(InstructionOutcome::RunInstruction); }, InstructionOutcome::Return => return Ok(InstructionOutcome::Return), + InstructionOutcome::ExecuteBlock(new_body) => { + block_stack.push_back(body); + body = new_body; + context.position = 0; + }, } } } diff --git a/src/interpreter/validator.rs b/src/interpreter/validator.rs index 795b26d..fbaa185 100644 --- a/src/interpreter/validator.rs +++ b/src/interpreter/validator.rs @@ -1,4 +1,5 @@ use std::u32; +use std::collections::VecDeque; use elements::{Module, Opcode, BlockType, FunctionType, ValueType, External, Type}; use interpreter::Error; use interpreter::runner::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; @@ -53,39 +54,91 @@ pub struct Validator; /// Instruction outcome. #[derive(Debug, Clone)] -pub enum InstructionOutcome { +pub enum InstructionOutcome<'a> { /// Continue with next instruction. - RunNextInstruction, + ValidateNextInstruction, /// Unreachable instruction reached. Unreachable, + /// Validate block. + ValidateBlock(bool, BlockType, &'a [Opcode]), + /// Validate 2 blocks. + ValidateBlock2(bool, BlockType, &'a [Opcode], &'a [Opcode]), } impl Validator { - pub fn validate_block(context: &mut FunctionValidationContext, is_loop: bool, block_type: BlockType, body: &[Opcode], end_instr: Opcode) -> Result { - if body.is_empty() || body[body.len() - 1] != end_instr { - return Err(Error::Validation("Every block must end with end/else instruction".into())); + pub fn validate_function(context: &mut FunctionValidationContext, block_type: BlockType, body: &[Opcode]) -> Result<(), Error> { + context.push_label(false, block_type)?; + Validator::validate_block(context, body)?; + while !context.frame_stack.is_empty() { + context.pop_label()?; } - context.push_label(is_loop, block_type)?; - for opcode in body { - match Validator::validate_instruction(context, opcode)? { - InstructionOutcome::RunNextInstruction => (), - InstructionOutcome::Unreachable => context.unreachable()?, - } - } - context.pop_label() + Ok(()) } - pub fn validate_instruction(context: &mut FunctionValidationContext, opcode: &Opcode) -> Result { + fn validate_block<'a>(context: &mut FunctionValidationContext, mut body: &[Opcode]) -> Result, Error> { + let mut block_stack = VecDeque::new(); + let mut position = 0; + loop { + let opcode = if position < body.len() { + &body[position] + } else { + let body_and_position = match block_stack.pop_back() { + Some((new_body, new_position, need_pop_value)) => (new_body, new_position, need_pop_value), + None => return Ok(InstructionOutcome::ValidateNextInstruction), + }; + context.pop_label()?; + + if body_and_position.2 { + context.pop_any_value()?; + } + + body = body_and_position.0; + position = body_and_position.1; + + continue; + }; + + match Validator::validate_instruction(context, opcode)? { + InstructionOutcome::ValidateNextInstruction => position += 1, + InstructionOutcome::Unreachable => { + context.unreachable()?; + position += 1; + }, + InstructionOutcome::ValidateBlock(is_loop, block_type, new_body) => { + context.push_label(is_loop, block_type)?; + block_stack.push_back((body, position + 1, false)); + + body = new_body; + position = 0; + }, + InstructionOutcome::ValidateBlock2(is_loop, block_type, new_body, new_body2) => { + let need_pop_value = match block_type { + BlockType::NoResult => false, + BlockType::Value(_) => true, + }; + context.push_label(is_loop, block_type)?; + context.push_label(is_loop, block_type)?; + block_stack.push_back((body, position + 1, false)); + block_stack.push_back((new_body2, 0, need_pop_value)); + + body = new_body; + position = 0; + }, + } + } + } + + pub fn validate_instruction<'a>(context: &mut FunctionValidationContext, opcode: &'a Opcode) -> Result, Error> { // println!("=== VALIDATING {:?}: {:?}", opcode, context.value_stack); match opcode { &Opcode::Unreachable => Ok(InstructionOutcome::Unreachable), - &Opcode::Nop => Ok(InstructionOutcome::RunNextInstruction), - &Opcode::Block(block_type, ref ops) => Validator::validate_block(context, false, block_type, ops.elements(), Opcode::End), + &Opcode::Nop => Ok(InstructionOutcome::ValidateNextInstruction), + &Opcode::Block(block_type, ref ops) => Validator::schedule_validate_block(false, block_type, ops.elements(), Opcode::End), &Opcode::Loop(block_type, ref ops) => Validator::validate_loop(context, block_type, ops.elements()), &Opcode::If(block_type, ref ops) => Validator::validate_if(context, block_type, ops.elements()), - &Opcode::Else => Ok(InstructionOutcome::RunNextInstruction), - &Opcode::End => Ok(InstructionOutcome::RunNextInstruction), + &Opcode::Else => Ok(InstructionOutcome::ValidateNextInstruction), + &Opcode::End => Ok(InstructionOutcome::ValidateNextInstruction), &Opcode::Br(idx) => Validator::validate_br(context, idx), &Opcode::BrIf(idx) => Validator::validate_br_if(context, idx), &Opcode::BrTable(ref table, default) => Validator::validate_br_table(context, table, default), @@ -271,96 +324,96 @@ impl Validator { } } - fn validate_const(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { + fn validate_const<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result, Error> { context.push_value(value_type)?; - Ok(InstructionOutcome::RunNextInstruction) + Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_unop(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { + fn validate_unop<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result, Error> { context.pop_value(value_type)?; context.push_value(value_type)?; - Ok(InstructionOutcome::RunNextInstruction) + Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_binop(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { + fn validate_binop<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result, Error> { context.pop_value(value_type)?; context.pop_value(value_type)?; context.push_value(value_type)?; - Ok(InstructionOutcome::RunNextInstruction) + Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_testop(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { + fn validate_testop<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result, Error> { context.pop_value(value_type)?; context.push_value(ValueType::I32.into())?; - Ok(InstructionOutcome::RunNextInstruction) + Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_relop(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { + fn validate_relop<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result, Error> { context.pop_value(value_type)?; context.pop_value(value_type)?; context.push_value(ValueType::I32.into())?; - Ok(InstructionOutcome::RunNextInstruction) + Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_cvtop(context: &mut FunctionValidationContext, value_type1: StackValueType, value_type2: StackValueType) -> Result { + fn validate_cvtop<'a>(context: &mut FunctionValidationContext, value_type1: StackValueType, value_type2: StackValueType) -> Result, Error> { context.pop_value(value_type1)?; context.push_value(value_type2)?; - Ok(InstructionOutcome::RunNextInstruction) + Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_drop(context: &mut FunctionValidationContext) -> Result { + fn validate_drop<'a>(context: &mut FunctionValidationContext) -> Result, Error> { context.pop_any_value().map(|_| ())?; - Ok(InstructionOutcome::RunNextInstruction) + Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_select(context: &mut FunctionValidationContext) -> Result { + fn validate_select<'a>(context: &mut FunctionValidationContext) -> Result, Error> { context.pop_value(ValueType::I32.into())?; let select_type = context.pop_any_value()?; context.pop_value(select_type)?; context.push_value(select_type)?; - Ok(InstructionOutcome::RunNextInstruction) + Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_get_local(context: &mut FunctionValidationContext, index: u32) -> Result { + fn validate_get_local<'a>(context: &mut FunctionValidationContext, index: u32) -> Result, Error> { let local_type = context.require_local(index)?; context.push_value(local_type)?; - Ok(InstructionOutcome::RunNextInstruction) + Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_set_local(context: &mut FunctionValidationContext, index: u32) -> Result { + fn validate_set_local<'a>(context: &mut FunctionValidationContext, index: u32) -> Result, Error> { let local_type = context.require_local(index)?; let value_type = context.pop_any_value()?; if local_type != value_type { return Err(Error::Validation(format!("Trying to update local {} of type {:?} with value of type {:?}", index, local_type, value_type))); } - Ok(InstructionOutcome::RunNextInstruction) + Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_tee_local(context: &mut FunctionValidationContext, index: u32) -> Result { + fn validate_tee_local<'a>(context: &mut FunctionValidationContext, index: u32) -> Result, Error> { let local_type = context.require_local(index)?; let value_type = context.tee_any_value()?; if local_type != value_type { return Err(Error::Validation(format!("Trying to update local {} of type {:?} with value of type {:?}", index, local_type, value_type))); } - Ok(InstructionOutcome::RunNextInstruction) + Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_get_global(context: &mut FunctionValidationContext, index: u32) -> Result { + fn validate_get_global<'a>(context: &mut FunctionValidationContext, index: u32) -> Result, Error> { let global_type = context.require_global(index, None)?; context.push_value(global_type)?; - Ok(InstructionOutcome::RunNextInstruction) + Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_set_global(context: &mut FunctionValidationContext, index: u32) -> Result { + fn validate_set_global<'a>(context: &mut FunctionValidationContext, index: u32) -> Result, Error> { let global_type = context.require_global(index, Some(true))?; let value_type = context.pop_any_value()?; if global_type != value_type { return Err(Error::Validation(format!("Trying to update global {} of type {:?} with value of type {:?}", index, global_type, value_type))); } - Ok(InstructionOutcome::RunNextInstruction) + Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_load(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: StackValueType) -> Result { + fn validate_load<'a>(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: StackValueType) -> Result, Error> { if align != NATURAL_ALIGNMENT { if 1u32.checked_shl(align).unwrap_or(u32::MAX) > max_align { return Err(Error::Validation(format!("Too large memory alignment 2^{} (expected at most {})", align, max_align))); @@ -370,10 +423,10 @@ impl Validator { context.pop_value(ValueType::I32.into())?; context.require_memory(DEFAULT_MEMORY_INDEX)?; context.push_value(value_type)?; - Ok(InstructionOutcome::RunNextInstruction) + Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_store(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: StackValueType) -> Result { + fn validate_store<'a>(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: StackValueType) -> Result, Error> { if align != NATURAL_ALIGNMENT { if 1u32.checked_shl(align).unwrap_or(u32::MAX) > max_align { return Err(Error::Validation(format!("Too large memory alignment 2^{} (expected at most {})", align, max_align))); @@ -383,14 +436,14 @@ impl Validator { context.require_memory(DEFAULT_MEMORY_INDEX)?; context.pop_value(value_type)?; context.pop_value(ValueType::I32.into())?; - Ok(InstructionOutcome::RunNextInstruction) + Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_loop(context: &mut FunctionValidationContext, block_type: BlockType, body: &[Opcode]) -> Result { - Validator::validate_block(context, true, block_type, body, Opcode::End) + fn validate_loop<'a>(_context: &mut FunctionValidationContext, block_type: BlockType, body: &'a [Opcode]) -> Result, Error> { + Validator::schedule_validate_block(true, block_type, body, Opcode::End) } - fn validate_if(context: &mut FunctionValidationContext, block_type: BlockType, body: &[Opcode]) -> Result { + fn validate_if<'a>(context: &mut FunctionValidationContext, block_type: BlockType, body: &'a [Opcode]) -> Result, Error> { context.pop_value(ValueType::I32.into())?; let body_len = body.len(); @@ -398,18 +451,17 @@ impl Validator { .position(|op| *op == Opcode::Else) .unwrap_or(body_len - 1); if separator_index != body_len - 1 { - Validator::validate_block(context, false, block_type, &body[..separator_index + 1], Opcode::Else)?; - Validator::validate_block(context, false, block_type, &body[separator_index+1..], Opcode::End) + Validator::schedule_validate_block2(false, block_type, &body[..separator_index + 1], Opcode::Else, &body[separator_index+1..], Opcode::End) } else { if block_type != BlockType::NoResult { return Err(Error::Validation(format!("If block without else required to have NoResult block type. But it have {:?} type", block_type))); } - Validator::validate_block(context, false, block_type, body, Opcode::End) + Validator::schedule_validate_block(false, block_type, body, Opcode::End) } } - fn validate_br(context: &mut FunctionValidationContext, idx: u32) -> Result { + fn validate_br<'a>(context: &mut FunctionValidationContext, idx: u32) -> Result, Error> { let (frame_is_loop, frame_block_type) = { let frame = context.require_label(idx)?; (frame.is_loop, frame.block_type) @@ -423,15 +475,15 @@ impl Validator { Ok(InstructionOutcome::Unreachable) } - fn validate_br_if(context: &mut FunctionValidationContext, idx: u32) -> Result { + fn validate_br_if<'a>(context: &mut FunctionValidationContext, idx: u32) -> Result, Error> { context.pop_value(ValueType::I32.into())?; if let BlockType::Value(value_type) = context.require_label(idx)?.block_type { context.tee_value(value_type.into())?; } - Ok(InstructionOutcome::RunNextInstruction) + Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_br_table(context: &mut FunctionValidationContext, table: &Vec, default: u32) -> Result { + fn validate_br_table<'a>(context: &mut FunctionValidationContext, table: &Vec, default: u32) -> Result, Error> { let mut required_block_type = None; { @@ -463,14 +515,14 @@ impl Validator { Ok(InstructionOutcome::Unreachable) } - fn validate_return(context: &mut FunctionValidationContext) -> Result { + fn validate_return<'a>(context: &mut FunctionValidationContext) -> Result, Error> { if let BlockType::Value(value_type) = context.return_type()? { context.tee_value(value_type.into())?; } Ok(InstructionOutcome::Unreachable) } - fn validate_call(context: &mut FunctionValidationContext, idx: u32) -> Result { + fn validate_call<'a>(context: &mut FunctionValidationContext, idx: u32) -> Result, Error> { let (argument_types, return_type) = context.require_function(idx)?; for argument_type in argument_types.iter().rev() { context.pop_value((*argument_type).into())?; @@ -478,10 +530,10 @@ impl Validator { if let BlockType::Value(value_type) = return_type { context.push_value(value_type.into())?; } - Ok(InstructionOutcome::RunNextInstruction) + Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_call_indirect(context: &mut FunctionValidationContext, idx: u32) -> Result { + fn validate_call_indirect<'a>(context: &mut FunctionValidationContext, idx: u32) -> Result, Error> { context.require_table(DEFAULT_TABLE_INDEX, VariableType::AnyFunc)?; context.pop_value(ValueType::I32.into())?; @@ -492,20 +544,39 @@ impl Validator { if let BlockType::Value(value_type) = return_type { context.push_value(value_type.into())?; } - Ok(InstructionOutcome::RunNextInstruction) + Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_current_memory(context: &mut FunctionValidationContext) -> Result { + fn validate_current_memory<'a>(context: &mut FunctionValidationContext) -> Result, Error> { context.require_memory(DEFAULT_MEMORY_INDEX)?; context.push_value(ValueType::I32.into())?; - Ok(InstructionOutcome::RunNextInstruction) + Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_grow_memory(context: &mut FunctionValidationContext) -> Result { + fn validate_grow_memory<'a>(context: &mut FunctionValidationContext) -> Result, Error> { context.require_memory(DEFAULT_MEMORY_INDEX)?; context.pop_value(ValueType::I32.into())?; context.push_value(ValueType::I32.into())?; - Ok(InstructionOutcome::RunNextInstruction) + Ok(InstructionOutcome::ValidateNextInstruction) + } + + fn schedule_validate_block<'a>(is_loop: bool, block_type: BlockType, body: &'a [Opcode], end_instr: Opcode) -> Result, Error> { + if body.is_empty() || body[body.len() - 1] != end_instr { + return Err(Error::Validation("Every block must end with end/else instruction".into())); + } + + Ok(InstructionOutcome::ValidateBlock(is_loop, block_type, body)) + } + + fn schedule_validate_block2<'a>(is_loop: bool, block_type: BlockType, body: &'a [Opcode], end_instr: Opcode, body2: &'a [Opcode], end_instr2: Opcode) -> Result, Error> { + if body.is_empty() || body[body.len() - 1] != end_instr { + return Err(Error::Validation("Every block must end with end/else instruction".into())); + } + if body2.is_empty() || body2[body2.len() - 1] != end_instr2 { + return Err(Error::Validation("Every block must end with end/else instruction".into())); + } + + Ok(InstructionOutcome::ValidateBlock2(is_loop, block_type, body, body2)) } } @@ -594,7 +665,7 @@ impl<'a> FunctionValidationContext<'a> { self.push_value(value_type.into())?; } - Ok(InstructionOutcome::RunNextInstruction) + Ok(InstructionOutcome::ValidateNextInstruction) } pub fn require_label(&self, idx: u32) -> Result<&ValidationFrame, Error> { From 669fdf1ed178e56e54f62b9206122fba220f9836 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Thu, 15 Jun 2017 12:12:21 +0300 Subject: [PATCH 03/11] getting rid of calls recursion (continue) --- src/interpreter/env.rs | 14 +- src/interpreter/env_native.rs | 9 +- src/interpreter/module.rs | 31 ++- src/interpreter/runner.rs | 423 ++++++++++++++++++++++------------ src/interpreter/tests/wabt.rs | 2 +- 5 files changed, 313 insertions(+), 166 deletions(-) diff --git a/src/interpreter/env.rs b/src/interpreter/env.rs index d9c65d2..7596e13 100644 --- a/src/interpreter/env.rs +++ b/src/interpreter/env.rs @@ -7,7 +7,7 @@ use elements::{Module, FunctionType, ExportEntry, Internal, GlobalEntry, GlobalT use interpreter::Error; use interpreter::env_native::NATIVE_INDEX_FUNC_MIN; use interpreter::module::{ModuleInstanceInterface, ModuleInstance, ExecutionParams, - ItemIndex, CallerContext, ExportEntryType}; + ItemIndex, CallerContext, CallResult, ExportEntryType}; use interpreter::memory::{MemoryInstance, LINEAR_MEMORY_PAGE_SIZE}; use interpreter::table::TableInstance; use interpreter::value::RuntimeValue; @@ -124,15 +124,15 @@ impl ModuleInstanceInterface for EnvModuleInstance { self.instance.global(index, variable_type) } - fn call_function(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result, Error> { + fn call_function<'a>(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result, Error> { self.instance.call_function(outer, index, function_type) } - fn call_function_indirect(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result, Error> { + fn call_function_indirect<'a>(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result, Error> { self.instance.call_function_indirect(outer, table_index, type_index, func_index) } - fn call_internal_function(&self, outer: CallerContext, index: u32, _function_type: Option<&FunctionType>) -> Result, Error> { + fn call_internal_function<'a>(&self, outer: CallerContext, index: u32, _function_type: Option<&FunctionType>) -> Result, Error> { // TODO: check function type // to make interpreter independent of *SCRIPTEN runtime, just make abort/assert = interpreter Error match index { @@ -145,12 +145,12 @@ impl ModuleInstanceInterface for EnvModuleInstance { .and_then(|g| g.set(RuntimeValue::I32(1))) .and_then(|_| Err(Error::Trap("assertion failed".into()))) } else { - Ok(None) + Ok(CallResult::Executed(None)) }), - INDEX_FUNC_ENLARGE_MEMORY => Ok(Some(RuntimeValue::I32(0))), // TODO: support memory enlarge + INDEX_FUNC_ENLARGE_MEMORY => Ok(CallResult::Executed(Some(RuntimeValue::I32(0)))), // TODO: support memory enlarge INDEX_FUNC_GET_TOTAL_MEMORY => self.global(ItemIndex::IndexSpace(INDEX_GLOBAL_TOTAL_MEMORY), Some(VariableType::I32)) .map(|g| g.get()) - .map(Some), + .map(|v| CallResult::Executed(Some(v))), INDEX_FUNC_MIN_NONUSED ... INDEX_FUNC_MAX => Err(Error::Trap("unimplemented".into())), _ => Err(Error::Trap(format!("trying to call function with index {} in env module", index))), } diff --git a/src/interpreter/env_native.rs b/src/interpreter/env_native.rs index 19216af..2932bf5 100644 --- a/src/interpreter/env_native.rs +++ b/src/interpreter/env_native.rs @@ -4,7 +4,7 @@ use parking_lot::RwLock; use elements::{FunctionType, Internal, ValueType}; use interpreter::Error; use interpreter::module::{ModuleInstanceInterface, ExecutionParams, ItemIndex, - CallerContext, ExportEntryType}; + CallerContext, CallResult, ExportEntryType}; use interpreter::memory::MemoryInstance; use interpreter::table::TableInstance; use interpreter::value::RuntimeValue; @@ -113,15 +113,15 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { self.env.global(index, variable_type) } - fn call_function(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result, Error> { + fn call_function<'b>(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result, Error> { self.env.call_function(outer, index, function_type) } - fn call_function_indirect(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result, Error> { + fn call_function_indirect<'b>(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result, Error> { self.env.call_function_indirect(outer, table_index, type_index, func_index) } - fn call_internal_function(&self, outer: CallerContext, index: u32, function_type: Option<&FunctionType>) -> Result, Error> { + fn call_internal_function<'b>(&self, outer: CallerContext, index: u32, function_type: Option<&FunctionType>) -> Result, Error> { if index < NATIVE_INDEX_FUNC_MIN { return self.env.call_internal_function(outer, index, function_type); } @@ -131,6 +131,7 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { .get((index - NATIVE_INDEX_FUNC_MIN) as usize) .ok_or(Error::Native(format!("trying to call native function with index {}", index))) .and_then(|f| self.executor.write().execute(&f.name, outer)) + .map(CallResult::Executed) } } diff --git a/src/interpreter/module.rs b/src/interpreter/module.rs index 2f12fc6..b3e9ef9 100644 --- a/src/interpreter/module.rs +++ b/src/interpreter/module.rs @@ -38,6 +38,14 @@ pub enum ExportEntryType { Global(VariableType), } +/// Call result. To eliminate recursion, module must return function body to interpreter or execute function itself if no body available. +pub enum CallResult<'a> { + /// Function is executed with given result. + Executed(Option), + /// Function execution is scheduled. + Scheduled(FunctionContext<'a>, &'a [Opcode]), +} + /// Module instance API. pub trait ModuleInstanceInterface { /// Run instantiation-time procedures (validation and start function call). Module is not completely validated until this call. @@ -57,11 +65,11 @@ pub trait ModuleInstanceInterface { /// Get global reference. fn global(&self, index: ItemIndex, variable_type: Option) -> Result, Error>; /// Call function with given index in functions index space. - fn call_function(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result, Error>; + fn call_function<'a>(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result, Error>; /// Call function with given index in the given table. - fn call_function_indirect(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result, Error>; + fn call_function_indirect<'a>(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result, Error>; /// Call function with internal index. - fn call_internal_function(&self, outer: CallerContext, index: u32, function_type: Option<&FunctionType>) -> Result, Error>; + fn call_internal_function<'a>(&self, outer: CallerContext, index: u32, function_type: Option<&FunctionType>) -> Result, Error>; } /// Item index in items index space. @@ -204,6 +212,13 @@ impl ModuleInstance { _ => Err(Error::Validation(format!("missing function type with index {}", type_index))), }) } + + fn unwrap_call_result(&self, call_result: CallResult) -> Result, Error> { + match call_result { + CallResult::Executed(v) => Ok(v), + CallResult::Scheduled(context, body) => Interpreter::run_function(context, body) + } + } } impl ModuleInstanceInterface for ModuleInstance { @@ -356,7 +371,7 @@ impl ModuleInstanceInterface for ModuleInstance { let args_len = params.args.len(); let mut args = StackWithLimit::with_data(params.args, args_len); let caller_context = CallerContext::topmost(&mut args, ¶ms.externals); - self.call_function(caller_context, ItemIndex::IndexSpace(index), None) + self.unwrap_call_result(self.call_function(caller_context, ItemIndex::IndexSpace(index), None)?) } fn execute_export(&self, name: &str, params: ExecutionParams) -> Result, Error> { @@ -451,7 +466,7 @@ impl ModuleInstanceInterface for ModuleInstance { } } - fn call_function(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result, Error> { + fn call_function<'a>(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result, Error> { match self.imports.parse_function_index(index) { ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"), ItemIndex::Internal(index) => self.call_internal_function(outer, index, function_type), @@ -465,7 +480,7 @@ impl ModuleInstanceInterface for ModuleInstance { } } - fn call_function_indirect(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result, Error> { + fn call_function_indirect<'a>(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result, Error> { let function_type = match self.module.type_section() .ok_or(Error::Function(format!("trying to indirect call function {} with non-existent function section", func_index))) .and_then(|s| s.types().get(type_index as usize) @@ -483,7 +498,7 @@ impl ModuleInstanceInterface for ModuleInstance { module.call_function(outer, ItemIndex::IndexSpace(index), Some(function_type)) } - fn call_internal_function(&self, mut outer: CallerContext, index: u32, function_type: Option<&FunctionType>) -> Result, Error> { + fn call_internal_function<'a>(&self, mut outer: CallerContext, index: u32, function_type: Option<&FunctionType>) -> Result, Error> { // TODO: cache // internal index = index of function in functions section && index of code in code section // get function type index @@ -527,7 +542,7 @@ impl ModuleInstanceInterface for ModuleInstance { let frame_stack_limit = outer.frame_stack_limit; let locals = prepare_function_locals(actual_function_type, function_body, &mut outer)?; let mut innner = FunctionContext::new(self, outer.externals, value_stack_limit, frame_stack_limit, actual_function_type, locals); - Interpreter::run_function(&mut innner, function_code) + Interpreter::run_function(innner, function_code).map(CallResult::Executed) } } diff --git a/src/interpreter/runner.rs b/src/interpreter/runner.rs index 014b534..193c5d7 100644 --- a/src/interpreter/runner.rs +++ b/src/interpreter/runner.rs @@ -2,11 +2,11 @@ use std::mem; use std::ops; use std::u32; use std::sync::Arc; -use std::fmt::Display; +use std::fmt::{self, Display}; use std::collections::{HashMap, VecDeque}; use elements::{Opcode, BlockType, FunctionType}; use interpreter::Error; -use interpreter::module::{ModuleInstance, ModuleInstanceInterface, CallerContext, ItemIndex}; +use interpreter::module::{ModuleInstance, ModuleInstanceInterface, CallerContext, CallResult, ItemIndex}; use interpreter::stack::StackWithLimit; use interpreter::value::{ RuntimeValue, TryInto, WrapInto, TryTruncateInto, ExtendInto, @@ -40,22 +40,28 @@ pub struct FunctionContext<'a> { pub position: usize, } -#[derive(Debug, Clone)] -pub enum InstructionOutcome<'a> { +/// Interpreter action to execute after executing instruction. +#[derive(Debug)] +pub enum InstructionOutcome { /// Continue with current instruction. RunInstruction, /// Continue with next instruction. RunNextInstruction, /// Branch to given frame. Branch(usize), + /// Execute block. + ExecuteBlock(bool), + /// Execute function call. + ExecuteCall(u32), + /// Execute indirect function call. + ExecuteIndirectCall(u32, u32, u32), /// End current frame. End, /// Return from current function block. Return, - /// Execute block. - ExecuteBlock(&'a [Opcode]), } +/// Control stack frame. #[derive(Debug, Clone)] pub struct BlockFrame { /// Is loop frame? @@ -71,23 +77,169 @@ pub struct BlockFrame { } impl Interpreter { - pub fn run_function(context: &mut FunctionContext, body: &[Opcode]) -> Result, Error> { - let return_type = context.return_type; - context.push_frame(false, body.len() - 1, body.len() - 1, return_type)?; + pub fn run_function(mut context: FunctionContext, body: &[Opcode]) -> Result, Error> { + let mut context_depth = 0usize; + let mut context_stack = VecDeque::new(); + let mut blocks_stack = VecDeque::new(); - Interpreter::execute_block(context, body)?; - match context.return_type { - BlockType::Value(_) => Ok(Some(context.value_stack_mut().pop()?)), - BlockType::NoResult => Ok(None), + { + let return_type = context.return_type; + context.push_frame(false, body.len() - 1, body.len() - 1, return_type)?; + context.position = 0; + + context_stack.push_back(context); + blocks_stack.push_back((1, body)); + } + + loop { // functions loop + let function_return = { + let context = context_stack.back_mut().unwrap(); + Interpreter::run_function_blocks(context_depth, &mut blocks_stack, context)? + }; + match function_return { + InstructionOutcome::ExecuteCall(func_idx) => { + let context = context_stack.back_mut().unwrap(); + match context.call_function(func_idx)? { + CallResult::Executed(result) => if let Some(result) = result { + context.value_stack_mut().push(result)?; + }, + CallResult::Scheduled(new_context, body) => { + unimplemented!() + }, + } + }, + InstructionOutcome::ExecuteIndirectCall(table_idx, type_idx, func_idx) => { + let context = context_stack.back_mut().unwrap(); + match context.call_function_indirect(table_idx, type_idx, func_idx)? { + CallResult::Executed(result) => if let Some(result) = result { + context.value_stack_mut().push(result)?; + }, + CallResult::Scheduled(new_context, body) => { + unimplemented!() + }, + } + }, + InstructionOutcome::Return => { + // return function value + let mut context = context_stack.pop_back().unwrap(); + let return_value = match context.return_type { + BlockType::Value(_) => Some(context.value_stack_mut().pop()?), + BlockType::NoResult => None, + }; + + match context_stack.back_mut() { + None => return Ok(return_value), + Some(context) => if let Some(return_value) = return_value { + context.value_stack_mut().push(return_value)?; + }, + } + }, + InstructionOutcome::RunInstruction | InstructionOutcome::RunNextInstruction | InstructionOutcome::Branch(_) + | InstructionOutcome::ExecuteBlock(_) | InstructionOutcome::End => unreachable!("managed by run_function_blocks"), + /*CallResult::Executed(result) => { + context_stack.pop_back(); + match context_stack.back_mut() { + None => return Ok(result), + Some(context) => match result { + Some(result) => context.value_stack_mut().push(result)?, + None => (), + } + } + + context_depth -= 1; + }, + CallResult::Scheduled(context, body) => { + context_depth += 1; + + context_stack.push_back(context); + blocks_stack.push_back((context_depth, body)); + },*/ + } } } - fn run_instruction<'a>(context: &mut FunctionContext, opcode: &'a Opcode) -> Result, Error> { + fn run_function_blocks<'a, 'b, 'c>(current_depth: usize, blocks_stack: &'b mut VecDeque<(usize, &'a [Opcode])>, context: &'c mut FunctionContext<'a>) -> Result where 'a: 'b { + loop { // blocks loop + let block_return = { + let block = match blocks_stack.back() { + Some(block) => block, + None => return Ok(InstructionOutcome::Return), + }; + + assert!(block.0 >= current_depth); + if block.0 < current_depth { + return Ok(InstructionOutcome::Return); + } + + let block_body = block.1; + Interpreter::run_block_instructions(context, block_body)? + }; + + match block_return { + InstructionOutcome::RunInstruction | InstructionOutcome::RunNextInstruction => unreachable!("resolved by run_block_instructions"), + InstructionOutcome::ExecuteCall(func_idx) => return Ok(InstructionOutcome::ExecuteCall(func_idx)), + InstructionOutcome::ExecuteIndirectCall(table_idx, type_idx, func_idx) => return Ok(InstructionOutcome::ExecuteIndirectCall(table_idx, type_idx, func_idx)), + InstructionOutcome::ExecuteBlock(branch) => { + let nested_block = Interpreter::into_block(&blocks_stack.back().unwrap().1[context.position], branch)?; + blocks_stack.push_back((current_depth, nested_block)); + context.position = 0; + }, + InstructionOutcome::Branch(mut index) => { + // discard index - 1 blocks + while index >= 1 { + context.discard_frame()?; + assert!(blocks_stack.pop_back().is_some()); + index -= 1; + } + + context.pop_frame(true)?; + assert!(blocks_stack.pop_back().is_some()); + } + InstructionOutcome::End => { + // pop single block + context.pop_frame(false)?; + assert!(blocks_stack.pop_back().is_some()); + }, + InstructionOutcome::Return => { + // discard all function blocks + while context.frame_stack.len() > 0 { + context.discard_frame()?; + assert!(blocks_stack.pop_back().is_some()); + } + } + } + } + } + + fn run_block_instructions<'a>(context: &mut FunctionContext<'a>, body: &'a [Opcode]) -> Result { + loop { + let instruction = &body[context.position]; + + match Interpreter::run_instruction(context, instruction)? { + InstructionOutcome::RunInstruction => (), + InstructionOutcome::RunNextInstruction => context.position += 1, + InstructionOutcome::Branch(index) => return Ok(InstructionOutcome::Branch(index)), + InstructionOutcome::ExecuteBlock(branch) => return Ok(InstructionOutcome::ExecuteBlock(branch)), + InstructionOutcome::ExecuteCall(func_idx) => { + context.position += 1; + return Ok(InstructionOutcome::ExecuteCall(func_idx)); + }, + InstructionOutcome::ExecuteIndirectCall(table_idx, type_idx, func_idx) => { + context.position += 1; + return Ok(InstructionOutcome::ExecuteIndirectCall(table_idx, type_idx, func_idx)); + }, + InstructionOutcome::End => return Ok(InstructionOutcome::End), + InstructionOutcome::Return => return Ok(InstructionOutcome::Return), + } + } + } + + fn run_instruction<'a>(context: &mut FunctionContext, opcode: &'a Opcode) -> Result { 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::Block(block_type, _) => Interpreter::run_block(context, block_type), + &Opcode::Loop(block_type, ref ops) => Interpreter::run_loop(context, block_type), &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), @@ -276,57 +428,72 @@ impl Interpreter { } } - fn run_unreachable<'a>(_context: &mut FunctionContext) -> Result, Error> { - Err(Error::Trap("programmatic".into())) + fn into_block(opcode: &Opcode, branch: bool) -> Result<&[Opcode], Error> { + match opcode { + &Opcode::Block(_, ref ops) if branch => Ok(ops.elements()), + &Opcode::Loop(_, ref ops) if branch => Ok(ops.elements()), + &Opcode::If(_, ref ops) => Ok(Interpreter::separate_if(ops.elements(), branch)), + _ => Err(Error::Interpreter("trying to read block from non-bock instruction".into())) + } } - fn run_nop<'a>(_context: &mut FunctionContext) -> Result, Error> { - Ok(InstructionOutcome::RunNextInstruction) - } - - fn run_block<'a>(context: &mut FunctionContext, block_type: BlockType, body: &'a [Opcode]) -> Result, Error> { - let frame_position = context.position + 1; - context.push_frame(false, frame_position, frame_position, block_type.clone())?; - Ok(InstructionOutcome::ExecuteBlock(body)) - } - - fn run_loop<'a>(context: &mut FunctionContext, block_type: BlockType, body: &'a [Opcode]) -> Result, Error> { - let frame_position = context.position; - context.push_frame(true, frame_position, frame_position + 1, block_type.clone())?; - Ok(InstructionOutcome::ExecuteBlock(body)) - } - - fn run_if<'a>(context: &mut FunctionContext, block_type: BlockType, body: &'a [Opcode]) -> Result, Error> { + fn separate_if(body: &[Opcode], branch: bool) -> &[Opcode] { let body_len = body.len(); let else_index = body.iter().position(|op| *op == Opcode::Else).unwrap_or(body_len - 1); - let (begin_index, end_index) = if context.value_stack_mut().pop_as()? { + let (begin_index, end_index) = if branch { (0, else_index + 1) } else { (else_index + 1, body_len) }; + &body[begin_index..end_index] + } - if begin_index != end_index { + fn run_unreachable<'a>(_context: &mut FunctionContext) -> Result { + Err(Error::Trap("programmatic".into())) + } + + fn run_nop<'a>(_context: &mut FunctionContext) -> Result { + Ok(InstructionOutcome::RunNextInstruction) + } + + fn run_block<'a>(context: &mut FunctionContext, block_type: BlockType) -> Result { + let frame_position = context.position + 1; + context.push_frame(false, frame_position, frame_position, block_type)?; + Ok(InstructionOutcome::ExecuteBlock(true)) + } + + fn run_loop<'a>(context: &mut FunctionContext, block_type: BlockType) -> Result { + let frame_position = context.position; + context.push_frame(true, frame_position, frame_position + 1, block_type.clone())?; + Ok(InstructionOutcome::ExecuteBlock(true)) + } + + fn run_if<'a>(context: &mut FunctionContext, block_type: BlockType, body: &'a [Opcode]) -> Result { + let branch = context.value_stack_mut().pop_as()?; + let branch_body = Interpreter::separate_if(body, branch); + + if branch_body.len() != 0 { let frame_position = context.position + 1; context.push_frame(false, frame_position, frame_position, block_type.clone())?; - Ok(InstructionOutcome::ExecuteBlock(&body[begin_index..end_index])) + Ok(InstructionOutcome::ExecuteBlock(branch)) } else { Ok(InstructionOutcome::RunNextInstruction) } } - fn run_else<'a>(_context: &mut FunctionContext) -> Result, Error> { + fn run_else<'a>(_context: &mut FunctionContext) -> Result { Ok(InstructionOutcome::End) } - fn run_end<'a>(_context: &mut FunctionContext) -> Result, Error> { + fn run_end<'a>(_context: &mut FunctionContext) -> Result { Ok(InstructionOutcome::End) } - fn run_br<'a>(_context: &mut FunctionContext, label_idx: u32) -> Result, Error> { + fn run_br<'a>(_context: &mut FunctionContext, label_idx: u32) -> Result { Ok(InstructionOutcome::Branch(label_idx as usize)) } - fn run_br_if<'a>(context: &mut FunctionContext, label_idx: u32) -> Result, Error> { + fn run_br_if<'a>(context: &mut FunctionContext, label_idx: u32) -> Result { if context.value_stack_mut().pop_as()? { Ok(InstructionOutcome::Branch(label_idx as usize)) } else { @@ -334,36 +501,38 @@ impl Interpreter { } } - fn run_br_table<'a>(context: &mut FunctionContext, table: &Vec, default: u32) -> Result, Error> { + fn run_br_table<'a>(context: &mut FunctionContext, table: &Vec, default: u32) -> Result { let index: u32 = context.value_stack_mut().pop_as()?; Ok(InstructionOutcome::Branch(table.get(index as usize).cloned().unwrap_or(default) as usize)) } - fn run_return<'a>(_context: &mut FunctionContext) -> Result, Error> { + fn run_return<'a>(_context: &mut FunctionContext) -> Result { Ok(InstructionOutcome::Return) } - fn run_call<'a>(context: &mut FunctionContext, func_idx: u32) -> Result, Error> { - context.call_function(func_idx) + fn run_call<'a>(context: &mut FunctionContext, func_idx: u32) -> Result { + Ok(InstructionOutcome::ExecuteCall(func_idx)) + /*context.call_function(func_idx) .and_then(|r| r.map(|r| context.value_stack_mut().push(r)).unwrap_or(Ok(()))) - .map(|_| InstructionOutcome::RunNextInstruction) + .map(|_| InstructionOutcome::RunNextInstruction)*/ } - fn run_call_indirect<'a>(context: &mut FunctionContext, type_idx: u32) -> Result, Error> { + fn run_call_indirect<'a>(context: &mut FunctionContext, type_idx: u32) -> Result { let table_func_idx: u32 = context.value_stack_mut().pop_as()?; - context.call_function_indirect(DEFAULT_TABLE_INDEX, type_idx, table_func_idx) + Ok(InstructionOutcome::ExecuteIndirectCall(DEFAULT_TABLE_INDEX, type_idx, table_func_idx)) + /*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) + .map(|_| InstructionOutcome::RunNextInstruction)*/ } - fn run_drop<'a>(context: &mut FunctionContext) -> Result, Error> { + fn run_drop<'a>(context: &mut FunctionContext) -> Result { context .value_stack_mut() .pop() .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_select<'a>(context: &mut FunctionContext) -> Result, Error> { + fn run_select<'a>(context: &mut FunctionContext) -> Result { context .value_stack_mut() .pop_triple() @@ -378,32 +547,32 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_get_local<'a>(context: &mut FunctionContext, index: u32) -> Result, Error> { + fn run_get_local<'a>(context: &mut FunctionContext, index: u32) -> Result { context.get_local(index as usize) .map(|value| context.value_stack_mut().push(value)) .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_set_local<'a>(context: &mut FunctionContext, index: u32) -> Result, Error> { + fn run_set_local<'a>(context: &mut FunctionContext, index: u32) -> Result { let arg = context.value_stack_mut().pop()?; context.set_local(index as usize, arg) .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_tee_local<'a>(context: &mut FunctionContext, index: u32) -> Result, Error> { + fn run_tee_local<'a>(context: &mut FunctionContext, index: u32) -> Result { let arg = context.value_stack().top()?.clone(); context.set_local(index as usize, arg) .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_get_global<'a>(context: &mut FunctionContext, index: u32) -> Result, Error> { + fn run_get_global<'a>(context: &mut FunctionContext, index: u32) -> Result { context.module() .global(ItemIndex::IndexSpace(index), None) .and_then(|g| context.value_stack_mut().push(g.get())) .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_set_global<'a>(context: &mut FunctionContext, index: u32) -> Result, Error> { + fn run_set_global<'a>(context: &mut FunctionContext, index: u32) -> Result { context .value_stack_mut() .pop() @@ -411,7 +580,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_load<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result, Error> + fn run_load<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result where RuntimeValue: From, T: LittleEndianConvert { let address = effective_address(offset, context.value_stack_mut().pop_as()?)?; context.module() @@ -422,7 +591,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_load_extend<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result, Error> + fn run_load_extend<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result where T: ExtendInto, RuntimeValue: From, T: LittleEndianConvert { let address = effective_address(offset, context.value_stack_mut().pop_as()?)?; let stack_value: U = context.module() @@ -436,7 +605,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_store<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result, Error> + fn run_store<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result where RuntimeValue: TryInto, T: LittleEndianConvert { let stack_value = context .value_stack_mut() @@ -449,7 +618,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_store_wrap<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result, Error> + fn run_store_wrap<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result where RuntimeValue: TryInto, T: WrapInto, U: LittleEndianConvert { let stack_value: T = context.value_stack_mut().pop().and_then(|v| v.try_into())?; let stack_value = stack_value.wrap_into().into_little_endian(); @@ -460,7 +629,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_current_memory<'a>(context: &mut FunctionContext) -> Result, Error> { + fn run_current_memory<'a>(context: &mut FunctionContext) -> Result { context.module() .memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX)) .map(|m| m.size()) @@ -468,7 +637,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_grow_memory<'a>(context: &mut FunctionContext) -> Result, Error> { + fn run_grow_memory<'a>(context: &mut FunctionContext) -> Result { let pages: u32 = context.value_stack_mut().pop_as()?; context.module() .memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX)) @@ -477,14 +646,14 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_const<'a>(context: &mut FunctionContext, val: RuntimeValue) -> Result, Error> { + fn run_const<'a>(context: &mut FunctionContext, val: RuntimeValue) -> Result { context .value_stack_mut() .push(val) .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_eqz<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_eqz<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: TryInto, T: PartialEq + Default { context .value_stack_mut() @@ -494,7 +663,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_eq<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_eq<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: TryInto, T: PartialEq { context .value_stack_mut() @@ -504,7 +673,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_ne<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_ne<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: TryInto, T: PartialEq { context .value_stack_mut() @@ -514,7 +683,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_lt<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_lt<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: TryInto, T: PartialOrd + Display { context .value_stack_mut() @@ -524,7 +693,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_gt<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_gt<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: TryInto, T: PartialOrd { context .value_stack_mut() @@ -534,7 +703,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_lte<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_lte<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: TryInto, T: PartialOrd { context .value_stack_mut() @@ -544,7 +713,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_gte<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_gte<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: TryInto, T: PartialOrd { context .value_stack_mut() @@ -554,7 +723,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_clz<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_clz<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Integer { context .value_stack_mut() @@ -564,7 +733,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_ctz<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_ctz<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Integer { context .value_stack_mut() @@ -574,7 +743,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_popcnt<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_popcnt<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Integer { context .value_stack_mut() @@ -584,7 +753,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_add<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_add<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: ArithmeticOps { context .value_stack_mut() @@ -594,7 +763,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_sub<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_sub<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: ArithmeticOps { context .value_stack_mut() @@ -604,7 +773,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_mul<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_mul<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: ArithmeticOps { context .value_stack_mut() @@ -614,7 +783,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_div<'a, T, U>(context: &mut FunctionContext) -> Result, Error> + fn run_div<'a, T, U>(context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: TransmuteInto + Display, U: ArithmeticOps + TransmuteInto { context .value_stack_mut() @@ -626,7 +795,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_rem<'a, T, U>(context: &mut FunctionContext) -> Result, Error> + fn run_rem<'a, T, U>(context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: TransmuteInto, U: Integer + TransmuteInto { context .value_stack_mut() @@ -638,7 +807,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_and<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_and<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: From<::Output> + TryInto, T: ops::BitAnd { context .value_stack_mut() @@ -648,7 +817,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_or<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_or<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: From<::Output> + TryInto, T: ops::BitOr { context .value_stack_mut() @@ -658,7 +827,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_xor<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_xor<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: From<::Output> + TryInto, T: ops::BitXor { context .value_stack_mut() @@ -668,7 +837,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_shl<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_shl<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: From<>::Output> + TryInto, T: ops::Shl { context .value_stack_mut() @@ -678,7 +847,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_shr<'a, T, U>(context: &mut FunctionContext) -> Result, Error> + fn run_shr<'a, T, U>(context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: TransmuteInto, U: ops::Shr, >::Output: TransmuteInto { context .value_stack_mut() @@ -690,7 +859,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_rotl<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_rotl<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Integer { context .value_stack_mut() @@ -700,7 +869,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_rotr<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_rotr<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Integer { context .value_stack_mut() @@ -710,7 +879,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_abs<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_abs<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -720,7 +889,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_neg<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_neg<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: From<::Output> + TryInto, T: ops::Neg { context .value_stack_mut() @@ -730,7 +899,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_ceil<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_ceil<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -740,7 +909,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_floor<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_floor<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -750,7 +919,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_trunc<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_trunc<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -760,7 +929,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_nearest<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_nearest<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -770,7 +939,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_sqrt<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_sqrt<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -780,7 +949,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_min<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_min<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -790,7 +959,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_max<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_max<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -800,7 +969,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_copysign<'a, T>(context: &mut FunctionContext) -> Result, Error> + fn run_copysign<'a, T>(context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -810,7 +979,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_wrap<'a, T, U>(context: &mut FunctionContext) -> Result, Error> + fn run_wrap<'a, T, U>(context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: WrapInto { context .value_stack_mut() @@ -820,7 +989,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_trunc_to_int<'a, T, U, V>(context: &mut FunctionContext) -> Result, Error> + fn run_trunc_to_int<'a, T, U, V>(context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: TryTruncateInto, U: TransmuteInto, { context .value_stack_mut() @@ -831,7 +1000,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_extend<'a, T, U, V>(context: &mut FunctionContext) -> Result, Error> + fn run_extend<'a, T, U, V>(context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: ExtendInto, U: TransmuteInto { context .value_stack_mut() @@ -842,7 +1011,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_reinterpret<'a, T, U>(context: &mut FunctionContext) -> Result, Error> + fn run_reinterpret<'a, T, U>(context: &mut FunctionContext) -> Result where RuntimeValue: From, RuntimeValue: TryInto, T: TransmuteInto { context .value_stack_mut() @@ -851,50 +1020,6 @@ impl Interpreter { .and_then(|val| context.value_stack_mut().push(val.into())) .map(|_| InstructionOutcome::RunNextInstruction) } - - fn execute_block<'a>(context: &mut FunctionContext, mut body: &[Opcode]) -> Result, Error> { - debug_assert!(!context.frame_stack.is_empty()); - - // run instructions - let mut block_stack = VecDeque::new(); - context.position = 0; - loop { - let instruction = &body[context.position]; - - // println!("=== RUNNING {:?}", instruction); // TODO: trace - match Interpreter::run_instruction(context, instruction)? { - InstructionOutcome::RunInstruction => (), - InstructionOutcome::RunNextInstruction => context.position += 1, - InstructionOutcome::Branch(mut index) => { - while index >= 1 { - context.discard_frame()?; - // there is block in block stack for each frame in context - assert!(block_stack.pop_back().is_some()); - index -= 1; - } - - body = match block_stack.pop_back() { - Some(body) => body, - None => return Ok(InstructionOutcome::Return), - }; - context.pop_frame(true)?; - }, - InstructionOutcome::End => { - body = match block_stack.pop_back() { - Some(body) => body, - None => return Ok(InstructionOutcome::Return), - }; - context.pop_frame(false)?; - }, - InstructionOutcome::Return => return Ok(InstructionOutcome::Return), - InstructionOutcome::ExecuteBlock(new_body) => { - block_stack.push_back(body); - body = new_body; - context.position = 0; - }, - } - } - } } impl<'a> FunctionContext<'a> { @@ -918,11 +1043,11 @@ impl<'a> FunctionContext<'a> { &self.externals } - pub fn call_function(&mut self, index: u32) -> Result, Error> { + pub fn call_function<'b>(&mut self, index: u32) -> Result, Error> { self.module.call_function(CallerContext::nested(self), ItemIndex::IndexSpace(index), None) } - pub fn call_function_indirect(&mut self, table_index: u32, type_index: u32, func_index: u32) -> Result, Error> { + pub fn call_function_indirect<'b>(&mut self, table_index: u32, type_index: u32, func_index: u32) -> Result, Error> { self.module.call_function_indirect(CallerContext::nested(self), ItemIndex::IndexSpace(table_index), type_index, func_index) } @@ -986,6 +1111,12 @@ impl<'a> FunctionContext<'a> { } } +impl<'a> fmt::Debug for FunctionContext<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "FunctionContext") + } +} + impl BlockFrame { pub fn invalid() -> Self { BlockFrame { diff --git a/src/interpreter/tests/wabt.rs b/src/interpreter/tests/wabt.rs index 0897212..6616d0c 100644 --- a/src/interpreter/tests/wabt.rs +++ b/src/interpreter/tests/wabt.rs @@ -20,7 +20,7 @@ fn run_function_i32(body: &Opcodes, arg: i32) -> Result { VariableInstance::new(true, VariableType::I32, RuntimeValue::I32(0)).unwrap(), // local1 VariableInstance::new(true, VariableType::I32, RuntimeValue::I32(0)).unwrap(), // local2 ]); - Interpreter::run_function(&mut context, body.elements()) + Interpreter::run_function(context, body.elements()) .map(|v| v.unwrap().try_into().unwrap()) } From 0fc044cb5ad8eeeb66637aee4644ef44454029c8 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Fri, 16 Jun 2017 12:23:49 +0300 Subject: [PATCH 04/11] flush --- src/interpreter/env.rs | 28 ++- src/interpreter/env_native.rs | 19 +- src/interpreter/module.rs | 257 ++++++++++++++----- src/interpreter/runner.rs | 457 +++++++++++++++++----------------- src/interpreter/stack.rs | 20 ++ src/interpreter/tests/wabt.rs | 163 ++++++------ 6 files changed, 557 insertions(+), 387 deletions(-) diff --git a/src/interpreter/env.rs b/src/interpreter/env.rs index 7596e13..1e29429 100644 --- a/src/interpreter/env.rs +++ b/src/interpreter/env.rs @@ -7,7 +7,7 @@ use elements::{Module, FunctionType, ExportEntry, Internal, GlobalEntry, GlobalT use interpreter::Error; use interpreter::env_native::NATIVE_INDEX_FUNC_MIN; use interpreter::module::{ModuleInstanceInterface, ModuleInstance, ExecutionParams, - ItemIndex, CallerContext, CallResult, ExportEntryType}; + ItemIndex, CallerContext, ExportEntryType, InternalFunctionReference, InternalFunction}; use interpreter::memory::{MemoryInstance, LINEAR_MEMORY_PAGE_SIZE}; use interpreter::table::TableInstance; use interpreter::value::RuntimeValue; @@ -124,15 +124,27 @@ impl ModuleInstanceInterface for EnvModuleInstance { self.instance.global(index, variable_type) } - fn call_function<'a>(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result, Error> { + fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap>>) -> Result, Error> { + self.instance.function_reference(index, externals) + } + + fn function_reference_indirect<'a>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'a HashMap>>) -> Result, Error> { + self.instance.function_reference_indirect(table_idx, type_idx, func_idx, externals) + } + + fn function_body<'a>(&'a self, internal_index: u32) -> Result>, Error> { + self.instance.function_body(internal_index) + } + + /*fn call_function(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result, Error> { self.instance.call_function(outer, index, function_type) } - fn call_function_indirect<'a>(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result, Error> { + fn call_function_indirect(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result, Error> { self.instance.call_function_indirect(outer, table_index, type_index, func_index) - } + }*/ - fn call_internal_function<'a>(&self, outer: CallerContext, index: u32, _function_type: Option<&FunctionType>) -> Result, Error> { + fn call_internal_function(&self, outer: CallerContext, index: u32, _function_type: Option<&FunctionType>) -> Result, Error> { // TODO: check function type // to make interpreter independent of *SCRIPTEN runtime, just make abort/assert = interpreter Error match index { @@ -145,12 +157,12 @@ impl ModuleInstanceInterface for EnvModuleInstance { .and_then(|g| g.set(RuntimeValue::I32(1))) .and_then(|_| Err(Error::Trap("assertion failed".into()))) } else { - Ok(CallResult::Executed(None)) + Ok(None) }), - INDEX_FUNC_ENLARGE_MEMORY => Ok(CallResult::Executed(Some(RuntimeValue::I32(0)))), // TODO: support memory enlarge + INDEX_FUNC_ENLARGE_MEMORY => Ok(Some(RuntimeValue::I32(0))), // TODO: support memory enlarge INDEX_FUNC_GET_TOTAL_MEMORY => self.global(ItemIndex::IndexSpace(INDEX_GLOBAL_TOTAL_MEMORY), Some(VariableType::I32)) .map(|g| g.get()) - .map(|v| CallResult::Executed(Some(v))), + .map(Some), INDEX_FUNC_MIN_NONUSED ... INDEX_FUNC_MAX => Err(Error::Trap("unimplemented".into())), _ => Err(Error::Trap(format!("trying to call function with index {} in env module", index))), } diff --git a/src/interpreter/env_native.rs b/src/interpreter/env_native.rs index 2932bf5..9edd21a 100644 --- a/src/interpreter/env_native.rs +++ b/src/interpreter/env_native.rs @@ -1,10 +1,10 @@ use std::sync::Arc; use std::collections::HashMap; use parking_lot::RwLock; -use elements::{FunctionType, Internal, ValueType}; +use elements::{FunctionType, Internal, ValueType, Opcode}; use interpreter::Error; use interpreter::module::{ModuleInstanceInterface, ExecutionParams, ItemIndex, - CallerContext, CallResult, ExportEntryType}; + CallerContext, ExportEntryType, InternalFunctionReference, InternalFunction}; use interpreter::memory::MemoryInstance; use interpreter::table::TableInstance; use interpreter::value::RuntimeValue; @@ -113,15 +113,19 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { self.env.global(index, variable_type) } - fn call_function<'b>(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result, Error> { - self.env.call_function(outer, index, function_type) + fn function_reference<'b>(&self, index: ItemIndex, externals: Option<&'b HashMap>>) -> Result, Error> { + self.env.function_reference(index, externals) } - fn call_function_indirect<'b>(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result, Error> { - self.env.call_function_indirect(outer, table_index, type_index, func_index) + fn function_reference_indirect<'b>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'b HashMap>>) -> Result, Error> { + self.env.function_reference_indirect(table_idx, type_idx, func_idx, externals) } - fn call_internal_function<'b>(&self, outer: CallerContext, index: u32, function_type: Option<&FunctionType>) -> Result, Error> { + fn function_body<'b>(&'b self, internal_index: u32) -> Result>, Error> { + self.env.function_body(internal_index) + } + + fn call_internal_function(&self, outer: CallerContext, index: u32, function_type: Option<&FunctionType>) -> Result, Error> { if index < NATIVE_INDEX_FUNC_MIN { return self.env.call_internal_function(outer, index, function_type); } @@ -131,7 +135,6 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { .get((index - NATIVE_INDEX_FUNC_MIN) as usize) .ok_or(Error::Native(format!("trying to call native function with index {}", index))) .and_then(|f| self.executor.write().execute(&f.name, outer)) - .map(CallResult::Executed) } } diff --git a/src/interpreter/module.rs b/src/interpreter/module.rs index b3e9ef9..486f283 100644 --- a/src/interpreter/module.rs +++ b/src/interpreter/module.rs @@ -1,7 +1,8 @@ use std::collections::HashMap; use std::iter::repeat; use std::sync::{Arc, Weak}; -use elements::{Module, InitExpr, Opcode, Type, FunctionType, FuncBody, Internal, External, BlockType, ResizableLimits}; +use std::fmt; +use elements::{Module, InitExpr, Opcode, Type, FunctionType, FuncBody, Internal, External, BlockType, ResizableLimits, Local}; use interpreter::Error; use interpreter::imports::ModuleImports; use interpreter::memory::MemoryInstance; @@ -16,7 +17,7 @@ use interpreter::variable::{VariableInstance, VariableType}; /// Maximum number of entries in value stack. const DEFAULT_VALUE_STACK_LIMIT: usize = 16384; /// Maximum number of entries in frame stack. -const DEFAULT_FRAME_STACK_LIMIT: usize = 128; // TODO: fix runner to support bigger depth +const DEFAULT_FRAME_STACK_LIMIT: usize = 1024; /// Execution context. #[derive(Default, Clone)] @@ -38,14 +39,6 @@ pub enum ExportEntryType { Global(VariableType), } -/// Call result. To eliminate recursion, module must return function body to interpreter or execute function itself if no body available. -pub enum CallResult<'a> { - /// Function is executed with given result. - Executed(Option), - /// Function execution is scheduled. - Scheduled(FunctionContext<'a>, &'a [Opcode]), -} - /// Module instance API. pub trait ModuleInstanceInterface { /// Run instantiation-time procedures (validation and start function call). Module is not completely validated until this call. @@ -64,12 +57,18 @@ pub trait ModuleInstanceInterface { fn memory(&self, index: ItemIndex) -> Result, Error>; /// Get global reference. fn global(&self, index: ItemIndex, variable_type: Option) -> Result, Error>; + /// Get function reference. + fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap>>) -> Result, Error>; + /// Get function indirect reference. + fn function_reference_indirect<'a>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'a HashMap>>) -> Result, Error>; + /// Get internal function for interpretation. + fn function_body<'a>(&'a self, internal_index: u32) -> Result>, Error>; /// Call function with given index in functions index space. - fn call_function<'a>(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result, Error>; + //fn call_function<'a>(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result, Error>; /// Call function with given index in the given table. - fn call_function_indirect<'a>(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result, Error>; + //fn call_function_indirect<'a>(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result, Error>; /// Call function with internal index. - fn call_internal_function<'a>(&self, outer: CallerContext, index: u32, function_type: Option<&FunctionType>) -> Result, Error>; + fn call_internal_function<'a>(&self, outer: CallerContext, index: u32, function_type: Option<&FunctionType>) -> Result, Error>; } /// Item index in items index space. @@ -111,6 +110,33 @@ pub struct CallerContext<'a> { pub externals: &'a HashMap>, } +/// Internal function reference. +#[derive(Clone)] +pub struct InternalFunctionReference<'a> { + /// Module reference. + pub module: Arc, + /// Internal function index. + pub internal_index: u32, + // Internal function type. + //pub function_type: &'a FunctionType, +} + +impl<'a> fmt::Debug for InternalFunctionReference<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "InternalFunctionReference") + } +} + +/// Internal function ready for interpretation. +pub struct InternalFunction<'a> { + /// Function type. + pub func_type: &'a FunctionType, + /// Function locals. + pub locals: &'a [Local], + /// Function body. + pub body: &'a [Opcode], +} + impl<'a> ExecutionParams<'a> { /// Create new execution params with given externa; module override. pub fn with_external(name: String, module: Arc) -> Self { @@ -185,6 +211,10 @@ impl ModuleInstance { }) } + fn self_ref<'a>(&self, externals: Option<&'a HashMap>>) -> Result, Error> { + self.imports.module(externals, &self.name) + } + fn require_function(&self, index: ItemIndex) -> Result { match self.imports.parse_function_index(index) { ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"), @@ -212,13 +242,6 @@ impl ModuleInstance { _ => Err(Error::Validation(format!("missing function type with index {}", type_index))), }) } - - fn unwrap_call_result(&self, call_result: CallResult) -> Result, Error> { - match call_result { - CallResult::Executed(v) => Ok(v), - CallResult::Scheduled(context, body) => Interpreter::run_function(context, body) - } - } } impl ModuleInstanceInterface for ModuleInstance { @@ -368,10 +391,12 @@ impl ModuleInstanceInterface for ModuleInstance { } fn execute_index(&self, index: u32, params: ExecutionParams) -> Result, Error> { - let args_len = params.args.len(); - let mut args = StackWithLimit::with_data(params.args, args_len); - let caller_context = CallerContext::topmost(&mut args, ¶ms.externals); - self.unwrap_call_result(self.call_function(caller_context, ItemIndex::IndexSpace(index), None)?) + let ExecutionParams { args, externals } = params; + let mut args = StackWithLimit::with_data(args, DEFAULT_VALUE_STACK_LIMIT); + let function_reference = self.function_reference(ItemIndex::IndexSpace(index), Some(&externals))?; + let function_type = self.function_type(ItemIndex::IndexSpace(index), Some(&externals))?; + let function_context = CallerContext::topmost(&mut args, &externals); + function_reference.module.call_internal_function(function_context, function_reference.internal_index, Some(&function_type)) } fn execute_export(&self, name: &str, params: ExecutionParams) -> Result, Error> { @@ -466,7 +491,120 @@ impl ModuleInstanceInterface for ModuleInstance { } } - fn call_function<'a>(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result, Error> { + fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap>>) -> Result, Error> { + match self.imports.parse_function_index(index) { + ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"), + ItemIndex::Internal(index) => Ok(InternalFunctionReference { + module: self.self_ref(externals)?, + internal_index: index, + }), + ItemIndex::External(index) => { + let import_section = self.module.import_section().unwrap(); + let import_entry = import_section.entries().get(index as usize).unwrap(); + Ok(InternalFunctionReference { + module: self.imports.module(externals, import_entry.module())?, + internal_index: index + }) + }, + } + } + + fn function_reference_indirect<'a>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'a HashMap>>) -> Result, Error> { + let function_type = match self.module.type_section() + .ok_or(Error::Function(format!("trying to indirect call function {} with non-existent function section", func_idx))) + .and_then(|s| s.types().get(type_idx as usize) + .ok_or(Error::Function(format!("trying to indirect call function {} with non-existent type index {}", func_idx, type_idx))))? { + &Type::Function(ref function_type) => function_type, + }; + + let table = self.table(ItemIndex::IndexSpace(table_idx))?; + let (module, index) = match table.get(func_idx)? { + RuntimeValue::AnyFunc(module, index) => (module.clone(), index), + _ => return Err(Error::Function(format!("trying to indirect call function {} via non-anyfunc table {:?}", func_idx, table_idx))), + }; + + let module = self.imports.module(externals, &module)?; + module.function_reference(ItemIndex::IndexSpace(index), externals) + } + + fn function_body<'a>(&'a self, internal_index: u32/*, externals: Option<&'a HashMap>>*/) -> Result>, Error> { + // internal index = index of function in functions section && index of code in code section + // get function type index + let function_type_index = self.module + .function_section() + .ok_or(Error::Function(format!("trying to call function with index {} in module without function section", internal_index))) + .and_then(|s| s.entries() + .get(internal_index as usize) + .ok_or(Error::Function(format!("trying to call function with index {} in module with {} functions", internal_index, s.entries().len()))))? + .type_ref(); + // function type index = index of function type in types index + // get function type + let item_type = self.module + .type_section() + .ok_or(Error::Function(format!("trying to call function with index {} in module without types section", internal_index))) + .and_then(|s| s.types() + .get(function_type_index as usize) + .ok_or(Error::Function(format!("trying to call function with type index {} in module with {} types", function_type_index, s.types().len()))))?; + let actual_function_type = match item_type { + &Type::Function(ref function_type) => function_type, + }; + + // get function body + let function_body = self.module + .code_section() + .ok_or(Error::Function(format!("trying to call function with index {} in module without code section", internal_index))) + .and_then(|s| s.bodies() + .get(internal_index as usize) + .ok_or(Error::Function(format!("trying to call function with index {} in module with {} functions codes", internal_index, s.bodies().len()))))?; + + Ok(Some(InternalFunction { + func_type: actual_function_type, + locals: function_body.locals(), + body: function_body.code().elements(), + })) + /*match self.imports.parse_function_index(index) { + ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"), + ItemIndex::Internal(index) => { + // internal index = index of function in functions section && index of code in code section + // get function type index + let function_type_index = self.module + .function_section() + .ok_or(Error::Function(format!("trying to call function with index {} in module without function section", index))) + .and_then(|s| s.entries() + .get(index as usize) + .ok_or(Error::Function(format!("trying to call function with index {} in module with {} functions", index, s.entries().len()))))? + .type_ref(); + // function type index = index of function type in types index + // get function type + let item_type = self.module + .type_section() + .ok_or(Error::Function(format!("trying to call function with index {} in module without types section", index))) + .and_then(|s| s.types() + .get(function_type_index as usize) + .ok_or(Error::Function(format!("trying to call function with type index {} in module with {} types", function_type_index, s.types().len()))))?; + let actual_function_type = match item_type { + &Type::Function(ref function_type) => function_type, + }; + + // get function body + let function_body = self.module + .code_section() + .ok_or(Error::Function(format!("trying to call function with index {} in module without code section", index))) + .and_then(|s| s.bodies() + .get(index as usize) + .ok_or(Error::Function(format!("trying to call function with index {} in module with {} functions codes", index, s.bodies().len()))))?; + + Ok(Some(Function { + func_type: actual_function_type, + body: function_body.code().elements(), + })) + }, + ItemIndex::External(index) => { + }, + }*/ + } + + /*fn call_function(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result, Error> { match self.imports.parse_function_index(index) { ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"), ItemIndex::Internal(index) => self.call_internal_function(outer, index, function_type), @@ -480,7 +618,7 @@ impl ModuleInstanceInterface for ModuleInstance { } } - fn call_function_indirect<'a>(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result, Error> { + fn call_function_indirect(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result, Error> { let function_type = match self.module.type_section() .ok_or(Error::Function(format!("trying to indirect call function {} with non-existent function section", func_index))) .and_then(|s| s.types().get(type_index as usize) @@ -496,53 +634,36 @@ impl ModuleInstanceInterface for ModuleInstance { let module = self.imports.module(Some(outer.externals), &module)?; module.call_function(outer, ItemIndex::IndexSpace(index), Some(function_type)) - } + }*/ - fn call_internal_function<'a>(&self, mut outer: CallerContext, index: u32, function_type: Option<&FunctionType>) -> Result, Error> { - // TODO: cache - // internal index = index of function in functions section && index of code in code section - // get function type index - let function_type_index = self.module - .function_section() - .ok_or(Error::Function(format!("trying to call function with index {} in module without function section", index))) - .and_then(|s| s.entries() - .get(index as usize) - .ok_or(Error::Function(format!("trying to call function with index {} in module with {} functions", index, s.entries().len()))))? - .type_ref(); - // function type index = index of function type in types index - // get function type - let item_type = self.module - .type_section() - .ok_or(Error::Function(format!("trying to call function with index {} in module without types section", index))) - .and_then(|s| s.types() - .get(function_type_index as usize) - .ok_or(Error::Function(format!("trying to call function with type index {} in module with {} types", function_type_index, s.types().len()))))?; - let actual_function_type = match item_type { - &Type::Function(ref function_type) => function_type, - }; - if let Some(ref function_type) = function_type { - if function_type != &actual_function_type { + fn call_internal_function(&self, mut outer: CallerContext, index: u32, required_function_type: Option<&FunctionType>) -> Result, Error> { + let function_type_index = self.require_function(ItemIndex::Internal(index))?; + let function_type = self.require_function_type(function_type_index)?; + let function_body = self.function_body(index)?; + + if let Some(ref required_function_type) = required_function_type { + if required_function_type != &function_type { return Err(Error::Function(format!("expected function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}", - function_type.params(), function_type.return_type(), actual_function_type.params(), actual_function_type.return_type()))); + required_function_type.params(), required_function_type.return_type(), function_type.params(), function_type.return_type()))); } } - // get function body - let function_body = self.module - .code_section() - .ok_or(Error::Function(format!("trying to call function with index {} in module without code section", index))) - .and_then(|s| s.bodies() - .get(index as usize) - .ok_or(Error::Function(format!("trying to call function with index {} in module with {} functions codes", index, s.bodies().len()))))?; - // each functions has its own value stack - // but there's global stack limit - // args, locals - let function_code = function_body.code().elements(); - let value_stack_limit = outer.value_stack_limit; - let frame_stack_limit = outer.frame_stack_limit; - let locals = prepare_function_locals(actual_function_type, function_body, &mut outer)?; - let mut innner = FunctionContext::new(self, outer.externals, value_stack_limit, frame_stack_limit, actual_function_type, locals); - Interpreter::run_function(innner, function_code).map(CallResult::Executed) + let args = function_type.params().iter() + .map(|param_type| { + let param_value = outer.value_stack.pop()?; + let actual_type = param_value.variable_type(); + let expected_type = (*param_type).into(); + if actual_type != Some(expected_type) { + return Err(Error::Function(format!("invalid parameter type {:?} when expected {:?}", actual_type, expected_type))); + } + + VariableInstance::new(true, expected_type, param_value) + }) + .collect::, _>>()?; + + let function_ref = InternalFunctionReference { module: self.self_ref(Some(outer.externals))?, internal_index: index }; + let inner = FunctionContext::new(function_ref, outer.externals, outer.value_stack_limit, outer.frame_stack_limit, &function_type, args); + Interpreter::run_function(inner) } } diff --git a/src/interpreter/runner.rs b/src/interpreter/runner.rs index 193c5d7..ce05e8d 100644 --- a/src/interpreter/runner.rs +++ b/src/interpreter/runner.rs @@ -3,10 +3,11 @@ use std::ops; use std::u32; use std::sync::Arc; use std::fmt::{self, Display}; +use std::iter::repeat; use std::collections::{HashMap, VecDeque}; -use elements::{Opcode, BlockType, FunctionType}; +use elements::{Opcode, BlockType, FunctionType, Local}; use interpreter::Error; -use interpreter::module::{ModuleInstance, ModuleInstanceInterface, CallerContext, CallResult, ItemIndex}; +use interpreter::module::{ModuleInstance, ModuleInstanceInterface, CallerContext, ItemIndex, InternalFunctionReference}; use interpreter::stack::StackWithLimit; use interpreter::value::{ RuntimeValue, TryInto, WrapInto, TryTruncateInto, ExtendInto, @@ -24,8 +25,10 @@ pub struct Interpreter; /// Function execution context. pub struct FunctionContext<'a> { - /// Module instance. - pub module: &'a ModuleInstance, + /// Is context initialized. + pub is_initialized: bool, + /// Internal function reference. + pub function: InternalFunctionReference<'a>, /// Execution-local external modules. pub externals: &'a HashMap>, /// Function return type. @@ -35,14 +38,14 @@ pub struct FunctionContext<'a> { /// Values stack. pub value_stack: StackWithLimit, /// Blocks frames stack. - pub frame_stack: StackWithLimit, + pub frame_stack: StackWithLimit>, /// Current instruction position. pub position: usize, } /// Interpreter action to execute after executing instruction. #[derive(Debug)] -pub enum InstructionOutcome { +pub enum InstructionOutcome<'a> { /// Continue with current instruction. RunInstruction, /// Continue with next instruction. @@ -52,9 +55,7 @@ pub enum InstructionOutcome { /// Execute block. ExecuteBlock(bool), /// Execute function call. - ExecuteCall(u32), - /// Execute indirect function call. - ExecuteIndirectCall(u32, u32, u32), + ExecuteCall(InternalFunctionReference<'a>), /// End current frame. End, /// Return from current function block. @@ -63,155 +64,103 @@ pub enum InstructionOutcome { /// Control stack frame. #[derive(Debug, Clone)] -pub struct BlockFrame { +pub struct BlockFrame<'a> { /// Is loop frame? is_loop: bool, - // A label for reference from branch instructions. + /// A label for reference from branch instructions. branch_position: usize, - // A label for reference from end instructions. + /// A label for reference from end instructions. end_position: usize, - // A limit integer value, which is an index into the value stack indicating where to reset it to on a branch to that label. + /// Block body. + body: &'a [Opcode], + /// 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. + /// A signature, which is a block signature type indicating the number and types of result values of the region. signature: BlockType, } +enum RunResult<'a> { + Return(Option), + NestedCall(FunctionContext<'a>), +} + impl Interpreter { - pub fn run_function(mut context: FunctionContext, body: &[Opcode]) -> Result, Error> { - let mut context_depth = 0usize; - let mut context_stack = VecDeque::new(); - let mut blocks_stack = VecDeque::new(); + pub fn run_function(function_context: FunctionContext) -> Result, Error> { + let mut function_stack = VecDeque::new(); + function_stack.push_back(function_context); - { - let return_type = context.return_type; - context.push_frame(false, body.len() - 1, body.len() - 1, return_type)?; - context.position = 0; + loop { + let mut function_context = function_stack.pop_back().expect("on loop entry - not empty; on loop continue - checking for emptiness; qed"); + let function_ref = function_context.function.clone(); + let function_body = function_ref.module.function_body(function_ref.internal_index)?; - context_stack.push_back(context); - blocks_stack.push_back((1, body)); - } + let function_return = match function_body { + Some(function_body) => { + if !function_context.is_initialized() { + function_context.initialize(function_body.locals)?; + } - loop { // functions loop - let function_return = { - let context = context_stack.back_mut().unwrap(); - Interpreter::run_function_blocks(context_depth, &mut blocks_stack, context)? + Interpreter::do_run_function(&mut function_context, function_body.body)? + }, + None => { + let nested_context = CallerContext::nested(&mut function_context); + RunResult::Return(function_ref.module.call_internal_function(nested_context, function_ref.internal_index, None)?) + }, }; + match function_return { - InstructionOutcome::ExecuteCall(func_idx) => { - let context = context_stack.back_mut().unwrap(); - match context.call_function(func_idx)? { - CallResult::Executed(result) => if let Some(result) = result { - context.value_stack_mut().push(result)?; + RunResult::Return(return_value) => { + match function_stack.back_mut() { + Some(caller_context) => if let Some(return_value) = return_value { + caller_context.value_stack_mut().push(return_value)?; }, - CallResult::Scheduled(new_context, body) => { - unimplemented!() - }, - } - }, - InstructionOutcome::ExecuteIndirectCall(table_idx, type_idx, func_idx) => { - let context = context_stack.back_mut().unwrap(); - match context.call_function_indirect(table_idx, type_idx, func_idx)? { - CallResult::Executed(result) => if let Some(result) = result { - context.value_stack_mut().push(result)?; - }, - CallResult::Scheduled(new_context, body) => { - unimplemented!() - }, - } - }, - InstructionOutcome::Return => { - // return function value - let mut context = context_stack.pop_back().unwrap(); - let return_value = match context.return_type { - BlockType::Value(_) => Some(context.value_stack_mut().pop()?), - BlockType::NoResult => None, - }; - - match context_stack.back_mut() { None => return Ok(return_value), - Some(context) => if let Some(return_value) = return_value { - context.value_stack_mut().push(return_value)?; - }, } }, - InstructionOutcome::RunInstruction | InstructionOutcome::RunNextInstruction | InstructionOutcome::Branch(_) - | InstructionOutcome::ExecuteBlock(_) | InstructionOutcome::End => unreachable!("managed by run_function_blocks"), - /*CallResult::Executed(result) => { - context_stack.pop_back(); - match context_stack.back_mut() { - None => return Ok(result), - Some(context) => match result { - Some(result) => context.value_stack_mut().push(result)?, - None => (), - } - } - - context_depth -= 1; + RunResult::NestedCall(nested_context) => { + function_stack.push_back(function_context); + function_stack.push_back(nested_context); }, - CallResult::Scheduled(context, body) => { - context_depth += 1; - - context_stack.push_back(context); - blocks_stack.push_back((context_depth, body)); - },*/ } } } - fn run_function_blocks<'a, 'b, 'c>(current_depth: usize, blocks_stack: &'b mut VecDeque<(usize, &'a [Opcode])>, context: &'c mut FunctionContext<'a>) -> Result where 'a: 'b { - loop { // blocks loop - let block_return = { - let block = match blocks_stack.back() { - Some(block) => block, - None => return Ok(InstructionOutcome::Return), - }; + fn do_run_function<'a>(function_context: &mut FunctionContext<'a>, function_body: &[Opcode]) -> Result, Error> { + loop { + let block_frame = function_context.frame_stack_mut().pop(); + let block_result = Interpreter::run_block_instructions(function_context, block_frame.body)?; - assert!(block.0 >= current_depth); - if block.0 < current_depth { - return Ok(InstructionOutcome::Return); - } - - let block_body = block.1; - Interpreter::run_block_instructions(context, block_body)? - }; - - match block_return { - InstructionOutcome::RunInstruction | InstructionOutcome::RunNextInstruction => unreachable!("resolved by run_block_instructions"), - InstructionOutcome::ExecuteCall(func_idx) => return Ok(InstructionOutcome::ExecuteCall(func_idx)), - InstructionOutcome::ExecuteIndirectCall(table_idx, type_idx, func_idx) => return Ok(InstructionOutcome::ExecuteIndirectCall(table_idx, type_idx, func_idx)), - InstructionOutcome::ExecuteBlock(branch) => { - let nested_block = Interpreter::into_block(&blocks_stack.back().unwrap().1[context.position], branch)?; - blocks_stack.push_back((current_depth, nested_block)); - context.position = 0; - }, + match block_result { + InstructionOutcome::RunInstruction | InstructionOutcome::RunNextInstruction => unreachable!("managed by run_block_instructions"), InstructionOutcome::Branch(mut index) => { - // discard index - 1 blocks - while index >= 1 { - context.discard_frame()?; - assert!(blocks_stack.pop_back().is_some()); + // discard index - 2 blocks (-1 since last block is popped && -1 since we have already popped current block) + while index >= 2 { + function_context.discard_frame()?; index -= 1; } - context.pop_frame(true)?; - assert!(blocks_stack.pop_back().is_some()); - } - InstructionOutcome::End => { - // pop single block - context.pop_frame(false)?; - assert!(blocks_stack.pop_back().is_some()); - }, - InstructionOutcome::Return => { - // discard all function blocks - while context.frame_stack.len() > 0 { - context.discard_frame()?; - assert!(blocks_stack.pop_back().is_some()); + function_context.pop_frame(true)?; + if function_context.frame_stack().is_empty() { + return Ok(RunResult::Return(match function_context.return_type { + BlockType::Value(_) => Some(function_context.value_stack_mut().pop()?), + BlockType::NoResult => None, + })); } - } + }, + InstructionOutcome::ExecuteBlock(branch) => { + function_context.frame_stack_mut().push_penultimate(block_frame)?; + }, + InstructionOutcome::ExecuteCall(func_ref) => return Ok(RunResult::NestedCall(function_context.nested(func_ref)?)), + InstructionOutcome::End => (), + InstructionOutcome::Return => return Ok(RunResult::Return(match function_context.return_type { + BlockType::Value(_) => Some(function_context.value_stack_mut().pop()?), + BlockType::NoResult => None, + })), } } } - fn run_block_instructions<'a>(context: &mut FunctionContext<'a>, body: &'a [Opcode]) -> Result { + fn run_block_instructions<'a, 'b>(context: &'b mut FunctionContext<'a>, body: &'a [Opcode]) -> Result, Error> { loop { let instruction = &body[context.position]; @@ -220,26 +169,25 @@ impl Interpreter { InstructionOutcome::RunNextInstruction => context.position += 1, InstructionOutcome::Branch(index) => return Ok(InstructionOutcome::Branch(index)), InstructionOutcome::ExecuteBlock(branch) => return Ok(InstructionOutcome::ExecuteBlock(branch)), - InstructionOutcome::ExecuteCall(func_idx) => { + InstructionOutcome::ExecuteCall(func_ref) => { context.position += 1; - return Ok(InstructionOutcome::ExecuteCall(func_idx)); + return Ok(InstructionOutcome::ExecuteCall(func_ref)); }, - InstructionOutcome::ExecuteIndirectCall(table_idx, type_idx, func_idx) => { - context.position += 1; - return Ok(InstructionOutcome::ExecuteIndirectCall(table_idx, type_idx, func_idx)); + InstructionOutcome::End => { + context.pop_frame(false)?; + return Ok(InstructionOutcome::End); }, - InstructionOutcome::End => return Ok(InstructionOutcome::End), InstructionOutcome::Return => return Ok(InstructionOutcome::Return), } } } - fn run_instruction<'a>(context: &mut FunctionContext, opcode: &'a Opcode) -> Result { + fn run_instruction<'a, 'b>(context: &'b mut FunctionContext<'a>, opcode: &'a Opcode) -> Result, Error> { match opcode { &Opcode::Unreachable => Interpreter::run_unreachable(context), &Opcode::Nop => Interpreter::run_nop(context), - &Opcode::Block(block_type, _) => Interpreter::run_block(context, block_type), - &Opcode::Loop(block_type, ref ops) => Interpreter::run_loop(context, block_type), + &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), @@ -448,52 +396,52 @@ impl Interpreter { &body[begin_index..end_index] } - fn run_unreachable<'a>(_context: &mut FunctionContext) -> Result { + fn run_unreachable<'a>(_context: &mut FunctionContext) -> Result, Error> { Err(Error::Trap("programmatic".into())) } - fn run_nop<'a>(_context: &mut FunctionContext) -> Result { + fn run_nop<'a>(_context: &mut FunctionContext) -> Result, Error> { Ok(InstructionOutcome::RunNextInstruction) } - fn run_block<'a>(context: &mut FunctionContext, block_type: BlockType) -> Result { + fn run_block<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType, body: &'a [Opcode]) -> Result, Error> { let frame_position = context.position + 1; - context.push_frame(false, frame_position, frame_position, block_type)?; + context.push_frame(false, frame_position, frame_position, body, block_type)?; Ok(InstructionOutcome::ExecuteBlock(true)) } - fn run_loop<'a>(context: &mut FunctionContext, block_type: BlockType) -> Result { + fn run_loop<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType, body: &'a [Opcode]) -> Result, Error> { let frame_position = context.position; - context.push_frame(true, frame_position, frame_position + 1, block_type.clone())?; + context.push_frame(true, frame_position, frame_position + 1, body, block_type)?; Ok(InstructionOutcome::ExecuteBlock(true)) } - fn run_if<'a>(context: &mut FunctionContext, block_type: BlockType, body: &'a [Opcode]) -> Result { + fn run_if<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType, body: &'a [Opcode]) -> Result, Error> { let branch = context.value_stack_mut().pop_as()?; let branch_body = Interpreter::separate_if(body, branch); if branch_body.len() != 0 { let frame_position = context.position + 1; - context.push_frame(false, frame_position, frame_position, block_type.clone())?; + context.push_frame(false, frame_position, frame_position, branch_body, block_type)?; Ok(InstructionOutcome::ExecuteBlock(branch)) } else { Ok(InstructionOutcome::RunNextInstruction) } } - fn run_else<'a>(_context: &mut FunctionContext) -> Result { + fn run_else<'a>(_context: &mut FunctionContext) -> Result, Error> { Ok(InstructionOutcome::End) } - fn run_end<'a>(_context: &mut FunctionContext) -> Result { + fn run_end<'a>(_context: &mut FunctionContext) -> Result, Error> { Ok(InstructionOutcome::End) } - fn run_br<'a>(_context: &mut FunctionContext, label_idx: u32) -> Result { + fn run_br<'a>(_context: &mut FunctionContext, label_idx: u32) -> Result, Error> { Ok(InstructionOutcome::Branch(label_idx as usize)) } - fn run_br_if<'a>(context: &mut FunctionContext, label_idx: u32) -> Result { + fn run_br_if<'a>(context: &mut FunctionContext, label_idx: u32) -> Result, Error> { if context.value_stack_mut().pop_as()? { Ok(InstructionOutcome::Branch(label_idx as usize)) } else { @@ -501,38 +449,32 @@ impl Interpreter { } } - fn run_br_table<'a>(context: &mut FunctionContext, table: &Vec, default: u32) -> Result { + fn run_br_table<'a>(context: &mut FunctionContext, table: &Vec, default: u32) -> Result, Error> { let index: u32 = context.value_stack_mut().pop_as()?; Ok(InstructionOutcome::Branch(table.get(index as usize).cloned().unwrap_or(default) as usize)) } - fn run_return<'a>(_context: &mut FunctionContext) -> Result { + fn run_return<'a>(_context: &mut FunctionContext) -> Result, Error> { Ok(InstructionOutcome::Return) } - fn run_call<'a>(context: &mut FunctionContext, func_idx: u32) -> Result { - Ok(InstructionOutcome::ExecuteCall(func_idx)) - /*context.call_function(func_idx) - .and_then(|r| r.map(|r| context.value_stack_mut().push(r)).unwrap_or(Ok(()))) - .map(|_| InstructionOutcome::RunNextInstruction)*/ + fn run_call<'a, 'b>(context: &'b mut FunctionContext<'a>, func_idx: u32) -> Result, Error> where 'a: 'b { + Ok(InstructionOutcome::ExecuteCall(context.module().function_reference(ItemIndex::IndexSpace(func_idx), Some(context.externals))?)) } - fn run_call_indirect<'a>(context: &mut FunctionContext, type_idx: u32) -> Result { + fn run_call_indirect<'a, 'b>(context: &'b mut FunctionContext<'a>, type_idx: u32) -> Result, Error> { let table_func_idx: u32 = context.value_stack_mut().pop_as()?; - Ok(InstructionOutcome::ExecuteIndirectCall(DEFAULT_TABLE_INDEX, type_idx, table_func_idx)) - /*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)*/ + Ok(InstructionOutcome::ExecuteCall(context.module().function_reference_indirect(DEFAULT_TABLE_INDEX, type_idx, table_func_idx, Some(context.externals))?)) } - fn run_drop<'a>(context: &mut FunctionContext) -> Result { + fn run_drop<'a>(context: &mut FunctionContext) -> Result, Error> { context .value_stack_mut() .pop() .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_select<'a>(context: &mut FunctionContext) -> Result { + fn run_select<'a>(context: &mut FunctionContext) -> Result, Error> { context .value_stack_mut() .pop_triple() @@ -547,32 +489,32 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_get_local<'a>(context: &mut FunctionContext, index: u32) -> Result { + fn run_get_local<'a>(context: &mut FunctionContext, index: u32) -> Result, Error> { context.get_local(index as usize) .map(|value| context.value_stack_mut().push(value)) .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_set_local<'a>(context: &mut FunctionContext, index: u32) -> Result { + fn run_set_local<'a>(context: &mut FunctionContext, index: u32) -> Result, Error> { let arg = context.value_stack_mut().pop()?; context.set_local(index as usize, arg) .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_tee_local<'a>(context: &mut FunctionContext, index: u32) -> Result { + fn run_tee_local<'a>(context: &mut FunctionContext, index: u32) -> Result, Error> { let arg = context.value_stack().top()?.clone(); context.set_local(index as usize, arg) .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_get_global<'a>(context: &mut FunctionContext, index: u32) -> Result { + fn run_get_global<'a>(context: &mut FunctionContext, index: u32) -> Result, Error> { context.module() .global(ItemIndex::IndexSpace(index), None) .and_then(|g| context.value_stack_mut().push(g.get())) .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_set_global<'a>(context: &mut FunctionContext, index: u32) -> Result { + fn run_set_global<'a>(context: &mut FunctionContext, index: u32) -> Result, Error> { context .value_stack_mut() .pop() @@ -580,7 +522,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_load<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result + fn run_load<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result, Error> where RuntimeValue: From, T: LittleEndianConvert { let address = effective_address(offset, context.value_stack_mut().pop_as()?)?; context.module() @@ -591,7 +533,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_load_extend<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result + fn run_load_extend<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result, Error> where T: ExtendInto, RuntimeValue: From, T: LittleEndianConvert { let address = effective_address(offset, context.value_stack_mut().pop_as()?)?; let stack_value: U = context.module() @@ -605,7 +547,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_store<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result + fn run_store<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result, Error> where RuntimeValue: TryInto, T: LittleEndianConvert { let stack_value = context .value_stack_mut() @@ -618,7 +560,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_store_wrap<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result + fn run_store_wrap<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result, Error> where RuntimeValue: TryInto, T: WrapInto, U: LittleEndianConvert { let stack_value: T = context.value_stack_mut().pop().and_then(|v| v.try_into())?; let stack_value = stack_value.wrap_into().into_little_endian(); @@ -629,7 +571,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_current_memory<'a>(context: &mut FunctionContext) -> Result { + fn run_current_memory<'a>(context: &mut FunctionContext) -> Result, Error> { context.module() .memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX)) .map(|m| m.size()) @@ -637,7 +579,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_grow_memory<'a>(context: &mut FunctionContext) -> Result { + fn run_grow_memory<'a>(context: &mut FunctionContext) -> Result, Error> { let pages: u32 = context.value_stack_mut().pop_as()?; context.module() .memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX)) @@ -646,14 +588,14 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_const<'a>(context: &mut FunctionContext, val: RuntimeValue) -> Result { + fn run_const<'a>(context: &mut FunctionContext, val: RuntimeValue) -> Result, Error> { context .value_stack_mut() .push(val) .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_eqz<'a, T>(context: &mut FunctionContext) -> Result + fn run_eqz<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: TryInto, T: PartialEq + Default { context .value_stack_mut() @@ -663,7 +605,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_eq<'a, T>(context: &mut FunctionContext) -> Result + fn run_eq<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: TryInto, T: PartialEq { context .value_stack_mut() @@ -673,7 +615,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_ne<'a, T>(context: &mut FunctionContext) -> Result + fn run_ne<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: TryInto, T: PartialEq { context .value_stack_mut() @@ -683,7 +625,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_lt<'a, T>(context: &mut FunctionContext) -> Result + fn run_lt<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: TryInto, T: PartialOrd + Display { context .value_stack_mut() @@ -693,7 +635,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_gt<'a, T>(context: &mut FunctionContext) -> Result + fn run_gt<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: TryInto, T: PartialOrd { context .value_stack_mut() @@ -703,7 +645,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_lte<'a, T>(context: &mut FunctionContext) -> Result + fn run_lte<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: TryInto, T: PartialOrd { context .value_stack_mut() @@ -713,7 +655,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_gte<'a, T>(context: &mut FunctionContext) -> Result + fn run_gte<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: TryInto, T: PartialOrd { context .value_stack_mut() @@ -723,7 +665,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_clz<'a, T>(context: &mut FunctionContext) -> Result + fn run_clz<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Integer { context .value_stack_mut() @@ -733,7 +675,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_ctz<'a, T>(context: &mut FunctionContext) -> Result + fn run_ctz<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Integer { context .value_stack_mut() @@ -743,7 +685,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_popcnt<'a, T>(context: &mut FunctionContext) -> Result + fn run_popcnt<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Integer { context .value_stack_mut() @@ -753,7 +695,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_add<'a, T>(context: &mut FunctionContext) -> Result + fn run_add<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: ArithmeticOps { context .value_stack_mut() @@ -763,7 +705,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_sub<'a, T>(context: &mut FunctionContext) -> Result + fn run_sub<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: ArithmeticOps { context .value_stack_mut() @@ -773,7 +715,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_mul<'a, T>(context: &mut FunctionContext) -> Result + fn run_mul<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: ArithmeticOps { context .value_stack_mut() @@ -783,7 +725,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_div<'a, T, U>(context: &mut FunctionContext) -> Result + fn run_div<'a, T, U>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: TransmuteInto + Display, U: ArithmeticOps + TransmuteInto { context .value_stack_mut() @@ -795,7 +737,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_rem<'a, T, U>(context: &mut FunctionContext) -> Result + fn run_rem<'a, T, U>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: TransmuteInto, U: Integer + TransmuteInto { context .value_stack_mut() @@ -807,7 +749,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_and<'a, T>(context: &mut FunctionContext) -> Result + fn run_and<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From<::Output> + TryInto, T: ops::BitAnd { context .value_stack_mut() @@ -817,7 +759,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_or<'a, T>(context: &mut FunctionContext) -> Result + fn run_or<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From<::Output> + TryInto, T: ops::BitOr { context .value_stack_mut() @@ -827,7 +769,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_xor<'a, T>(context: &mut FunctionContext) -> Result + fn run_xor<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From<::Output> + TryInto, T: ops::BitXor { context .value_stack_mut() @@ -837,7 +779,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_shl<'a, T>(context: &mut FunctionContext) -> Result + fn run_shl<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From<>::Output> + TryInto, T: ops::Shl { context .value_stack_mut() @@ -847,7 +789,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_shr<'a, T, U>(context: &mut FunctionContext) -> Result + fn run_shr<'a, T, U>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: TransmuteInto, U: ops::Shr, >::Output: TransmuteInto { context .value_stack_mut() @@ -859,7 +801,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_rotl<'a, T>(context: &mut FunctionContext) -> Result + fn run_rotl<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Integer { context .value_stack_mut() @@ -869,7 +811,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_rotr<'a, T>(context: &mut FunctionContext) -> Result + fn run_rotr<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Integer { context .value_stack_mut() @@ -879,7 +821,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_abs<'a, T>(context: &mut FunctionContext) -> Result + fn run_abs<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -889,7 +831,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_neg<'a, T>(context: &mut FunctionContext) -> Result + fn run_neg<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From<::Output> + TryInto, T: ops::Neg { context .value_stack_mut() @@ -899,7 +841,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_ceil<'a, T>(context: &mut FunctionContext) -> Result + fn run_ceil<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -909,7 +851,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_floor<'a, T>(context: &mut FunctionContext) -> Result + fn run_floor<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -919,7 +861,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_trunc<'a, T>(context: &mut FunctionContext) -> Result + fn run_trunc<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -929,7 +871,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_nearest<'a, T>(context: &mut FunctionContext) -> Result + fn run_nearest<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -939,7 +881,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_sqrt<'a, T>(context: &mut FunctionContext) -> Result + fn run_sqrt<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -949,7 +891,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_min<'a, T>(context: &mut FunctionContext) -> Result + fn run_min<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -959,7 +901,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_max<'a, T>(context: &mut FunctionContext) -> Result + fn run_max<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -969,7 +911,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_copysign<'a, T>(context: &mut FunctionContext) -> Result + fn run_copysign<'a, T>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: Float { context .value_stack_mut() @@ -979,7 +921,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_wrap<'a, T, U>(context: &mut FunctionContext) -> Result + fn run_wrap<'a, T, U>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: WrapInto { context .value_stack_mut() @@ -989,7 +931,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_trunc_to_int<'a, T, U, V>(context: &mut FunctionContext) -> Result + fn run_trunc_to_int<'a, T, U, V>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: TryTruncateInto, U: TransmuteInto, { context .value_stack_mut() @@ -1000,7 +942,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_extend<'a, T, U, V>(context: &mut FunctionContext) -> Result + fn run_extend<'a, T, U, V>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From + TryInto, T: ExtendInto, U: TransmuteInto { context .value_stack_mut() @@ -1011,7 +953,7 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_reinterpret<'a, T, U>(context: &mut FunctionContext) -> Result + fn run_reinterpret<'a, T, U>(context: &mut FunctionContext) -> Result, Error> where RuntimeValue: From, RuntimeValue: TryInto, T: TransmuteInto { context .value_stack_mut() @@ -1023,11 +965,12 @@ impl Interpreter { } impl<'a> FunctionContext<'a> { - pub fn new(module: &'a ModuleInstance, externals: &'a HashMap>, value_stack_limit: usize, frame_stack_limit: usize, function: &FunctionType, args: Vec) -> Self { + pub fn new(function: InternalFunctionReference<'a>, externals: &'a HashMap>, value_stack_limit: usize, frame_stack_limit: usize, function_type: &FunctionType, args: Vec) -> Self { FunctionContext { - module: module, + is_initialized: false, + function: function, externals: externals, - return_type: function.return_type().map(|vt| BlockType::Value(vt)).unwrap_or(BlockType::NoResult), + return_type: function_type.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, @@ -1035,23 +978,57 @@ impl<'a> FunctionContext<'a> { } } - pub fn module(&self) -> &ModuleInstance { - self.module + pub fn nested(&mut self, function: InternalFunctionReference<'a>) -> Result { + let function_type = function.module.function_type(ItemIndex::Internal(function.internal_index), Some(self.externals))?; + let function_return_type = function_type.return_type().map(|vt| BlockType::Value(vt)).unwrap_or(BlockType::NoResult); + let function_locals = function_type.params().iter().rev().map(|param_type| { + let param_value = self.value_stack.pop()?; + let actual_type = param_value.variable_type(); + let expected_type = (*param_type).into(); + if actual_type != Some(expected_type) { + return Err(Error::Function(format!("invalid parameter type {:?} when expected {:?}", actual_type, expected_type))); + } + + VariableInstance::new(true, expected_type, param_value) + }).collect::, _>>()?; + + Ok(FunctionContext { + is_initialized: false, + function: function, + externals: self.externals, + return_type: function_return_type, + value_stack: StackWithLimit::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, + }) + } + + pub fn is_initialized(&self) -> bool { + self.is_initialized + } + + pub fn initialize(&mut self, locals: &[Local]) -> Result<(), Error> { + debug_assert!(!self.is_initialized); + self.is_initialized = true; + + let locals = locals.iter() + .flat_map(|l| repeat(l.value_type().into()).take(l.count() as usize)) + .map(|vt| VariableInstance::new(true, vt, RuntimeValue::default(vt))) + .collect::, _>>()?; + self.locals.extend(locals); + Ok(()) + } + + pub fn module(&self) -> &Arc { + &self.function.module } pub fn externals(&self) -> &HashMap> { &self.externals } - pub fn call_function<'b>(&mut self, index: u32) -> Result, Error> { - self.module.call_function(CallerContext::nested(self), ItemIndex::IndexSpace(index), None) - } - - pub fn call_function_indirect<'b>(&mut self, table_index: u32, type_index: u32, func_index: u32) -> Result, Error> { - self.module.call_function_indirect(CallerContext::nested(self), ItemIndex::IndexSpace(table_index), type_index, func_index) - } - - pub fn set_local(&mut self, index: usize, value: RuntimeValue) -> Result { + pub fn set_local(&mut self, index: usize, value: RuntimeValue) -> Result, Error> { self.locals.get_mut(index) .ok_or(Error::Local(format!("expected to have local with index {}", index))) .and_then(|l| l.set(value)) @@ -1076,11 +1053,16 @@ impl<'a> FunctionContext<'a> { &self.frame_stack } - pub fn push_frame(&mut self, is_loop: bool, branch_position: usize, end_position: usize, signature: BlockType) -> Result<(), Error> { + pub fn frame_stack_mut(&mut self) -> &mut StackWithLimit> { + &mut self.frame_stack + } + + pub fn push_frame(&mut self, is_loop: bool, branch_position: usize, end_position: usize, body: &'a [Opcode], signature: BlockType) -> Result<(), Error> { self.frame_stack.push(BlockFrame { is_loop: is_loop, branch_position: branch_position, end_position: end_position, + body: body, value_limit: self.value_stack.len(), signature: signature, }) @@ -1117,16 +1099,17 @@ impl<'a> fmt::Debug for FunctionContext<'a> { } } -impl BlockFrame { - pub fn invalid() -> Self { +impl<'a> BlockFrame<'a> { +/* pub fn invalid() -> Self { BlockFrame { is_loop: false, branch_position: usize::max_value(), end_position: usize::max_value(), + branch: true, value_limit: usize::max_value(), signature: BlockType::NoResult, } - } + }*/ } fn effective_address(address: u32, offset: u32) -> Result { @@ -1135,3 +1118,25 @@ fn effective_address(address: u32, offset: u32) -> Result { Some(address) => Ok(address), } } + +/*fn prepare_function_locals(function_type: &FunctionType, function_body: &FuncBody, value_stack: &mut StackWithLimit) -> Result, Error> { + // locals = function arguments + defined locals + function_type.params().iter().rev() + .map(|param_type| { + let param_value = outer.value_stack.pop()?; + let actual_type = param_value.variable_type(); + let expected_type = (*param_type).into(); + if actual_type != Some(expected_type) { + return Err(Error::Function(format!("invalid parameter type {:?} when expected {:?}", actual_type, expected_type))); + } + + VariableInstance::new(true, expected_type, param_value) + }) + .collect::>().into_iter().rev() + .chain(function_body.locals() + .iter() + .flat_map(|l| repeat(l.value_type().into()).take(l.count() as usize)) + .map(|vt| VariableInstance::new(true, vt, RuntimeValue::default(vt)))) + .collect::, _>>() +} +*/ \ No newline at end of file diff --git a/src/interpreter/stack.rs b/src/interpreter/stack.rs index d21267e..603f8d8 100644 --- a/src/interpreter/stack.rs +++ b/src/interpreter/stack.rs @@ -38,16 +38,22 @@ impl StackWithLimit where T: Clone { self.limit } + pub fn values(&self) -> &VecDeque { + &self.values + } + pub fn top(&self) -> Result<&T, Error> { self.values .back() .ok_or(Error::Stack("non-empty stack expected".into())) +.map_err(|e| { panic!("1") }) } pub fn top_mut(&mut self) -> Result<&mut T, Error> { self.values .back_mut() .ok_or(Error::Stack("non-empty stack expected".into())) +.map_err(|e| { panic!("2") }) } pub fn get(&self, index: usize) -> Result<&T, Error> { @@ -67,10 +73,24 @@ impl StackWithLimit where T: Clone { Ok(()) } + pub fn push_penultimate(&mut self, value: T) -> Result<(), Error> { + if self.values.is_empty() { + return Err(Error::Stack("trying to insert penultimate element into empty stack".into())); + } + self.push(value)?; + + let last_index = self.values.len() - 1; + let penultimate_index = last_index - 1; + self.values.swap(last_index, penultimate_index); + + Ok(()) + } + pub fn pop(&mut self) -> Result { self.values .pop_back() .ok_or(Error::Stack("non-empty stack expected".into())) +.map_err(|e| { panic!("3") }) } pub fn resize(&mut self, new_size: usize, dummy: T) { diff --git a/src/interpreter/tests/wabt.rs b/src/interpreter/tests/wabt.rs index 6616d0c..de56d04 100644 --- a/src/interpreter/tests/wabt.rs +++ b/src/interpreter/tests/wabt.rs @@ -1,9 +1,9 @@ ///! Tests from https://github.com/WebAssembly/wabt/tree/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp -use std::sync::Weak; +use std::sync::{Arc, Weak}; use std::collections::HashMap; use builder::module; -use elements::{Module, ValueType, Opcodes, Opcode, BlockType, FunctionType}; +use elements::{Module, ValueType, Opcodes, Opcode, BlockType, FunctionType, Local}; use interpreter::Error; use interpreter::module::{ModuleInstance, ModuleInstanceInterface, ItemIndex}; use interpreter::program::ProgramInstance; @@ -11,44 +11,53 @@ use interpreter::runner::{Interpreter, FunctionContext}; use interpreter::value::{RuntimeValue, TryInto}; use interpreter::variable::{VariableInstance, VariableType}; -fn run_function_i32(body: &Opcodes, arg: i32) -> Result { - let ftype = FunctionType::new(vec![ValueType::I32], Some(ValueType::I32)); - let module = ModuleInstance::new(Weak::default(), "test".into(), Module::default()).unwrap(); - let externals = HashMap::new(); - let mut context = FunctionContext::new(&module, &externals, 1024, 1024, &ftype, vec![ - VariableInstance::new(true, VariableType::I32, RuntimeValue::I32(arg)).unwrap(), // arg - VariableInstance::new(true, VariableType::I32, RuntimeValue::I32(0)).unwrap(), // local1 - VariableInstance::new(true, VariableType::I32, RuntimeValue::I32(0)).unwrap(), // local2 - ]); - Interpreter::run_function(context, body.elements()) - .map(|v| v.unwrap().try_into().unwrap()) +fn make_function_i32(body: Opcodes) -> (ProgramInstance, Arc) { + let module = module() + .function() + .signature().param().i32().return_type().i32().build() + .body() + .with_locals(vec![Local::new(2, ValueType::I32)]) + .with_opcodes(body) + .build() + .build() + .build(); + + let program = ProgramInstance::new().unwrap(); + let module = program.add_module("main", module, None).unwrap(); + (program, module) +} + +fn run_function_i32(module: &Arc, arg: i32) -> Result { + module + .execute_index(0, vec![RuntimeValue::I32(arg)].into()) + .map(|r| r.unwrap().try_into().unwrap()) } /// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/unreachable.txt #[test] fn unreachable() { - let body = Opcodes::new(vec![ + let (_program, module) = make_function_i32(Opcodes::new(vec![ Opcode::Unreachable, // trap - Opcode::End]); + Opcode::End])); - assert_eq!(run_function_i32(&body, 0).unwrap_err(), Error::Trap("programmatic".into())); + assert_eq!(run_function_i32(&module, 0).unwrap_err(), Error::Trap("programmatic".into())); } #[test] fn nop() { - let body = Opcodes::new(vec![ + let (_program, module) = make_function_i32(Opcodes::new(vec![ Opcode::Nop, // nop Opcode::I32Const(1), // [1] Opcode::Nop, // nop - Opcode::End]); + Opcode::End])); - assert_eq!(run_function_i32(&body, 0).unwrap(), 1); + assert_eq!(run_function_i32(&module, 0).unwrap(), 1); } /// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/expr-block.txt #[test] fn expr_block() { - let body = Opcodes::new(vec![ + let (_program, module) = make_function_i32(Opcodes::new(vec![ Opcode::Block(BlockType::Value(ValueType::I32), // mark block Opcodes::new(vec![ Opcode::I32Const(10), // [10] @@ -56,15 +65,15 @@ fn expr_block() { Opcode::I32Const(1), // [1] Opcode::End, ])), - Opcode::End]); + Opcode::End])); - assert_eq!(run_function_i32(&body, 0).unwrap(), 1); + assert_eq!(run_function_i32(&module, 0).unwrap(), 1); } /// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/loop.txt #[test] fn loop_test() { - let body = Opcodes::new(vec![ + let (_program, module) = make_function_i32(Opcodes::new(vec![ Opcode::Loop(BlockType::NoResult, // loop Opcodes::new(vec![ Opcode::GetLocal(1), // [local1] @@ -85,15 +94,15 @@ fn loop_test() { ])), Opcode::End])), // end loop Opcode::GetLocal(1), // [local1] - Opcode::End]); + Opcode::End])); - assert_eq!(run_function_i32(&body, 0).unwrap(), 10); + assert_eq!(run_function_i32(&module, 0).unwrap(), 10); } /// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/if.txt#L3 #[test] fn if_1() { - let body = Opcodes::new(vec![ + let (_program, module) = make_function_i32(Opcodes::new(vec![ Opcode::I32Const(0), // [0] Opcode::SetLocal(0), // [] + arg = 0 Opcode::I32Const(1), // [1] @@ -115,15 +124,15 @@ fn if_1() { Opcode::End, // end if ])), Opcode::GetLocal(0), // [arg] - Opcode::End]); + Opcode::End])); - assert_eq!(run_function_i32(&body, 0).unwrap(), 1); + assert_eq!(run_function_i32(&module, 0).unwrap(), 1); } /// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/if.txt#L23 #[test] fn if_2() { - let body = Opcodes::new(vec![ + let (_program, module) = make_function_i32(Opcodes::new(vec![ Opcode::I32Const(1), // [1] Opcode::If(BlockType::NoResult, // if 1 Opcodes::new(vec![ @@ -147,15 +156,15 @@ fn if_2() { Opcode::GetLocal(0), // [arg] Opcode::GetLocal(1), // [arg, local1] Opcode::I32Add, // [arg + local1] - Opcode::End]); + Opcode::End])); - assert_eq!(run_function_i32(&body, 0).unwrap(), 9); + assert_eq!(run_function_i32(&module, 0).unwrap(), 9); } /// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/expr-if.txt #[test] fn expr_if() { - let body = Opcodes::new(vec![ + let (_program, module) = make_function_i32(Opcodes::new(vec![ Opcode::GetLocal(0), // [arg] Opcode::I32Const(0), // [arg, 0] Opcode::I32Eq, // [arg == 0] @@ -166,16 +175,16 @@ fn expr_if() { Opcode::I32Const(2), // [2] Opcode::End, // end if ])), - Opcode::End]); + Opcode::End])); - assert_eq!(run_function_i32(&body, 0).unwrap(), 1); - assert_eq!(run_function_i32(&body, 1).unwrap(), 2); + assert_eq!(run_function_i32(&module, 0).unwrap(), 1); + assert_eq!(run_function_i32(&module, 1).unwrap(), 2); } /// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/nested-if.txt #[test] fn nested_if() { - let body = Opcodes::new(vec![ + let (_program, module) = make_function_i32(Opcodes::new(vec![ Opcode::Block(BlockType::NoResult, Opcodes::new(vec![ Opcode::I32Const(1), @@ -194,15 +203,15 @@ fn nested_if() { Opcode::End, ])), Opcode::I32Const(4), - Opcode::End]); + Opcode::End])); - assert_eq!(run_function_i32(&body, 0).unwrap(), 4); + assert_eq!(run_function_i32(&module, 0).unwrap(), 4); } /// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/br.txt#L4 #[test] fn br_0() { - let body = Opcodes::new(vec![ + let (_program, module) = make_function_i32(Opcodes::new(vec![ Opcode::Block(BlockType::NoResult, // mark block Opcodes::new(vec![ Opcode::I32Const(1), // [1] @@ -224,15 +233,15 @@ fn br_0() { Opcode::I32Const(1), // [arg == 0, local1, 1] Opcode::I32Eq, // [arg == 0, local1 == 1] Opcode::I32Add, // [arg == 0 + local1 == 1] - Opcode::End]); + Opcode::End])); - assert_eq!(run_function_i32(&body, 0).unwrap(), 2); + assert_eq!(run_function_i32(&module, 0).unwrap(), 2); } /// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/br.txt#L26 #[test] fn br_1() { - let body = Opcodes::new(vec![ + let (_program, module) = make_function_i32(Opcodes::new(vec![ Opcode::Block(BlockType::NoResult, // block1 Opcodes::new(vec![ Opcode::Block(BlockType::NoResult, // block2 @@ -264,15 +273,15 @@ fn br_1() { Opcode::I32Const(1), // [arg == 0 + local1 == 0, local2, 1] Opcode::I32Eq, // [arg == 0 + local1 == 0, local2 == 1] Opcode::I32Add, // [arg == 0 + local1 == 0 + local2 == 1] - Opcode::End]); + Opcode::End])); - assert_eq!(run_function_i32(&body, 0).unwrap(), 3); + assert_eq!(run_function_i32(&module, 0).unwrap(), 3); } /// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/br.txt#L56 #[test] fn br_2() { - let body = Opcodes::new(vec![ + let (_program, module) = make_function_i32(Opcodes::new(vec![ Opcode::Block(BlockType::NoResult, // block1 Opcodes::new(vec![ Opcode::Block(BlockType::NoResult, // block2 @@ -291,15 +300,15 @@ fn br_2() { ])), Opcode::I32Const(2), // [2] Opcode::Return, // return 2 - Opcode::End]); + Opcode::End])); - assert_eq!(run_function_i32(&body, 0).unwrap(), 2); + assert_eq!(run_function_i32(&module, 0).unwrap(), 2); } /// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/br.txt#L71 #[test] fn br_3() { - let body = Opcodes::new(vec![ + let (_program, module) = make_function_i32(Opcodes::new(vec![ Opcode::Block(BlockType::NoResult, // block1 Opcodes::new(vec![ Opcode::Loop(BlockType::NoResult, // loop @@ -333,15 +342,15 @@ fn br_3() { ])), Opcode::GetLocal(1), // [local1] Opcode::Return, // return local1 - Opcode::End]); + Opcode::End])); - assert_eq!(run_function_i32(&body, 0).unwrap(), 3); + assert_eq!(run_function_i32(&module, 0).unwrap(), 3); } /// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/expr-br.txt #[test] fn expr_br() { - let body = Opcodes::new(vec![ + let (_program, module) = make_function_i32(Opcodes::new(vec![ Opcode::Block(BlockType::Value(ValueType::I32), // block1 Opcodes::new(vec![ Opcode::GetLocal(0), // [arg] @@ -356,16 +365,16 @@ fn expr_br() { Opcode::I32Const(2), // [2] Opcode::End, // end (block1) ])), - Opcode::End]); + Opcode::End])); - assert_eq!(run_function_i32(&body, 0).unwrap(), 1); - assert_eq!(run_function_i32(&body, 1).unwrap(), 2); + assert_eq!(run_function_i32(&module, 0).unwrap(), 1); + assert_eq!(run_function_i32(&module, 1).unwrap(), 2); } /// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/brif.txt #[test] fn brif() { - let body = Opcodes::new(vec![ + let (_program, module) = make_function_i32(Opcodes::new(vec![ Opcode::Block(BlockType::NoResult, // block1 Opcodes::new(vec![ Opcode::GetLocal(0), // [arg] @@ -376,16 +385,16 @@ fn brif() { ])), Opcode::I32Const(2), // [2] Opcode::Return, // return 2 - Opcode::End]); + Opcode::End])); - assert_eq!(run_function_i32(&body, 0).unwrap(), 1); - assert_eq!(run_function_i32(&body, 1).unwrap(), 2); + assert_eq!(run_function_i32(&module, 0).unwrap(), 1); + assert_eq!(run_function_i32(&module, 1).unwrap(), 2); } /// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/brif-loop.txt #[test] fn brif_loop() { - let body = Opcodes::new(vec![ + let (_program, module) = make_function_i32(Opcodes::new(vec![ Opcode::Loop(BlockType::NoResult, // loop Opcodes::new(vec![ Opcode::GetLocal(1), // [local1] @@ -400,16 +409,16 @@ fn brif_loop() { ])), Opcode::GetLocal(1), // [local1] Opcode::Return, // return - Opcode::End]); + Opcode::End])); - assert_eq!(run_function_i32(&body, 3).unwrap(), 3); - assert_eq!(run_function_i32(&body, 10).unwrap(), 10); + assert_eq!(run_function_i32(&module, 3).unwrap(), 3); + assert_eq!(run_function_i32(&module, 10).unwrap(), 10); } /// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/expr-brif.txt #[test] fn expr_brif() { - let body = Opcodes::new(vec![ + let (_program, module) = make_function_i32(Opcodes::new(vec![ Opcode::Loop(BlockType::NoResult, // loop Opcodes::new(vec![ Opcode::GetLocal(1), // [local1] @@ -423,16 +432,16 @@ fn expr_brif() { Opcode::End, // end (loop) ])), Opcode::GetLocal(1), // [local1] - Opcode::End]); + Opcode::End])); - assert_eq!(run_function_i32(&body, 3).unwrap(), 3); - assert_eq!(run_function_i32(&body, 10).unwrap(), 10); + assert_eq!(run_function_i32(&module, 3).unwrap(), 3); + assert_eq!(run_function_i32(&module, 10).unwrap(), 10); } /// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/brtable.txt #[test] fn brtable() { - let body = Opcodes::new(vec![ + let (_program, module) = make_function_i32(Opcodes::new(vec![ Opcode::Block(BlockType::NoResult, // block3 Opcodes::new(vec![ Opcode::Block(BlockType::NoResult, // block2 @@ -457,18 +466,18 @@ fn brtable() { ])), Opcode::I32Const(2), // [2] Opcode::Return, // return 2 - Opcode::End]); + Opcode::End])); - assert_eq!(run_function_i32(&body, 0).unwrap(), 0); - assert_eq!(run_function_i32(&body, 1).unwrap(), 1); - assert_eq!(run_function_i32(&body, 2).unwrap(), 2); - assert_eq!(run_function_i32(&body, 3).unwrap(), 2); + assert_eq!(run_function_i32(&module, 0).unwrap(), 0); + assert_eq!(run_function_i32(&module, 1).unwrap(), 1); + assert_eq!(run_function_i32(&module, 2).unwrap(), 2); + assert_eq!(run_function_i32(&module, 3).unwrap(), 2); } /// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/return.txt #[test] fn return_test() { - let body = Opcodes::new(vec![ + let (_program, module) = make_function_i32(Opcodes::new(vec![ Opcode::GetLocal(0), Opcode::I32Const(0), Opcode::I32Eq, @@ -489,11 +498,11 @@ fn return_test() { ])), Opcode::I32Const(3), Opcode::Return, - Opcode::End]); + Opcode::End])); - assert_eq!(run_function_i32(&body, 0).unwrap(), 1); - assert_eq!(run_function_i32(&body, 1).unwrap(), 2); - assert_eq!(run_function_i32(&body, 5).unwrap(), 3); + assert_eq!(run_function_i32(&module, 0).unwrap(), 1); + assert_eq!(run_function_i32(&module, 1).unwrap(), 2); + assert_eq!(run_function_i32(&module, 5).unwrap(), 3); } /// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/return-void.txt From 8d7d39d80b1bb9019f66b69375dea18bd1d7336b Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Mon, 19 Jun 2017 11:01:59 +0300 Subject: [PATCH 05/11] call && call_indirect are working --- spec/src/fixtures.rs | 4 +- src/interpreter/env.rs | 9 +- src/interpreter/env_native.rs | 13 ++- src/interpreter/module.rs | 84 ++++++++-------- src/interpreter/program.rs | 22 +++-- src/interpreter/runner.rs | 180 +++++++++++++++++++++------------- 6 files changed, 187 insertions(+), 125 deletions(-) diff --git a/spec/src/fixtures.rs b/spec/src/fixtures.rs index 6d36470..fdcc8b0 100644 --- a/spec/src/fixtures.rs +++ b/spec/src/fixtures.rs @@ -23,8 +23,8 @@ run_test!("br_if", wasm_br_if); run_test!("br_table", wasm_br_table); run_test!("br", wasm_br); run_test!("break-drop", wasm_break_drop); -// TODO: run_test!("call_indirect", wasm_call_indirect); -// TODO: run_test!("call", wasm_call); +run_test!("call_indirect", wasm_call_indirect); +run_test!("call", wasm_call); run_test!("comments", wasm_comments); // TODO: run_test!("conversions", wasm_conversions); // TODO: run_test!("custom_section", wasm_custom_section); diff --git a/src/interpreter/env.rs b/src/interpreter/env.rs index 1e29429..18d7b91 100644 --- a/src/interpreter/env.rs +++ b/src/interpreter/env.rs @@ -112,6 +112,10 @@ impl ModuleInstanceInterface for EnvModuleInstance { self.instance.function_type(function_index, externals) } + fn function_type_by_index<'a>(&self, type_index: u32) -> Result { + self.instance.function_type_by_index(type_index) + } + fn table(&self, index: ItemIndex) -> Result, Error> { self.instance.table(index) } @@ -132,8 +136,9 @@ impl ModuleInstanceInterface for EnvModuleInstance { self.instance.function_reference_indirect(table_idx, type_idx, func_idx, externals) } - fn function_body<'a>(&'a self, internal_index: u32) -> Result>, Error> { - self.instance.function_body(internal_index) + fn function_body<'a>(&'a self, internal_index: u32, function_type: Option<&FunctionType>) -> Result>, Error> { + Ok(None) + //self.instance.function_body(internal_index, function_type) } /*fn call_function(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result, Error> { diff --git a/src/interpreter/env_native.rs b/src/interpreter/env_native.rs index 9edd21a..51cd14c 100644 --- a/src/interpreter/env_native.rs +++ b/src/interpreter/env_native.rs @@ -90,7 +90,7 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { ItemIndex::IndexSpace(index) | ItemIndex::Internal(index) => index, ItemIndex::External(_) => unreachable!("trying to call function, exported by native env module"), }; - +println!("=== env_native.function_type({})", index); if index < NATIVE_INDEX_FUNC_MIN { return self.env.function_type(function_index, externals); } @@ -101,6 +101,10 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { .map(|f| FunctionType::new(f.params.clone(), f.result.clone())) } + fn function_type_by_index<'b>(&self, type_index: u32) -> Result { + self.function_type(ItemIndex::Internal(type_index), None) + } + fn table(&self, index: ItemIndex) -> Result, Error> { self.env.table(index) } @@ -121,15 +125,16 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { self.env.function_reference_indirect(table_idx, type_idx, func_idx, externals) } - fn function_body<'b>(&'b self, internal_index: u32) -> Result>, Error> { - self.env.function_body(internal_index) + fn function_body<'b>(&'b self, internal_index: u32, function_type: Option<&FunctionType>) -> Result>, Error> { + Ok(None) + //self.env.function_body(internal_index, function_type) } fn call_internal_function(&self, outer: CallerContext, index: u32, function_type: Option<&FunctionType>) -> Result, Error> { if index < NATIVE_INDEX_FUNC_MIN { return self.env.call_internal_function(outer, index, function_type); } - +println!("=== env_native.args({:?})", outer.value_stack); // TODO: check type self.functions .get((index - NATIVE_INDEX_FUNC_MIN) as usize) diff --git a/src/interpreter/module.rs b/src/interpreter/module.rs index 486f283..f08be0d 100644 --- a/src/interpreter/module.rs +++ b/src/interpreter/module.rs @@ -7,7 +7,7 @@ use interpreter::Error; use interpreter::imports::ModuleImports; use interpreter::memory::MemoryInstance; use interpreter::program::ProgramInstanceEssence; -use interpreter::runner::{Interpreter, FunctionContext}; +use interpreter::runner::{Interpreter, FunctionContext, prepare_function_args}; use interpreter::stack::StackWithLimit; use interpreter::table::TableInstance; use interpreter::validator::{Validator, FunctionValidationContext}; @@ -49,8 +49,10 @@ pub trait ModuleInstanceInterface { fn execute_export(&self, name: &str, params: ExecutionParams) -> Result, Error>; /// Get export entry. fn export_entry<'a>(&self, name: &str, externals: Option<&'a HashMap>>, required_type: &ExportEntryType) -> Result; - /// Get function type. + /// Get function type for given function index. fn function_type<'a>(&self, function_index: ItemIndex, externals: Option<&'a HashMap>>) -> Result; + /// Get function type for given function index. + fn function_type_by_index<'a>(&self, type_index: u32) -> Result; /// Get table reference. fn table(&self, index: ItemIndex) -> Result, Error>; /// Get memory reference. @@ -62,7 +64,7 @@ pub trait ModuleInstanceInterface { /// Get function indirect reference. fn function_reference_indirect<'a>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'a HashMap>>) -> Result, Error>; /// Get internal function for interpretation. - fn function_body<'a>(&'a self, internal_index: u32) -> Result>, Error>; + fn function_body<'a>(&'a self, internal_index: u32, function_type: Option<&FunctionType>) -> Result>, Error>; /// Call function with given index in functions index space. //fn call_function<'a>(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result, Error>; /// Call function with given index in the given table. @@ -117,8 +119,6 @@ pub struct InternalFunctionReference<'a> { pub module: Arc, /// Internal function index. pub internal_index: u32, - // Internal function type. - //pub function_type: &'a FunctionType, } impl<'a> fmt::Debug for InternalFunctionReference<'a> { @@ -233,15 +233,6 @@ impl ModuleInstance { }), } } - - fn require_function_type(&self, type_index: u32) -> Result<&FunctionType, Error> { - self.module.type_section() - .ok_or(Error::Validation(format!("type reference {} exists in module without type section", type_index))) - .and_then(|s| match s.types().get(type_index as usize) { - Some(&Type::Function(ref function_type)) => Ok(function_type), - _ => Err(Error::Validation(format!("missing function type with index {}", type_index))), - }) - } } impl ModuleInstanceInterface for ModuleInstance { @@ -250,7 +241,7 @@ impl ModuleInstanceInterface for ModuleInstance { if let Some(start_function) = self.module.start_section() { let func_type_index = self.require_function(ItemIndex::IndexSpace(start_function))?; if is_user_module { // tests use non-empty main functions - let func_type = self.require_function_type(func_type_index)?; + let func_type = self.function_type_by_index(func_type_index)?; if func_type.return_type() != None || func_type.params().len() != 0 { return Err(Error::Validation("start function expected to have type [] -> []".into())); } @@ -287,7 +278,7 @@ impl ModuleInstanceInterface for ModuleInstance { // for functions we need to check if function type matches in both modules &External::Function(ref function_type_index) => { // External::Function points to function type in type section in this module - let import_function_type = self.require_function_type(*function_type_index)?; + let import_function_type = self.function_type_by_index(*function_type_index)?; // get export entry in external module let external_module = self.imports.module(externals, import.module())?; @@ -300,7 +291,7 @@ impl ModuleInstanceInterface for ModuleInstance { _ => return Err(Error::Validation(format!("Export with name {} from module {} is not a function", import.field(), import.module()))), }; - if import_function_type != &export_function_type { + if import_function_type != export_function_type { return Err(Error::Validation(format!("Export function type {} mismatch. Expected function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}", function_type_index, import_function_type.params(), import_function_type.return_type(), export_function_type.params(), export_function_type.return_type()))); @@ -346,7 +337,7 @@ impl ModuleInstanceInterface for ModuleInstance { let code_section = self.module.code_section().expect("function_section_len != 0; function_section_len == code_section_len; qed"); // check every function body for (index, function) in function_section.entries().iter().enumerate() { - let function_type = self.require_function_type(function.type_ref())?; + let function_type = self.function_type_by_index(function.type_ref())?; let function_body = code_section.bodies().get(index as usize).ok_or(Error::Validation(format!("Missing body for function {}", index)))?; let mut locals = function_type.params().to_vec(); locals.extend(function_body.locals().iter().flat_map(|l| repeat(l.value_type()).take(l.count() as usize))); @@ -439,19 +430,37 @@ impl ModuleInstanceInterface for ModuleInstance { } fn function_type<'a>(&self, function_index: ItemIndex, externals: Option<&'a HashMap>>) -> Result { +println!("=== getting function_type({}, {:?})", self.name, function_index); match self.imports.parse_function_index(function_index) { ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"), ItemIndex::Internal(index) => self.require_function(ItemIndex::Internal(index)) - .and_then(|ft| self.require_function_type(ft).map(Clone::clone)), + .and_then(|ft| self.function_type_by_index(ft)), ItemIndex::External(index) => self.module.import_section() .ok_or(Error::Function(format!("trying to access external function with index {} in module without import section", index))) .and_then(|s| s.entries().get(index as usize) .ok_or(Error::Function(format!("trying to access external function with index {} in module with {}-entries import section", index, s.entries().len())))) - .and_then(|e| self.imports.module(externals, e.module())) - .and_then(|m| m.function_type(ItemIndex::IndexSpace(index), externals)), + .and_then(|e| { + let module = self.imports.module(externals, e.module())?; + let function_type = match e.external() { + &External::Function(type_index) => self.function_type_by_index(type_index)?, + _ => return Err(Error::Function(format!("exported function {} is not a function", index))), + }; + let external_function_index = self.imports.function(externals, e, Some(&function_type))?; + module.function_type(ItemIndex::IndexSpace(external_function_index), externals) + }), } } + fn function_type_by_index<'a>(&self, type_index: u32) -> Result { + self.module.type_section() + .ok_or(Error::Validation(format!("type reference {} exists in module without type section", type_index))) + .and_then(|s| match s.types().get(type_index as usize) { + Some(&Type::Function(ref function_type)) => Ok(function_type), + _ => Err(Error::Validation(format!("missing function type with index {}", type_index))), + }) + .map(Clone::clone) + } + fn table(&self, index: ItemIndex) -> Result, Error> { match self.imports.parse_table_index(index) { ItemIndex::IndexSpace(_) => unreachable!("parse_table_index resolves IndexSpace option"), @@ -501,9 +510,11 @@ impl ModuleInstanceInterface for ModuleInstance { ItemIndex::External(index) => { let import_section = self.module.import_section().unwrap(); let import_entry = import_section.entries().get(index as usize).unwrap(); + let required_function_type = self.function_type(ItemIndex::External(index), externals)?; + let internal_function_index = self.imports.function(externals, import_entry, Some(&required_function_type))?; Ok(InternalFunctionReference { module: self.imports.module(externals, import_entry.module())?, - internal_index: index + internal_index: internal_function_index, }) }, } @@ -527,7 +538,7 @@ impl ModuleInstanceInterface for ModuleInstance { module.function_reference(ItemIndex::IndexSpace(index), externals) } - fn function_body<'a>(&'a self, internal_index: u32/*, externals: Option<&'a HashMap>>*/) -> Result>, Error> { + fn function_body<'a>(&'a self, internal_index: u32, function_type: Option<&FunctionType>) -> Result>, Error> { // internal index = index of function in functions section && index of code in code section // get function type index let function_type_index = self.module @@ -637,30 +648,21 @@ impl ModuleInstanceInterface for ModuleInstance { }*/ fn call_internal_function(&self, mut outer: CallerContext, index: u32, required_function_type: Option<&FunctionType>) -> Result, Error> { +println!("=== call_internal_function({})", index); let function_type_index = self.require_function(ItemIndex::Internal(index))?; - let function_type = self.require_function_type(function_type_index)?; - let function_body = self.function_body(index)?; + let function_type = self.function_type_by_index(function_type_index)?; + let function_body = self.function_body(index, required_function_type)?; if let Some(ref required_function_type) = required_function_type { - if required_function_type != &function_type { + if **required_function_type != function_type { return Err(Error::Function(format!("expected function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}", required_function_type.params(), required_function_type.return_type(), function_type.params(), function_type.return_type()))); } } - let args = function_type.params().iter() - .map(|param_type| { - let param_value = outer.value_stack.pop()?; - let actual_type = param_value.variable_type(); - let expected_type = (*param_type).into(); - if actual_type != Some(expected_type) { - return Err(Error::Function(format!("invalid parameter type {:?} when expected {:?}", actual_type, expected_type))); - } - - VariableInstance::new(true, expected_type, param_value) - }) - .collect::, _>>()?; - + let mut args = prepare_function_args(&function_type, outer.value_stack)?; +println!("=== call_internal_Function.function_type: {:?}", function_type); +println!("=== call_internal_Function.args: {:?}", args); let function_ref = InternalFunctionReference { module: self.self_ref(Some(outer.externals))?, internal_index: index }; let inner = FunctionContext::new(function_ref, outer.externals, outer.value_stack_limit, outer.frame_stack_limit, &function_type, args); Interpreter::run_function(inner) @@ -699,7 +701,7 @@ pub fn check_limits(limits: &ResizableLimits) -> Result<(), Error> { Ok(()) } -fn prepare_function_locals(function_type: &FunctionType, function_body: &FuncBody, outer: &mut CallerContext) -> Result, Error> { +/*fn prepare_function_locals(function_type: &FunctionType, function_body: &FuncBody, outer: &mut CallerContext) -> Result, Error> { // locals = function arguments + defined locals function_type.params().iter().rev() .map(|param_type| { @@ -718,7 +720,7 @@ fn prepare_function_locals(function_type: &FunctionType, function_body: &FuncBod .flat_map(|l| repeat(l.value_type().into()).take(l.count() as usize)) .map(|vt| VariableInstance::new(true, vt, RuntimeValue::default(vt)))) .collect::, _>>() -} +}*/ fn get_initializer(expr: &InitExpr, module: &Module, imports: &ModuleImports, expected_type: VariableType) -> Result { let first_opcode = match expr.code().len() { diff --git a/src/interpreter/program.rs b/src/interpreter/program.rs index cc272ee..5eb3ff8 100644 --- a/src/interpreter/program.rs +++ b/src/interpreter/program.rs @@ -34,19 +34,29 @@ impl ProgramInstance { /// Instantiate module with validation. pub fn add_module<'a>(&self, name: &str, module: Module, externals: Option<&'a HashMap>>) -> Result, Error> { let module_instance = Arc::new(ModuleInstance::new(Arc::downgrade(&self.essence), name.into(), module)?); - module_instance.instantiate(true, externals)?; - // replace existing module with the same name with new one self.essence.modules.write().insert(name.into(), module_instance.clone()); - Ok(module_instance) + // replace existing module with the same name with new one + match module_instance.instantiate(true, externals) { + Ok(()) => Ok(module_instance), + Err(err) => { + self.essence.modules.write().remove(name.into()); + Err(err) + } + } } /// Instantiate module without validation. pub fn add_module_without_validation<'a>(&self, name: &str, module: Module, externals: Option<&'a HashMap>>) -> Result, Error> { let module_instance = Arc::new(ModuleInstance::new(Arc::downgrade(&self.essence), name.into(), module)?); - module_instance.instantiate(false, externals)?; - // replace existing module with the same name with new one self.essence.modules.write().insert(name.into(), module_instance.clone()); - Ok(module_instance) + // replace existing module with the same name with new one + match module_instance.instantiate(false, externals) { + Ok(()) => Ok(module_instance), + Err(err) => { + self.essence.modules.write().remove(name.into()); + Err(err) + } + } } /// Insert instantiated module. diff --git a/src/interpreter/runner.rs b/src/interpreter/runner.rs index ce05e8d..815be94 100644 --- a/src/interpreter/runner.rs +++ b/src/interpreter/runner.rs @@ -38,7 +38,7 @@ pub struct FunctionContext<'a> { /// Values stack. pub value_stack: StackWithLimit, /// Blocks frames stack. - pub frame_stack: StackWithLimit>, + pub frame_stack: StackWithLimit, /// Current instruction position. pub position: usize, } @@ -53,7 +53,7 @@ pub enum InstructionOutcome<'a> { /// Branch to given frame. Branch(usize), /// Execute block. - ExecuteBlock(bool), + ExecuteBlock, /// Execute function call. ExecuteCall(InternalFunctionReference<'a>), /// End current frame. @@ -64,21 +64,29 @@ pub enum InstructionOutcome<'a> { /// Control stack frame. #[derive(Debug, Clone)] -pub struct BlockFrame<'a> { - /// Is loop frame? - is_loop: bool, +pub struct BlockFrame { + /// Frame type. + frame_type: BlockFrameType, + /// A label for reference to block instruction. + begin_position: usize, /// A label for reference from branch instructions. branch_position: usize, /// A label for reference from end instructions. end_position: usize, - /// Block body. - body: &'a [Opcode], /// 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, } +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum BlockFrameType { + Block, + Loop, + IfTrue, + IfElse, +} + enum RunResult<'a> { Return(Option), NestedCall(FunctionContext<'a>), @@ -92,17 +100,25 @@ impl Interpreter { loop { let mut function_context = function_stack.pop_back().expect("on loop entry - not empty; on loop continue - checking for emptiness; qed"); let function_ref = function_context.function.clone(); - let function_body = function_ref.module.function_body(function_ref.internal_index)?; + let function_body = function_ref.module.function_body(function_ref.internal_index, None)?; let function_return = match function_body { Some(function_body) => { if !function_context.is_initialized() { + let return_type = function_context.return_type; function_context.initialize(function_body.locals)?; + function_context.push_frame(BlockFrameType::Block, 0, function_body.body.len() - 1, function_body.body.len() - 1, return_type)?; } Interpreter::do_run_function(&mut function_context, function_body.body)? }, None => { + // move locals back to the stack + let locals_to_move: Vec<_> = function_context.locals.drain(..).rev().collect(); + for local in locals_to_move { + function_context.value_stack_mut().push(local.get())?; + } + let nested_context = CallerContext::nested(&mut function_context); RunResult::Return(function_ref.module.call_internal_function(nested_context, function_ref.internal_index, None)?) }, @@ -126,20 +142,32 @@ impl Interpreter { } fn do_run_function<'a>(function_context: &mut FunctionContext<'a>, function_body: &[Opcode]) -> Result, Error> { - loop { - let block_frame = function_context.frame_stack_mut().pop(); - let block_result = Interpreter::run_block_instructions(function_context, block_frame.body)?; + // TODO: slow!!! remove this after 'plaining' function instructions + let mut body_stack = VecDeque::with_capacity(function_context.frame_stack().values().len()); + body_stack.push_back(function_body); + for frame in function_context.frame_stack().values().iter().skip(1) { + let instruction = &body_stack.back().unwrap()[frame.begin_position]; + let instruction_body = Interpreter::into_block(instruction, frame.frame_type)?; + body_stack.push_back(instruction_body); + } + loop { + //let block_frame = function_context.frame_stack_mut().pop().expect("TODO"); + //let block_body = body_stack.back().expect("TODO"); + let block_result = Interpreter::run_block_instructions(function_context, body_stack.back().expect("TODO"))?; +println!("=== block_result = {:?}", block_result); match block_result { InstructionOutcome::RunInstruction | InstructionOutcome::RunNextInstruction => unreachable!("managed by run_block_instructions"), InstructionOutcome::Branch(mut index) => { - // discard index - 2 blocks (-1 since last block is popped && -1 since we have already popped current block) - while index >= 2 { + // discard index - 1 blocks + while index >= 1 { function_context.discard_frame()?; + assert!(body_stack.pop_back().is_some()); index -= 1; } function_context.pop_frame(true)?; + assert!(body_stack.pop_back().is_some()); if function_context.frame_stack().is_empty() { return Ok(RunResult::Return(match function_context.return_type { BlockType::Value(_) => Some(function_context.value_stack_mut().pop()?), @@ -147,12 +175,20 @@ impl Interpreter { })); } }, - InstructionOutcome::ExecuteBlock(branch) => { - function_context.frame_stack_mut().push_penultimate(block_frame)?; + InstructionOutcome::ExecuteBlock => { + function_context.position = 0; + let top_frame = function_context.frame_stack().top().expect("TODO"); + let instruction = &body_stack.back().expect("TODO")[top_frame.begin_position]; + let block_body = Interpreter::into_block(instruction, top_frame.frame_type)?; + body_stack.push_back(block_body); + //body_stack.insert(block_body.len() - 1, block_body); + //function_context.frame_stack_mut().push_penultimate(block_frame)?; }, InstructionOutcome::ExecuteCall(func_ref) => return Ok(RunResult::NestedCall(function_context.nested(func_ref)?)), - InstructionOutcome::End => (), - InstructionOutcome::Return => return Ok(RunResult::Return(match function_context.return_type { + InstructionOutcome::End if !function_context.frame_stack().is_empty() => { + assert!(body_stack.pop_back().is_some()); + }, + InstructionOutcome::End | InstructionOutcome::Return => return Ok(RunResult::Return(match function_context.return_type { BlockType::Value(_) => Some(function_context.value_stack_mut().pop()?), BlockType::NoResult => None, })), @@ -160,7 +196,7 @@ impl Interpreter { } } - fn run_block_instructions<'a, 'b>(context: &'b mut FunctionContext<'a>, body: &'a [Opcode]) -> Result, Error> { + fn run_block_instructions<'a, 'b>(context: &'b mut FunctionContext<'a>, body: &[Opcode]) -> Result, Error> { loop { let instruction = &body[context.position]; @@ -168,7 +204,7 @@ impl Interpreter { InstructionOutcome::RunInstruction => (), InstructionOutcome::RunNextInstruction => context.position += 1, InstructionOutcome::Branch(index) => return Ok(InstructionOutcome::Branch(index)), - InstructionOutcome::ExecuteBlock(branch) => return Ok(InstructionOutcome::ExecuteBlock(branch)), + InstructionOutcome::ExecuteBlock => return Ok(InstructionOutcome::ExecuteBlock), InstructionOutcome::ExecuteCall(func_ref) => { context.position += 1; return Ok(InstructionOutcome::ExecuteCall(func_ref)); @@ -182,7 +218,8 @@ impl Interpreter { } } - fn run_instruction<'a, 'b>(context: &'b mut FunctionContext<'a>, opcode: &'a Opcode) -> Result, Error> { + fn run_instruction<'a, 'b>(context: &'b mut FunctionContext<'a>, opcode: &Opcode) -> Result, Error> { + println!("=== RUNNING {:?}", opcode); match opcode { &Opcode::Unreachable => Interpreter::run_unreachable(context), &Opcode::Nop => Interpreter::run_nop(context), @@ -376,19 +413,19 @@ impl Interpreter { } } - fn into_block(opcode: &Opcode, branch: bool) -> Result<&[Opcode], Error> { + fn into_block(opcode: &Opcode, frame_type: BlockFrameType) -> Result<&[Opcode], Error> { match opcode { - &Opcode::Block(_, ref ops) if branch => Ok(ops.elements()), - &Opcode::Loop(_, ref ops) if branch => Ok(ops.elements()), - &Opcode::If(_, ref ops) => Ok(Interpreter::separate_if(ops.elements(), branch)), + &Opcode::Block(_, ref ops) if frame_type != BlockFrameType::IfElse => Ok(ops.elements()), + &Opcode::Loop(_, ref ops) if frame_type != BlockFrameType::IfElse => Ok(ops.elements()), + &Opcode::If(_, ref ops) => Ok(Interpreter::separate_if(ops.elements(), frame_type)), _ => Err(Error::Interpreter("trying to read block from non-bock instruction".into())) } } - fn separate_if(body: &[Opcode], branch: bool) -> &[Opcode] { + fn separate_if(body: &[Opcode], frame_type: BlockFrameType) -> &[Opcode] { let body_len = body.len(); let else_index = body.iter().position(|op| *op == Opcode::Else).unwrap_or(body_len - 1); - let (begin_index, end_index) = if branch { + let (begin_index, end_index) = if frame_type == BlockFrameType::IfTrue { (0, else_index + 1) } else { (else_index + 1, body_len) @@ -404,26 +441,27 @@ impl Interpreter { Ok(InstructionOutcome::RunNextInstruction) } - fn run_block<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType, body: &'a [Opcode]) -> Result, Error> { - let frame_position = context.position + 1; - context.push_frame(false, frame_position, frame_position, body, block_type)?; - Ok(InstructionOutcome::ExecuteBlock(true)) - } - - fn run_loop<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType, body: &'a [Opcode]) -> Result, Error> { + fn run_block<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType, body: &[Opcode]) -> Result, Error> { let frame_position = context.position; - context.push_frame(true, frame_position, frame_position + 1, body, block_type)?; - Ok(InstructionOutcome::ExecuteBlock(true)) + context.push_frame(BlockFrameType::Block, frame_position, frame_position + 1, frame_position + 1, block_type)?; + Ok(InstructionOutcome::ExecuteBlock) } - fn run_if<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType, body: &'a [Opcode]) -> Result, Error> { + fn run_loop<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType, body: &[Opcode]) -> Result, Error> { + let frame_position = context.position; + context.push_frame(BlockFrameType::Loop, frame_position, frame_position, frame_position + 1, block_type)?; + Ok(InstructionOutcome::ExecuteBlock) + } + + fn run_if<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType, body: &[Opcode]) -> Result, Error> { let branch = context.value_stack_mut().pop_as()?; - let branch_body = Interpreter::separate_if(body, branch); + let block_frame_type = if branch { BlockFrameType::IfTrue } else { BlockFrameType::IfElse }; + let branch_body = Interpreter::separate_if(body, block_frame_type); if branch_body.len() != 0 { - let frame_position = context.position + 1; - context.push_frame(false, frame_position, frame_position, branch_body, block_type)?; - Ok(InstructionOutcome::ExecuteBlock(branch)) + let frame_position = context.position; + context.push_frame(block_frame_type, frame_position, frame_position + 1, frame_position + 1, block_type)?; + Ok(InstructionOutcome::ExecuteBlock) } else { Ok(InstructionOutcome::RunNextInstruction) } @@ -464,7 +502,15 @@ impl Interpreter { fn run_call_indirect<'a, 'b>(context: &'b mut FunctionContext<'a>, type_idx: u32) -> Result, Error> { let table_func_idx: u32 = context.value_stack_mut().pop_as()?; - Ok(InstructionOutcome::ExecuteCall(context.module().function_reference_indirect(DEFAULT_TABLE_INDEX, type_idx, table_func_idx, Some(context.externals))?)) + let function_reference = context.module().function_reference_indirect(DEFAULT_TABLE_INDEX, type_idx, table_func_idx, Some(context.externals))?; + let required_function_type = context.module().function_type_by_index(type_idx)?; + let actual_function_type = function_reference.module.function_type(ItemIndex::Internal(function_reference.internal_index), Some(context.externals))?; + if required_function_type != actual_function_type { + return Err(Error::Function(format!("expected function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}", + required_function_type.params(), required_function_type.return_type(), + actual_function_type.params(), actual_function_type.return_type()))); + } + Ok(InstructionOutcome::ExecuteCall(function_reference)) } fn run_drop<'a>(context: &mut FunctionContext) -> Result, Error> { @@ -981,17 +1027,9 @@ impl<'a> FunctionContext<'a> { pub fn nested(&mut self, function: InternalFunctionReference<'a>) -> Result { let function_type = function.module.function_type(ItemIndex::Internal(function.internal_index), Some(self.externals))?; let function_return_type = function_type.return_type().map(|vt| BlockType::Value(vt)).unwrap_or(BlockType::NoResult); - let function_locals = function_type.params().iter().rev().map(|param_type| { - let param_value = self.value_stack.pop()?; - let actual_type = param_value.variable_type(); - let expected_type = (*param_type).into(); - if actual_type != Some(expected_type) { - return Err(Error::Function(format!("invalid parameter type {:?} when expected {:?}", actual_type, expected_type))); - } - - VariableInstance::new(true, expected_type, param_value) - }).collect::, _>>()?; - + let function_locals = prepare_function_args(&function_type, &mut self.value_stack)?; +println!("=== nested_call.function_type: {:?}", function_type); +println!("=== nested_call.function_locals: {:?}", function_locals); Ok(FunctionContext { is_initialized: false, function: function, @@ -1053,16 +1091,16 @@ impl<'a> FunctionContext<'a> { &self.frame_stack } - pub fn frame_stack_mut(&mut self) -> &mut StackWithLimit> { + pub fn frame_stack_mut(&mut self) -> &mut StackWithLimit { &mut self.frame_stack } - pub fn push_frame(&mut self, is_loop: bool, branch_position: usize, end_position: usize, body: &'a [Opcode], signature: BlockType) -> Result<(), Error> { + pub fn push_frame(&mut self, frame_type: BlockFrameType, begin_position: usize, branch_position: usize, end_position: usize, signature: BlockType) -> Result<(), Error> { self.frame_stack.push(BlockFrame { - is_loop: is_loop, + frame_type: frame_type, + begin_position: begin_position, branch_position: branch_position, end_position: end_position, - body: body, value_limit: self.value_stack.len(), signature: signature, }) @@ -1080,7 +1118,7 @@ impl<'a> FunctionContext<'a> { } let frame_value = match frame.signature { - BlockType::Value(_) if !frame.is_loop || !is_branch => Some(self.value_stack.pop()?), + BlockType::Value(_) if frame.frame_type != BlockFrameType::Loop || !is_branch => Some(self.value_stack.pop()?), _ => None, }; self.value_stack.resize(frame.value_limit, RuntimeValue::I32(0)); @@ -1099,19 +1137,6 @@ impl<'a> fmt::Debug for FunctionContext<'a> { } } -impl<'a> BlockFrame<'a> { -/* pub fn invalid() -> Self { - BlockFrame { - is_loop: false, - branch_position: usize::max_value(), - end_position: usize::max_value(), - branch: true, - value_limit: usize::max_value(), - signature: BlockType::NoResult, - } - }*/ -} - fn effective_address(address: u32, offset: u32) -> Result { match offset.checked_add(address) { None => Err(Error::Memory(format!("invalid memory access: {} + {}", offset, address))), @@ -1119,6 +1144,21 @@ fn effective_address(address: u32, offset: u32) -> Result { } } +pub fn prepare_function_args(function_type: &FunctionType, caller_stack: &mut StackWithLimit) -> Result, Error> { + let mut args = function_type.params().iter().rev().map(|param_type| { + let param_value = caller_stack.pop()?; + let actual_type = param_value.variable_type(); + let expected_type = (*param_type).into(); + if actual_type != Some(expected_type) { + return Err(Error::Function(format!("invalid parameter type {:?} when expected {:?}", actual_type, expected_type))); + } + + VariableInstance::new(true, expected_type, param_value) + }).collect::, _>>()?; + args.reverse(); + Ok(args) +} + /*fn prepare_function_locals(function_type: &FunctionType, function_body: &FuncBody, value_stack: &mut StackWithLimit) -> Result, Error> { // locals = function arguments + defined locals function_type.params().iter().rev() From 7bd7c6df98d5f3235775735b5a919b0df47ff981 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Mon, 19 Jun 2017 12:04:16 +0300 Subject: [PATCH 06/11] cleanup --- src/interpreter/env.rs | 30 ++-- src/interpreter/env_native.rs | 36 +++-- src/interpreter/module.rs | 250 +++++++++------------------------- src/interpreter/runner.rs | 4 +- 4 files changed, 91 insertions(+), 229 deletions(-) diff --git a/src/interpreter/env.rs b/src/interpreter/env.rs index 18d7b91..b3e36ea 100644 --- a/src/interpreter/env.rs +++ b/src/interpreter/env.rs @@ -108,14 +108,6 @@ impl ModuleInstanceInterface for EnvModuleInstance { self.instance.export_entry(name, externals, required_type) } - fn function_type<'a>(&self, function_index: ItemIndex, externals: Option<&'a HashMap>>) -> Result { - self.instance.function_type(function_index, externals) - } - - fn function_type_by_index<'a>(&self, type_index: u32) -> Result { - self.instance.function_type_by_index(type_index) - } - fn table(&self, index: ItemIndex) -> Result, Error> { self.instance.table(index) } @@ -128,6 +120,14 @@ impl ModuleInstanceInterface for EnvModuleInstance { self.instance.global(index, variable_type) } + fn function_type<'a>(&self, function_index: ItemIndex, externals: Option<&'a HashMap>>) -> Result { + self.instance.function_type(function_index, externals) + } + + fn function_type_by_index<'a>(&self, type_index: u32) -> Result { + self.instance.function_type_by_index(type_index) + } + fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap>>) -> Result, Error> { self.instance.function_reference(index, externals) } @@ -136,21 +136,11 @@ impl ModuleInstanceInterface for EnvModuleInstance { self.instance.function_reference_indirect(table_idx, type_idx, func_idx, externals) } - fn function_body<'a>(&'a self, internal_index: u32, function_type: Option<&FunctionType>) -> Result>, Error> { + fn function_body<'a>(&'a self, _internal_index: u32) -> Result>, Error> { Ok(None) - //self.instance.function_body(internal_index, function_type) } - /*fn call_function(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result, Error> { - self.instance.call_function(outer, index, function_type) - } - - fn call_function_indirect(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result, Error> { - self.instance.call_function_indirect(outer, table_index, type_index, func_index) - }*/ - - fn call_internal_function(&self, outer: CallerContext, index: u32, _function_type: Option<&FunctionType>) -> Result, Error> { - // TODO: check function type + fn call_internal_function(&self, outer: CallerContext, index: u32) -> Result, Error> { // to make interpreter independent of *SCRIPTEN runtime, just make abort/assert = interpreter Error match index { INDEX_FUNC_ABORT => self.global(ItemIndex::IndexSpace(INDEX_GLOBAL_ABORT), Some(VariableType::I32)) diff --git a/src/interpreter/env_native.rs b/src/interpreter/env_native.rs index 51cd14c..83c7f80 100644 --- a/src/interpreter/env_native.rs +++ b/src/interpreter/env_native.rs @@ -85,12 +85,24 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { self.env.export_entry(name, externals, required_type) } + fn table(&self, index: ItemIndex) -> Result, Error> { + self.env.table(index) + } + + fn memory(&self, index: ItemIndex) -> Result, Error> { + self.env.memory(index) + } + + fn global(&self, index: ItemIndex, variable_type: Option) -> Result, Error> { + self.env.global(index, variable_type) + } + fn function_type<'b>(&self, function_index: ItemIndex, externals: Option<&'b HashMap>>) -> Result { let index = match function_index { ItemIndex::IndexSpace(index) | ItemIndex::Internal(index) => index, ItemIndex::External(_) => unreachable!("trying to call function, exported by native env module"), }; -println!("=== env_native.function_type({})", index); + if index < NATIVE_INDEX_FUNC_MIN { return self.env.function_type(function_index, externals); } @@ -105,18 +117,6 @@ println!("=== env_native.function_type({})", index); self.function_type(ItemIndex::Internal(type_index), None) } - fn table(&self, index: ItemIndex) -> Result, Error> { - self.env.table(index) - } - - fn memory(&self, index: ItemIndex) -> Result, Error> { - self.env.memory(index) - } - - fn global(&self, index: ItemIndex, variable_type: Option) -> Result, Error> { - self.env.global(index, variable_type) - } - fn function_reference<'b>(&self, index: ItemIndex, externals: Option<&'b HashMap>>) -> Result, Error> { self.env.function_reference(index, externals) } @@ -125,17 +125,15 @@ println!("=== env_native.function_type({})", index); self.env.function_reference_indirect(table_idx, type_idx, func_idx, externals) } - fn function_body<'b>(&'b self, internal_index: u32, function_type: Option<&FunctionType>) -> Result>, Error> { + fn function_body<'b>(&'b self, _internal_index: u32) -> Result>, Error> { Ok(None) - //self.env.function_body(internal_index, function_type) } - fn call_internal_function(&self, outer: CallerContext, index: u32, function_type: Option<&FunctionType>) -> Result, Error> { + fn call_internal_function(&self, outer: CallerContext, index: u32) -> Result, Error> { if index < NATIVE_INDEX_FUNC_MIN { - return self.env.call_internal_function(outer, index, function_type); + return self.env.call_internal_function(outer, index); } -println!("=== env_native.args({:?})", outer.value_stack); - // TODO: check type + self.functions .get((index - NATIVE_INDEX_FUNC_MIN) as usize) .ok_or(Error::Native(format!("trying to call native function with index {}", index))) diff --git a/src/interpreter/module.rs b/src/interpreter/module.rs index f08be0d..43248ec 100644 --- a/src/interpreter/module.rs +++ b/src/interpreter/module.rs @@ -49,28 +49,24 @@ pub trait ModuleInstanceInterface { fn execute_export(&self, name: &str, params: ExecutionParams) -> Result, Error>; /// Get export entry. fn export_entry<'a>(&self, name: &str, externals: Option<&'a HashMap>>, required_type: &ExportEntryType) -> Result; - /// Get function type for given function index. - fn function_type<'a>(&self, function_index: ItemIndex, externals: Option<&'a HashMap>>) -> Result; - /// Get function type for given function index. - fn function_type_by_index<'a>(&self, type_index: u32) -> Result; /// Get table reference. fn table(&self, index: ItemIndex) -> Result, Error>; /// Get memory reference. fn memory(&self, index: ItemIndex) -> Result, Error>; /// Get global reference. fn global(&self, index: ItemIndex, variable_type: Option) -> Result, Error>; + /// Get function type for given function index. + fn function_type<'a>(&self, function_index: ItemIndex, externals: Option<&'a HashMap>>) -> Result; + /// Get function type for given function index. + fn function_type_by_index<'a>(&self, type_index: u32) -> Result; /// Get function reference. fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap>>) -> Result, Error>; /// Get function indirect reference. fn function_reference_indirect<'a>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'a HashMap>>) -> Result, Error>; /// Get internal function for interpretation. - fn function_body<'a>(&'a self, internal_index: u32, function_type: Option<&FunctionType>) -> Result>, Error>; - /// Call function with given index in functions index space. - //fn call_function<'a>(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result, Error>; - /// Call function with given index in the given table. - //fn call_function_indirect<'a>(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result, Error>; - /// Call function with internal index. - fn call_internal_function<'a>(&self, outer: CallerContext, index: u32, function_type: Option<&FunctionType>) -> Result, Error>; + fn function_body<'a>(&'a self, internal_index: u32) -> Result>, Error>; + /// Call function with given internal index. + fn call_internal_function<'a>(&self, outer: CallerContext, index: u32) -> Result, Error>; } /// Item index in items index space. @@ -129,8 +125,6 @@ impl<'a> fmt::Debug for InternalFunctionReference<'a> { /// Internal function ready for interpretation. pub struct InternalFunction<'a> { - /// Function type. - pub func_type: &'a FunctionType, /// Function locals. pub locals: &'a [Local], /// Function body. @@ -233,6 +227,19 @@ impl ModuleInstance { }), } } + + fn check_function_type(&self, function_index: ItemIndex, required_function_type: Option<&FunctionType>, externals: Option<&HashMap>>) -> Result<(), Error> { + if let Some(ref required_function_type) = required_function_type { + let actual_function_type = self.function_type(function_index, externals)?; + if **required_function_type != actual_function_type { + return Err(Error::Function(format!("expected function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}", + required_function_type.params(), required_function_type.return_type(), + actual_function_type.params(), actual_function_type.return_type()))); + } + } + + Ok(()) + } } impl ModuleInstanceInterface for ModuleInstance { @@ -385,9 +392,8 @@ impl ModuleInstanceInterface for ModuleInstance { let ExecutionParams { args, externals } = params; let mut args = StackWithLimit::with_data(args, DEFAULT_VALUE_STACK_LIMIT); let function_reference = self.function_reference(ItemIndex::IndexSpace(index), Some(&externals))?; - let function_type = self.function_type(ItemIndex::IndexSpace(index), Some(&externals))?; let function_context = CallerContext::topmost(&mut args, &externals); - function_reference.module.call_internal_function(function_context, function_reference.internal_index, Some(&function_type)) + function_reference.module.call_internal_function(function_context, function_reference.internal_index) } fn execute_export(&self, name: &str, params: ExecutionParams) -> Result, Error> { @@ -429,38 +435,6 @@ impl ModuleInstanceInterface for ModuleInstance { .ok_or(Error::Program(format!("unresolved import {}", name)))) } - fn function_type<'a>(&self, function_index: ItemIndex, externals: Option<&'a HashMap>>) -> Result { -println!("=== getting function_type({}, {:?})", self.name, function_index); - match self.imports.parse_function_index(function_index) { - ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"), - ItemIndex::Internal(index) => self.require_function(ItemIndex::Internal(index)) - .and_then(|ft| self.function_type_by_index(ft)), - ItemIndex::External(index) => self.module.import_section() - .ok_or(Error::Function(format!("trying to access external function with index {} in module without import section", index))) - .and_then(|s| s.entries().get(index as usize) - .ok_or(Error::Function(format!("trying to access external function with index {} in module with {}-entries import section", index, s.entries().len())))) - .and_then(|e| { - let module = self.imports.module(externals, e.module())?; - let function_type = match e.external() { - &External::Function(type_index) => self.function_type_by_index(type_index)?, - _ => return Err(Error::Function(format!("exported function {} is not a function", index))), - }; - let external_function_index = self.imports.function(externals, e, Some(&function_type))?; - module.function_type(ItemIndex::IndexSpace(external_function_index), externals) - }), - } - } - - fn function_type_by_index<'a>(&self, type_index: u32) -> Result { - self.module.type_section() - .ok_or(Error::Validation(format!("type reference {} exists in module without type section", type_index))) - .and_then(|s| match s.types().get(type_index as usize) { - Some(&Type::Function(ref function_type)) => Ok(function_type), - _ => Err(Error::Validation(format!("missing function type with index {}", type_index))), - }) - .map(Clone::clone) - } - fn table(&self, index: ItemIndex) -> Result, Error> { match self.imports.parse_table_index(index) { ItemIndex::IndexSpace(_) => unreachable!("parse_table_index resolves IndexSpace option"), @@ -500,6 +474,32 @@ println!("=== getting function_type({}, {:?})", self.name, function_index); } } + fn function_type<'a>(&self, function_index: ItemIndex, externals: Option<&'a HashMap>>) -> Result { + match self.imports.parse_function_index(function_index) { + ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"), + ItemIndex::Internal(index) => self.require_function(ItemIndex::Internal(index)) + .and_then(|ft| self.function_type_by_index(ft)), + ItemIndex::External(index) => self.module.import_section() + .ok_or(Error::Function(format!("trying to access external function with index {} in module without import section", index))) + .and_then(|s| s.entries().get(index as usize) + .ok_or(Error::Function(format!("trying to access external function with index {} in module with {}-entries import section", index, s.entries().len())))) + .and_then(|e| match e.external() { + &External::Function(type_index) => self.function_type_by_index(type_index), + _ => Err(Error::Function(format!("exported function {} is not a function", index))), + }), + } + } + + fn function_type_by_index<'a>(&self, type_index: u32) -> Result { + self.module.type_section() + .ok_or(Error::Validation(format!("type reference {} exists in module without type section", type_index))) + .and_then(|s| match s.types().get(type_index as usize) { + Some(&Type::Function(ref function_type)) => Ok(function_type), + _ => Err(Error::Validation(format!("missing function type with index {}", type_index))), + }) + .map(Clone::clone) + } + fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap>>) -> Result, Error> { match self.imports.parse_function_index(index) { ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"), @@ -508,8 +508,10 @@ println!("=== getting function_type({}, {:?})", self.name, function_index); internal_index: index, }), ItemIndex::External(index) => { - let import_section = self.module.import_section().unwrap(); - let import_entry = import_section.entries().get(index as usize).unwrap(); + let import_entry = self.module.import_section() + .expect("parse_function_index has returned External(index); it is only returned when import section exists; qed") + .entries().get(index as usize) + .expect("parse_function_index has returned External(index); it is only returned when entry with index exists in import section exists; qed"); let required_function_type = self.function_type(ItemIndex::External(index), externals)?; let internal_function_index = self.imports.function(externals, import_entry, Some(&required_function_type))?; Ok(InternalFunctionReference { @@ -521,13 +523,6 @@ println!("=== getting function_type({}, {:?})", self.name, function_index); } fn function_reference_indirect<'a>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'a HashMap>>) -> Result, Error> { - let function_type = match self.module.type_section() - .ok_or(Error::Function(format!("trying to indirect call function {} with non-existent function section", func_idx))) - .and_then(|s| s.types().get(type_idx as usize) - .ok_or(Error::Function(format!("trying to indirect call function {} with non-existent type index {}", func_idx, type_idx))))? { - &Type::Function(ref function_type) => function_type, - }; - let table = self.table(ItemIndex::IndexSpace(table_idx))?; let (module, index) = match table.get(func_idx)? { RuntimeValue::AnyFunc(module, index) => (module.clone(), index), @@ -535,32 +530,18 @@ println!("=== getting function_type({}, {:?})", self.name, function_index); }; let module = self.imports.module(externals, &module)?; + let required_function_type = self.function_type_by_index(type_idx)?; + let actual_function_type = module.function_type(ItemIndex::IndexSpace(index), externals)?; + if required_function_type != actual_function_type { + return Err(Error::Function(format!("expected indirect function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}", + required_function_type.params(), required_function_type.return_type(), + actual_function_type.params(), actual_function_type.return_type()))); + } + module.function_reference(ItemIndex::IndexSpace(index), externals) } - fn function_body<'a>(&'a self, internal_index: u32, function_type: Option<&FunctionType>) -> Result>, Error> { - // internal index = index of function in functions section && index of code in code section - // get function type index - let function_type_index = self.module - .function_section() - .ok_or(Error::Function(format!("trying to call function with index {} in module without function section", internal_index))) - .and_then(|s| s.entries() - .get(internal_index as usize) - .ok_or(Error::Function(format!("trying to call function with index {} in module with {} functions", internal_index, s.entries().len()))))? - .type_ref(); - // function type index = index of function type in types index - // get function type - let item_type = self.module - .type_section() - .ok_or(Error::Function(format!("trying to call function with index {} in module without types section", internal_index))) - .and_then(|s| s.types() - .get(function_type_index as usize) - .ok_or(Error::Function(format!("trying to call function with type index {} in module with {} types", function_type_index, s.types().len()))))?; - let actual_function_type = match item_type { - &Type::Function(ref function_type) => function_type, - }; - - // get function body + fn function_body<'a>(&'a self, internal_index: u32) -> Result>, Error> { let function_body = self.module .code_section() .ok_or(Error::Function(format!("trying to call function with index {} in module without code section", internal_index))) @@ -569,100 +550,14 @@ println!("=== getting function_type({}, {:?})", self.name, function_index); .ok_or(Error::Function(format!("trying to call function with index {} in module with {} functions codes", internal_index, s.bodies().len()))))?; Ok(Some(InternalFunction { - func_type: actual_function_type, locals: function_body.locals(), body: function_body.code().elements(), })) - /*match self.imports.parse_function_index(index) { - ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"), - ItemIndex::Internal(index) => { - // internal index = index of function in functions section && index of code in code section - // get function type index - let function_type_index = self.module - .function_section() - .ok_or(Error::Function(format!("trying to call function with index {} in module without function section", index))) - .and_then(|s| s.entries() - .get(index as usize) - .ok_or(Error::Function(format!("trying to call function with index {} in module with {} functions", index, s.entries().len()))))? - .type_ref(); - // function type index = index of function type in types index - // get function type - let item_type = self.module - .type_section() - .ok_or(Error::Function(format!("trying to call function with index {} in module without types section", index))) - .and_then(|s| s.types() - .get(function_type_index as usize) - .ok_or(Error::Function(format!("trying to call function with type index {} in module with {} types", function_type_index, s.types().len()))))?; - let actual_function_type = match item_type { - &Type::Function(ref function_type) => function_type, - }; - - // get function body - let function_body = self.module - .code_section() - .ok_or(Error::Function(format!("trying to call function with index {} in module without code section", index))) - .and_then(|s| s.bodies() - .get(index as usize) - .ok_or(Error::Function(format!("trying to call function with index {} in module with {} functions codes", index, s.bodies().len()))))?; - - Ok(Some(Function { - func_type: actual_function_type, - body: function_body.code().elements(), - })) - }, - ItemIndex::External(index) => { - }, - }*/ } - /*fn call_function(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result, Error> { - match self.imports.parse_function_index(index) { - ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"), - ItemIndex::Internal(index) => self.call_internal_function(outer, index, function_type), - ItemIndex::External(index) => self.module.import_section() - .ok_or(Error::Function(format!("trying to access external function with index {} in module without import section", index))) - .and_then(|s| s.entries().get(index as usize) - .ok_or(Error::Function(format!("trying to access external function with index {} in module with {}-entries import section", index, s.entries().len())))) - .and_then(|e| Ok((self.imports.module(Some(outer.externals), e.module())?, - self.imports.function(Some(outer.externals), e, function_type)?))) - .and_then(|(m, index)| m.call_internal_function(outer, index, function_type)), - } - } - - fn call_function_indirect(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result, Error> { - let function_type = match self.module.type_section() - .ok_or(Error::Function(format!("trying to indirect call function {} with non-existent function section", func_index))) - .and_then(|s| s.types().get(type_index as usize) - .ok_or(Error::Function(format!("trying to indirect call function {} with non-existent type index {}", func_index, type_index))))? { - &Type::Function(ref function_type) => function_type, - }; - - let table = self.table(table_index)?; - let (module, index) = match table.get(func_index)? { - RuntimeValue::AnyFunc(module, index) => (module.clone(), index), - _ => return Err(Error::Function(format!("trying to indirect call function {} via non-anyfunc table {:?}", func_index, table_index))), - }; - - let module = self.imports.module(Some(outer.externals), &module)?; - module.call_function(outer, ItemIndex::IndexSpace(index), Some(function_type)) - }*/ - - fn call_internal_function(&self, mut outer: CallerContext, index: u32, required_function_type: Option<&FunctionType>) -> Result, Error> { -println!("=== call_internal_function({})", index); - let function_type_index = self.require_function(ItemIndex::Internal(index))?; - let function_type = self.function_type_by_index(function_type_index)?; - let function_body = self.function_body(index, required_function_type)?; - - if let Some(ref required_function_type) = required_function_type { - if **required_function_type != function_type { - return Err(Error::Function(format!("expected function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}", - required_function_type.params(), required_function_type.return_type(), function_type.params(), function_type.return_type()))); - } - } - + fn call_internal_function(&self, mut outer: CallerContext, index: u32) -> Result, Error> { + let function_type = self.function_type(ItemIndex::Internal(index), None)?; let mut args = prepare_function_args(&function_type, outer.value_stack)?; -println!("=== call_internal_Function.function_type: {:?}", function_type); -println!("=== call_internal_Function.args: {:?}", args); let function_ref = InternalFunctionReference { module: self.self_ref(Some(outer.externals))?, internal_index: index }; let inner = FunctionContext::new(function_ref, outer.externals, outer.value_stack_limit, outer.frame_stack_limit, &function_type, args); Interpreter::run_function(inner) @@ -701,27 +596,6 @@ pub fn check_limits(limits: &ResizableLimits) -> Result<(), Error> { Ok(()) } -/*fn prepare_function_locals(function_type: &FunctionType, function_body: &FuncBody, outer: &mut CallerContext) -> Result, Error> { - // locals = function arguments + defined locals - function_type.params().iter().rev() - .map(|param_type| { - let param_value = outer.value_stack.pop()?; - let actual_type = param_value.variable_type(); - let expected_type = (*param_type).into(); - if actual_type != Some(expected_type) { - return Err(Error::Function(format!("invalid parameter type {:?} when expected {:?}", actual_type, expected_type))); - } - - VariableInstance::new(true, expected_type, param_value) - }) - .collect::>().into_iter().rev() - .chain(function_body.locals() - .iter() - .flat_map(|l| repeat(l.value_type().into()).take(l.count() as usize)) - .map(|vt| VariableInstance::new(true, vt, RuntimeValue::default(vt)))) - .collect::, _>>() -}*/ - fn get_initializer(expr: &InitExpr, module: &Module, imports: &ModuleImports, expected_type: VariableType) -> Result { let first_opcode = match expr.code().len() { 1 => &expr.code()[0], diff --git a/src/interpreter/runner.rs b/src/interpreter/runner.rs index 815be94..3454e4c 100644 --- a/src/interpreter/runner.rs +++ b/src/interpreter/runner.rs @@ -100,7 +100,7 @@ impl Interpreter { loop { let mut function_context = function_stack.pop_back().expect("on loop entry - not empty; on loop continue - checking for emptiness; qed"); let function_ref = function_context.function.clone(); - let function_body = function_ref.module.function_body(function_ref.internal_index, None)?; + let function_body = function_ref.module.function_body(function_ref.internal_index)?; let function_return = match function_body { Some(function_body) => { @@ -120,7 +120,7 @@ impl Interpreter { } let nested_context = CallerContext::nested(&mut function_context); - RunResult::Return(function_ref.module.call_internal_function(nested_context, function_ref.internal_index, None)?) + RunResult::Return(function_ref.module.call_internal_function(nested_context, function_ref.internal_index)?) }, }; From ad390c95fd4738add92a7ca35b1b0228ec9d25de Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Mon, 19 Jun 2017 12:09:18 +0300 Subject: [PATCH 07/11] cleaning --- src/interpreter/env_native.rs | 3 --- src/interpreter/runner.rs | 32 +++----------------------------- 2 files changed, 3 insertions(+), 32 deletions(-) diff --git a/src/interpreter/env_native.rs b/src/interpreter/env_native.rs index 83c7f80..9c6ff7d 100644 --- a/src/interpreter/env_native.rs +++ b/src/interpreter/env_native.rs @@ -13,9 +13,6 @@ use interpreter::variable::{VariableInstance, VariableType}; /// Min index of native function. pub const NATIVE_INDEX_FUNC_MIN: u32 = 10001; -/// User function closure type. -// pub type UserFunctionClosure<'a> = &'a mut FnMut(context: CallerContext) -> Result, Error>; - /// User functions executor. pub trait UserFunctionExecutor { /// Execute function with given name. diff --git a/src/interpreter/runner.rs b/src/interpreter/runner.rs index 3454e4c..610a31e 100644 --- a/src/interpreter/runner.rs +++ b/src/interpreter/runner.rs @@ -142,7 +142,7 @@ impl Interpreter { } fn do_run_function<'a>(function_context: &mut FunctionContext<'a>, function_body: &[Opcode]) -> Result, Error> { - // TODO: slow!!! remove this after 'plaining' function instructions + // TODO: remove this after 'plaining' function instructions let mut body_stack = VecDeque::with_capacity(function_context.frame_stack().values().len()); body_stack.push_back(function_body); for frame in function_context.frame_stack().values().iter().skip(1) { @@ -152,10 +152,8 @@ impl Interpreter { } loop { - //let block_frame = function_context.frame_stack_mut().pop().expect("TODO"); - //let block_body = body_stack.back().expect("TODO"); let block_result = Interpreter::run_block_instructions(function_context, body_stack.back().expect("TODO"))?; -println!("=== block_result = {:?}", block_result); + match block_result { InstructionOutcome::RunInstruction | InstructionOutcome::RunNextInstruction => unreachable!("managed by run_block_instructions"), InstructionOutcome::Branch(mut index) => { @@ -219,7 +217,6 @@ println!("=== block_result = {:?}", block_result); } fn run_instruction<'a, 'b>(context: &'b mut FunctionContext<'a>, opcode: &Opcode) -> Result, Error> { - println!("=== RUNNING {:?}", opcode); match opcode { &Opcode::Unreachable => Interpreter::run_unreachable(context), &Opcode::Nop => Interpreter::run_nop(context), @@ -1028,8 +1025,7 @@ impl<'a> FunctionContext<'a> { let function_type = function.module.function_type(ItemIndex::Internal(function.internal_index), Some(self.externals))?; let function_return_type = function_type.return_type().map(|vt| BlockType::Value(vt)).unwrap_or(BlockType::NoResult); let function_locals = prepare_function_args(&function_type, &mut self.value_stack)?; -println!("=== nested_call.function_type: {:?}", function_type); -println!("=== nested_call.function_locals: {:?}", function_locals); + Ok(FunctionContext { is_initialized: false, function: function, @@ -1158,25 +1154,3 @@ pub fn prepare_function_args(function_type: &FunctionType, caller_stack: &mut St args.reverse(); Ok(args) } - -/*fn prepare_function_locals(function_type: &FunctionType, function_body: &FuncBody, value_stack: &mut StackWithLimit) -> Result, Error> { - // locals = function arguments + defined locals - function_type.params().iter().rev() - .map(|param_type| { - let param_value = outer.value_stack.pop()?; - let actual_type = param_value.variable_type(); - let expected_type = (*param_type).into(); - if actual_type != Some(expected_type) { - return Err(Error::Function(format!("invalid parameter type {:?} when expected {:?}", actual_type, expected_type))); - } - - VariableInstance::new(true, expected_type, param_value) - }) - .collect::>().into_iter().rev() - .chain(function_body.locals() - .iter() - .flat_map(|l| repeat(l.value_type().into()).take(l.count() as usize)) - .map(|vt| VariableInstance::new(true, vt, RuntimeValue::default(vt)))) - .collect::, _>>() -} -*/ \ No newline at end of file From 8a17a012c580dbaa068f041ce68ded4db78c0ea9 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Mon, 19 Jun 2017 12:35:17 +0300 Subject: [PATCH 08/11] cleaning --- spec/src/run.rs | 2 +- src/interpreter/env.rs | 10 ++++---- src/interpreter/env_native.rs | 17 +++++++------- src/interpreter/imports.rs | 2 +- src/interpreter/module.rs | 43 ++++++++++++----------------------- src/interpreter/runner.rs | 14 ++++++------ src/interpreter/stack.rs | 3 --- src/interpreter/tests/wabt.rs | 2 +- 8 files changed, 39 insertions(+), 54 deletions(-) diff --git a/spec/src/run.rs b/spec/src/run.rs index 142bbc1..bd4c968 100644 --- a/spec/src/run.rs +++ b/spec/src/run.rs @@ -104,7 +104,7 @@ fn run_action(program: &ProgramInstance, action: &test::Action) let module = module.trim_left_matches('$'); let module = program.module(&module).expect(&format!("Expected program to have loaded module {}", module)); - module.export_entry(field.as_ref(), None, &ExportEntryType::Any) + module.export_entry(field.as_ref(), &ExportEntryType::Any) .and_then(|i| match i { elements::Internal::Global(global_index) => Ok(ItemIndex::IndexSpace(global_index)), _ => Err(InterpreterError::Global(format!("Expected to have exported global with name {}", field))), diff --git a/src/interpreter/env.rs b/src/interpreter/env.rs index b3e36ea..ec6ead8 100644 --- a/src/interpreter/env.rs +++ b/src/interpreter/env.rs @@ -104,8 +104,8 @@ impl ModuleInstanceInterface for EnvModuleInstance { self.instance.execute_export(name, params) } - fn export_entry<'a>(&self, name: &str, externals: Option<&'a HashMap>>, required_type: &ExportEntryType) -> Result { - self.instance.export_entry(name, externals, required_type) + fn export_entry<'a>(&self, name: &str, required_type: &ExportEntryType) -> Result { + self.instance.export_entry(name, required_type) } fn table(&self, index: ItemIndex) -> Result, Error> { @@ -120,11 +120,11 @@ impl ModuleInstanceInterface for EnvModuleInstance { self.instance.global(index, variable_type) } - fn function_type<'a>(&self, function_index: ItemIndex, externals: Option<&'a HashMap>>) -> Result { - self.instance.function_type(function_index, externals) + fn function_type(&self, function_index: ItemIndex) -> Result { + self.instance.function_type(function_index) } - fn function_type_by_index<'a>(&self, type_index: u32) -> Result { + fn function_type_by_index(&self, type_index: u32) -> Result { self.instance.function_type_by_index(type_index) } diff --git a/src/interpreter/env_native.rs b/src/interpreter/env_native.rs index 9c6ff7d..b4b18db 100644 --- a/src/interpreter/env_native.rs +++ b/src/interpreter/env_native.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use std::collections::HashMap; use parking_lot::RwLock; -use elements::{FunctionType, Internal, ValueType, Opcode}; +use elements::{FunctionType, Internal, ValueType}; use interpreter::Error; use interpreter::module::{ModuleInstanceInterface, ExecutionParams, ItemIndex, CallerContext, ExportEntryType, InternalFunctionReference, InternalFunction}; @@ -74,12 +74,13 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { self.env.execute_export(name, params) } - fn export_entry<'b>(&self, name: &str, externals: Option<&'b HashMap>>, required_type: &ExportEntryType) -> Result { + fn export_entry<'b>(&self, name: &str, required_type: &ExportEntryType) -> Result { if let Some(index) = self.by_name.get(name) { + // TODO: check type return Ok(Internal::Function(NATIVE_INDEX_FUNC_MIN + *index)); } - self.env.export_entry(name, externals, required_type) + self.env.export_entry(name, required_type) } fn table(&self, index: ItemIndex) -> Result, Error> { @@ -94,14 +95,14 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { self.env.global(index, variable_type) } - fn function_type<'b>(&self, function_index: ItemIndex, externals: Option<&'b HashMap>>) -> Result { + fn function_type(&self, function_index: ItemIndex) -> Result { let index = match function_index { ItemIndex::IndexSpace(index) | ItemIndex::Internal(index) => index, ItemIndex::External(_) => unreachable!("trying to call function, exported by native env module"), }; if index < NATIVE_INDEX_FUNC_MIN { - return self.env.function_type(function_index, externals); + return self.env.function_type(function_index); } self.functions @@ -110,8 +111,8 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { .map(|f| FunctionType::new(f.params.clone(), f.result.clone())) } - fn function_type_by_index<'b>(&self, type_index: u32) -> Result { - self.function_type(ItemIndex::Internal(type_index), None) + fn function_type_by_index(&self, type_index: u32) -> Result { + self.function_type(ItemIndex::Internal(type_index)) } fn function_reference<'b>(&self, index: ItemIndex, externals: Option<&'b HashMap>>) -> Result, Error> { @@ -139,6 +140,6 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { } /// Create wrapper for env module with given native user functions. -pub fn env_native_module(env: Arc, user_functions: UserFunctions) -> Result { +pub fn env_native_module<'a>(env: Arc, user_functions: UserFunctions<'a>) -> Result { NativeModuleInstance::new(env, user_functions) } diff --git a/src/interpreter/imports.rs b/src/interpreter/imports.rs index 8703333..a21774d 100644 --- a/src/interpreter/imports.rs +++ b/src/interpreter/imports.rs @@ -161,7 +161,7 @@ impl ModuleImports { fn external_export<'a>(&self, externals: Option<&'a HashMap>>, import: &ImportEntry, required_type: &ExportEntryType) -> Result<(Arc, Internal), Error> { self.module(externals, import.module()) .and_then(|m| - m.export_entry(import.field(), externals, required_type) + m.export_entry(import.field(), required_type) .map(|e| (m, e))) } } diff --git a/src/interpreter/module.rs b/src/interpreter/module.rs index 43248ec..a100a1f 100644 --- a/src/interpreter/module.rs +++ b/src/interpreter/module.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use std::iter::repeat; use std::sync::{Arc, Weak}; use std::fmt; -use elements::{Module, InitExpr, Opcode, Type, FunctionType, FuncBody, Internal, External, BlockType, ResizableLimits, Local}; +use elements::{Module, InitExpr, Opcode, Type, FunctionType, Internal, External, BlockType, ResizableLimits, Local}; use interpreter::Error; use interpreter::imports::ModuleImports; use interpreter::memory::MemoryInstance; @@ -48,7 +48,7 @@ pub trait ModuleInstanceInterface { /// Execute function with the given export name. fn execute_export(&self, name: &str, params: ExecutionParams) -> Result, Error>; /// Get export entry. - fn export_entry<'a>(&self, name: &str, externals: Option<&'a HashMap>>, required_type: &ExportEntryType) -> Result; + fn export_entry<'a>(&self, name: &str, required_type: &ExportEntryType) -> Result; /// Get table reference. fn table(&self, index: ItemIndex) -> Result, Error>; /// Get memory reference. @@ -56,9 +56,9 @@ pub trait ModuleInstanceInterface { /// Get global reference. fn global(&self, index: ItemIndex, variable_type: Option) -> Result, Error>; /// Get function type for given function index. - fn function_type<'a>(&self, function_index: ItemIndex, externals: Option<&'a HashMap>>) -> Result; + fn function_type(&self, function_index: ItemIndex) -> Result; /// Get function type for given function index. - fn function_type_by_index<'a>(&self, type_index: u32) -> Result; + fn function_type_by_index(&self, type_index: u32) -> Result; /// Get function reference. fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap>>) -> Result, Error>; /// Get function indirect reference. @@ -66,7 +66,7 @@ pub trait ModuleInstanceInterface { /// Get internal function for interpretation. fn function_body<'a>(&'a self, internal_index: u32) -> Result>, Error>; /// Call function with given internal index. - fn call_internal_function<'a>(&self, outer: CallerContext, index: u32) -> Result, Error>; + fn call_internal_function(&self, outer: CallerContext, index: u32) -> Result, Error>; } /// Item index in items index space. @@ -227,19 +227,6 @@ impl ModuleInstance { }), } } - - fn check_function_type(&self, function_index: ItemIndex, required_function_type: Option<&FunctionType>, externals: Option<&HashMap>>) -> Result<(), Error> { - if let Some(ref required_function_type) = required_function_type { - let actual_function_type = self.function_type(function_index, externals)?; - if **required_function_type != actual_function_type { - return Err(Error::Function(format!("expected function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}", - required_function_type.params(), required_function_type.return_type(), - actual_function_type.params(), actual_function_type.return_type()))); - } - } - - Ok(()) - } } impl ModuleInstanceInterface for ModuleInstance { @@ -289,12 +276,12 @@ impl ModuleInstanceInterface for ModuleInstance { // get export entry in external module let external_module = self.imports.module(externals, import.module())?; - let export_entry = external_module.export_entry(import.field(), externals, &ExportEntryType::Function(import_function_type.clone()))?; + let export_entry = external_module.export_entry(import.field(), &ExportEntryType::Function(import_function_type.clone()))?; // export entry points to function in function index space // and Internal::Function points to type in type section let export_function_type = match export_entry { - Internal::Function(function_index) => external_module.function_type(ItemIndex::IndexSpace(function_index), externals)?, + Internal::Function(function_index) => external_module.function_type(ItemIndex::IndexSpace(function_index))?, _ => return Err(Error::Validation(format!("Export with name {} from module {} is not a function", import.field(), import.module()))), }; @@ -413,7 +400,7 @@ impl ModuleInstanceInterface for ModuleInstance { self.execute_index(index, params) } - fn export_entry<'a>(&self, name: &str, externals: Option<&'a HashMap>>, required_type: &ExportEntryType) -> Result { + fn export_entry<'a>(&self, name: &str, required_type: &ExportEntryType) -> Result { self.module.export_section() .ok_or(Error::Program(format!("trying to import {} from module without export section", name))) .and_then(|s| s.entries().iter() @@ -425,7 +412,7 @@ impl ModuleInstanceInterface for ModuleInstance { }, &ExportEntryType::Function(ref required_type) => match e.internal() { &Internal::Function(function_index) => - self.function_type(ItemIndex::IndexSpace(function_index), externals) + self.function_type(ItemIndex::IndexSpace(function_index)) .map(|ft| &ft == required_type) .unwrap_or(false), _ => false, @@ -474,7 +461,7 @@ impl ModuleInstanceInterface for ModuleInstance { } } - fn function_type<'a>(&self, function_index: ItemIndex, externals: Option<&'a HashMap>>) -> Result { + fn function_type(&self, function_index: ItemIndex) -> Result { match self.imports.parse_function_index(function_index) { ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"), ItemIndex::Internal(index) => self.require_function(ItemIndex::Internal(index)) @@ -490,7 +477,7 @@ impl ModuleInstanceInterface for ModuleInstance { } } - fn function_type_by_index<'a>(&self, type_index: u32) -> Result { + fn function_type_by_index(&self, type_index: u32) -> Result { self.module.type_section() .ok_or(Error::Validation(format!("type reference {} exists in module without type section", type_index))) .and_then(|s| match s.types().get(type_index as usize) { @@ -512,7 +499,7 @@ impl ModuleInstanceInterface for ModuleInstance { .expect("parse_function_index has returned External(index); it is only returned when import section exists; qed") .entries().get(index as usize) .expect("parse_function_index has returned External(index); it is only returned when entry with index exists in import section exists; qed"); - let required_function_type = self.function_type(ItemIndex::External(index), externals)?; + let required_function_type = self.function_type(ItemIndex::External(index))?; let internal_function_index = self.imports.function(externals, import_entry, Some(&required_function_type))?; Ok(InternalFunctionReference { module: self.imports.module(externals, import_entry.module())?, @@ -531,7 +518,7 @@ impl ModuleInstanceInterface for ModuleInstance { let module = self.imports.module(externals, &module)?; let required_function_type = self.function_type_by_index(type_idx)?; - let actual_function_type = module.function_type(ItemIndex::IndexSpace(index), externals)?; + let actual_function_type = module.function_type(ItemIndex::IndexSpace(index))?; if required_function_type != actual_function_type { return Err(Error::Function(format!("expected indirect function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}", required_function_type.params(), required_function_type.return_type(), @@ -556,8 +543,8 @@ impl ModuleInstanceInterface for ModuleInstance { } fn call_internal_function(&self, mut outer: CallerContext, index: u32) -> Result, Error> { - let function_type = self.function_type(ItemIndex::Internal(index), None)?; - let mut args = prepare_function_args(&function_type, outer.value_stack)?; + let function_type = self.function_type(ItemIndex::Internal(index))?; + let args = prepare_function_args(&function_type, outer.value_stack)?; let function_ref = InternalFunctionReference { module: self.self_ref(Some(outer.externals))?, internal_index: index }; let inner = FunctionContext::new(function_ref, outer.externals, outer.value_stack_limit, outer.frame_stack_limit, &function_type, args); Interpreter::run_function(inner) diff --git a/src/interpreter/runner.rs b/src/interpreter/runner.rs index 610a31e..093c718 100644 --- a/src/interpreter/runner.rs +++ b/src/interpreter/runner.rs @@ -7,7 +7,7 @@ use std::iter::repeat; use std::collections::{HashMap, VecDeque}; use elements::{Opcode, BlockType, FunctionType, Local}; use interpreter::Error; -use interpreter::module::{ModuleInstance, ModuleInstanceInterface, CallerContext, ItemIndex, InternalFunctionReference}; +use interpreter::module::{ModuleInstanceInterface, CallerContext, ItemIndex, InternalFunctionReference}; use interpreter::stack::StackWithLimit; use interpreter::value::{ RuntimeValue, TryInto, WrapInto, TryTruncateInto, ExtendInto, @@ -220,8 +220,8 @@ impl Interpreter { 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::Block(block_type, _) => Interpreter::run_block(context, block_type), + &Opcode::Loop(block_type, _) => Interpreter::run_loop(context, block_type), &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), @@ -438,13 +438,13 @@ impl Interpreter { Ok(InstructionOutcome::RunNextInstruction) } - fn run_block<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType, body: &[Opcode]) -> Result, Error> { + fn run_block<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType) -> Result, Error> { let frame_position = context.position; context.push_frame(BlockFrameType::Block, frame_position, frame_position + 1, frame_position + 1, block_type)?; Ok(InstructionOutcome::ExecuteBlock) } - fn run_loop<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType, body: &[Opcode]) -> Result, Error> { + fn run_loop<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType) -> Result, Error> { let frame_position = context.position; context.push_frame(BlockFrameType::Loop, frame_position, frame_position, frame_position + 1, block_type)?; Ok(InstructionOutcome::ExecuteBlock) @@ -501,7 +501,7 @@ impl Interpreter { let table_func_idx: u32 = context.value_stack_mut().pop_as()?; let function_reference = context.module().function_reference_indirect(DEFAULT_TABLE_INDEX, type_idx, table_func_idx, Some(context.externals))?; let required_function_type = context.module().function_type_by_index(type_idx)?; - let actual_function_type = function_reference.module.function_type(ItemIndex::Internal(function_reference.internal_index), Some(context.externals))?; + let actual_function_type = function_reference.module.function_type(ItemIndex::Internal(function_reference.internal_index))?; if required_function_type != actual_function_type { return Err(Error::Function(format!("expected function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}", required_function_type.params(), required_function_type.return_type(), @@ -1022,7 +1022,7 @@ impl<'a> FunctionContext<'a> { } pub fn nested(&mut self, function: InternalFunctionReference<'a>) -> Result { - let function_type = function.module.function_type(ItemIndex::Internal(function.internal_index), Some(self.externals))?; + let function_type = function.module.function_type(ItemIndex::Internal(function.internal_index))?; let function_return_type = function_type.return_type().map(|vt| BlockType::Value(vt)).unwrap_or(BlockType::NoResult); let function_locals = prepare_function_args(&function_type, &mut self.value_stack)?; diff --git a/src/interpreter/stack.rs b/src/interpreter/stack.rs index 603f8d8..78d1093 100644 --- a/src/interpreter/stack.rs +++ b/src/interpreter/stack.rs @@ -46,14 +46,12 @@ impl StackWithLimit where T: Clone { self.values .back() .ok_or(Error::Stack("non-empty stack expected".into())) -.map_err(|e| { panic!("1") }) } pub fn top_mut(&mut self) -> Result<&mut T, Error> { self.values .back_mut() .ok_or(Error::Stack("non-empty stack expected".into())) -.map_err(|e| { panic!("2") }) } pub fn get(&self, index: usize) -> Result<&T, Error> { @@ -90,7 +88,6 @@ impl StackWithLimit where T: Clone { self.values .pop_back() .ok_or(Error::Stack("non-empty stack expected".into())) -.map_err(|e| { panic!("3") }) } pub fn resize(&mut self, new_size: usize, dummy: T) { diff --git a/src/interpreter/tests/wabt.rs b/src/interpreter/tests/wabt.rs index de56d04..a93f3eb 100644 --- a/src/interpreter/tests/wabt.rs +++ b/src/interpreter/tests/wabt.rs @@ -807,7 +807,7 @@ fn callindirect_2() { assert_eq!(module.execute_index(3, vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(0)].into()).unwrap().unwrap(), RuntimeValue::I32(14)); assert_eq!(module.execute_index(3, vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(1)].into()).unwrap().unwrap(), RuntimeValue::I32(6)); assert_eq!(module.execute_index(3, vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(2)].into()).unwrap_err(), - Error::Function("expected function with signature ([I32, I32]) -> Some(I32) when got with ([I32]) -> Some(I32)".into())); + Error::Function("expected indirect function with signature ([I32, I32]) -> Some(I32) when got with ([I32]) -> Some(I32)".into())); assert_eq!(module.execute_index(3, vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(3)].into()).unwrap_err(), Error::Table("trying to read table item with index 3 when there are only 3 items".into())); } From e56c33439191d45d4d225c65967117554f41cec2 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Mon, 19 Jun 2017 12:41:19 +0300 Subject: [PATCH 09/11] missing comments --- src/interpreter/runner.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/interpreter/runner.rs b/src/interpreter/runner.rs index 093c718..fed497a 100644 --- a/src/interpreter/runner.rs +++ b/src/interpreter/runner.rs @@ -79,16 +79,24 @@ pub struct BlockFrame { signature: BlockType, } +/// Type of block frame. #[derive(Debug, Clone, Copy, PartialEq)] pub enum BlockFrameType { + /// Usual block frame. Block, + /// Loop frame (branching to the beginning of block). Loop, + /// True-subblock of if expression. IfTrue, + /// False-subblock of if expression. IfElse, } +/// Function run result. enum RunResult<'a> { + /// Function has returned (optional) value. Return(Option), + /// Function is calling other function. NestedCall(FunctionContext<'a>), } From 328e08358d6dff907bfa173687c84e86ff9590e7 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Mon, 19 Jun 2017 13:24:57 +0300 Subject: [PATCH 10/11] wasm_conversions --- spec/src/fixtures.rs | 4 +++- src/interpreter/value.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/spec/src/fixtures.rs b/spec/src/fixtures.rs index fdcc8b0..b74ac1a 100644 --- a/spec/src/fixtures.rs +++ b/spec/src/fixtures.rs @@ -26,7 +26,9 @@ run_test!("break-drop", wasm_break_drop); run_test!("call_indirect", wasm_call_indirect); run_test!("call", wasm_call); run_test!("comments", wasm_comments); -// TODO: run_test!("conversions", wasm_conversions); +// TODO: commented out until sNaN issue is resolved: +// https://github.com/NikVolf/parity-wasm/blob/b5aaf103cf28f1e36df832f4883f55043e67894b/src/interpreter/value.rs#L510 +// run_test!("conversions", wasm_conversions); // TODO: run_test!("custom_section", wasm_custom_section); run_test!("endianness", wasm_endianness); run_test!("f32_exports", wasm_exports); diff --git a/src/interpreter/value.rs b/src/interpreter/value.rs index 736407f..aa91d37 100644 --- a/src/interpreter/value.rs +++ b/src/interpreter/value.rs @@ -274,7 +274,9 @@ macro_rules! impl_try_truncate_into { return Err(Error::Value("invalid float value for this operation".into())); } - if self < $into::MIN as $from || self > $into::MAX as $from { + // range check + let result = self as $into; + if result as $from != self.trunc() { return Err(Error::Value("invalid float value for this operation".into())); } From 9949706e7cce263238f2b74036af7ce430db6a4d Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Mon, 19 Jun 2017 13:55:53 +0300 Subject: [PATCH 11/11] fixed shr && shl in dev configuration --- src/interpreter/module.rs | 2 +- src/interpreter/runner.rs | 24 ++++++++++++------------ src/interpreter/tests/basics.rs | 4 ++-- src/interpreter/tests/wabt.rs | 9 +++------ 4 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/interpreter/module.rs b/src/interpreter/module.rs index b470a28..2c2303b 100644 --- a/src/interpreter/module.rs +++ b/src/interpreter/module.rs @@ -344,7 +344,7 @@ impl ModuleInstanceInterface for ModuleInstance { &function_type); let block_type = function_type.return_type().map(BlockType::Value).unwrap_or(BlockType::NoResult); - Validator::validate_function(&mut context, block_type, function_body.code().elements())?; + Validator::validate_function(&mut context, block_type, function_body.code().elements()) .map_err(|e| { if let Error::Validation(msg) = e { Error::Validation(format!("Function #{} validation error: {}", index, msg)) diff --git a/src/interpreter/runner.rs b/src/interpreter/runner.rs index d8c6bc6..2b7e9f0 100644 --- a/src/interpreter/runner.rs +++ b/src/interpreter/runner.rs @@ -333,9 +333,9 @@ impl Interpreter { &Opcode::I32And => Interpreter::run_and::(context), &Opcode::I32Or => Interpreter::run_or::(context), &Opcode::I32Xor => Interpreter::run_xor::(context), - &Opcode::I32Shl => Interpreter::run_shl::(context), - &Opcode::I32ShrS => Interpreter::run_shr::(context), - &Opcode::I32ShrU => Interpreter::run_shr::(context), + &Opcode::I32Shl => Interpreter::run_shl::(context, 0x1F), + &Opcode::I32ShrS => Interpreter::run_shr::(context, 0x1F), + &Opcode::I32ShrU => Interpreter::run_shr::(context, 0x1F), &Opcode::I32Rotl => Interpreter::run_rotl::(context), &Opcode::I32Rotr => Interpreter::run_rotr::(context), @@ -352,9 +352,9 @@ impl Interpreter { &Opcode::I64And => Interpreter::run_and::(context), &Opcode::I64Or => Interpreter::run_or::(context), &Opcode::I64Xor => Interpreter::run_xor::(context), - &Opcode::I64Shl => Interpreter::run_shl::(context), - &Opcode::I64ShrS => Interpreter::run_shr::(context), - &Opcode::I64ShrU => Interpreter::run_shr::(context), + &Opcode::I64Shl => Interpreter::run_shl::(context, 0x3F), + &Opcode::I64ShrS => Interpreter::run_shr::(context, 0x3F), + &Opcode::I64ShrU => Interpreter::run_shr::(context, 0x3F), &Opcode::I64Rotl => Interpreter::run_rotl::(context), &Opcode::I64Rotr => Interpreter::run_rotr::(context), @@ -829,23 +829,23 @@ impl Interpreter { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_shl<'a, T>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From<>::Output> + TryInto, T: ops::Shl { + fn run_shl<'a, T>(context: &mut FunctionContext, mask: T) -> Result, Error> + where RuntimeValue: From<>::Output> + TryInto, T: ops::Shl + ops::BitAnd { context .value_stack_mut() .pop_pair_as::() - .map(|(left, right)| left.shl(right)) + .map(|(left, right)| left.shl(right & mask)) .map(|v| context.value_stack_mut().push(v.into())) .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_shr<'a, T, U>(context: &mut FunctionContext) -> Result, Error> - where RuntimeValue: From + TryInto, T: TransmuteInto, U: ops::Shr, >::Output: TransmuteInto { + fn run_shr<'a, T, U>(context: &mut FunctionContext, mask: U) -> Result, Error> + where RuntimeValue: From + TryInto, T: TransmuteInto, U: ops::Shr + ops::BitAnd, >::Output: TransmuteInto { context .value_stack_mut() .pop_pair_as::() .map(|(left, right)| (left.transmute_into(), right.transmute_into())) - .map(|(left, right)| left.shr(right)) + .map(|(left, right)| left.shr(right & mask)) .map(|v| v.transmute_into()) .map(|v| context.value_stack_mut().push(v.into())) .map(|_| InstructionOutcome::RunNextInstruction) diff --git a/src/interpreter/tests/basics.rs b/src/interpreter/tests/basics.rs index 2931529..1d00c0c 100644 --- a/src/interpreter/tests/basics.rs +++ b/src/interpreter/tests/basics.rs @@ -235,7 +235,7 @@ fn if_else_with_return_type_validation() { let imports = ModuleImports::new(Weak::default(), None); let mut context = FunctionValidationContext::new(&module, &imports, &[], 1024, 1024, &FunctionType::default()); - Validator::validate_block(&mut context, false, BlockType::NoResult, &[ + Validator::validate_function(&mut context, BlockType::NoResult, &[ Opcode::I32Const(1), Opcode::If(BlockType::NoResult, Opcodes::new(vec![ Opcode::I32Const(1), @@ -249,5 +249,5 @@ fn if_else_with_return_type_validation() { Opcode::End, ])), Opcode::End, - ], Opcode::End).unwrap(); + ]).unwrap(); } diff --git a/src/interpreter/tests/wabt.rs b/src/interpreter/tests/wabt.rs index a93f3eb..f7fec05 100644 --- a/src/interpreter/tests/wabt.rs +++ b/src/interpreter/tests/wabt.rs @@ -1,15 +1,12 @@ ///! Tests from https://github.com/WebAssembly/wabt/tree/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp -use std::sync::{Arc, Weak}; -use std::collections::HashMap; +use std::sync::Arc; use builder::module; -use elements::{Module, ValueType, Opcodes, Opcode, BlockType, FunctionType, Local}; +use elements::{ValueType, Opcodes, Opcode, BlockType, Local}; use interpreter::Error; -use interpreter::module::{ModuleInstance, ModuleInstanceInterface, ItemIndex}; +use interpreter::module::{ModuleInstanceInterface, ItemIndex}; use interpreter::program::ProgramInstance; -use interpreter::runner::{Interpreter, FunctionContext}; use interpreter::value::{RuntimeValue, TryInto}; -use interpreter::variable::{VariableInstance, VariableType}; fn make_function_i32(body: Opcodes) -> (ProgramInstance, Arc) { let module = module()