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()) }