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