From 4b61e1892970efe786fefafef51d8438c284cc6a Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Thu, 22 Jun 2017 17:52:05 +0300 Subject: [PATCH 1/9] plain instruction set draft --- examples/inject.rs | 22 +- src/elements/ops.rs | 68 +++-- src/elements/section.rs | 10 +- src/interpreter/env.rs | 4 +- src/interpreter/env_native.rs | 4 +- src/interpreter/module.rs | 75 ++++-- src/interpreter/program.rs | 25 +- src/interpreter/runner.rs | 223 +++++++++------- src/interpreter/stack.rs | 3 + src/interpreter/tests/basics.rs | 37 +-- src/interpreter/tests/wabt.rs | 453 ++++++++++++++------------------ src/interpreter/validator.rs | 215 ++++++++------- 12 files changed, 552 insertions(+), 587 deletions(-) diff --git a/examples/inject.rs b/examples/inject.rs index 03d027a..a897e8a 100644 --- a/examples/inject.rs +++ b/examples/inject.rs @@ -7,16 +7,22 @@ use parity_wasm::builder; pub fn inject_nop(opcodes: &mut elements::Opcodes) { use parity_wasm::elements::Opcode::*; - for opcode in opcodes.elements_mut().iter_mut() { - match opcode { - &mut Block(_, ref mut block) | &mut If(_, ref mut block) => { - inject_nop(block) - }, - _ => { } + let opcodes = opcodes.elements_mut(); + let mut position = 0; + loop { + let need_inject = match &opcodes[position] { + &Block(_) | &If(_) => true, + _ => false, + }; + if need_inject { + opcodes.insert(position + 1, Nop); + } + + position += 1; + if position >= opcodes.len() { + break; } } - - opcodes.elements_mut().insert(0, Nop); } fn main() { diff --git a/src/elements/ops.rs b/src/elements/ops.rs index b80b29e..114621c 100644 --- a/src/elements/ops.rs +++ b/src/elements/ops.rs @@ -33,12 +33,18 @@ impl Deserialize for Opcodes { fn deserialize(reader: &mut R) -> Result { let mut opcodes = Vec::new(); + let mut block_count = 1usize; loop { let opcode = Opcode::deserialize(reader)?; - let is_terminal = opcode.is_terminal(); + if opcode.is_terminal() { + block_count -= 1; + } else if opcode.is_block() { + block_count = block_count.checked_add(1).ok_or(Error::Other("too many opcodes"))?; + } + opcodes.push(opcode); - if is_terminal { + if block_count == 0 { break; } } @@ -100,9 +106,9 @@ impl Deserialize for InitExpr { pub enum Opcode { Unreachable, Nop, - Block(BlockType, Opcodes), - Loop(BlockType, Opcodes), - If(BlockType, Opcodes), + Block(BlockType), + Loop(BlockType), + If(BlockType), Else, End, Br(u32), @@ -289,6 +295,14 @@ pub enum Opcode { } impl Opcode { + /// Is this opcode starts the new block (which should end with terminal opcode). + pub fn is_block(&self) -> bool { + match self { + &Opcode::Block(_) | &Opcode::Loop(_) | &Opcode::If(_) => true, + _ => false, + } + } + /// Is this opcode determines the termination of opcode sequence /// `true` for `Opcode::End` pub fn is_terminal(&self) -> bool { @@ -311,9 +325,9 @@ impl Deserialize for Opcode { match val { 0x00 => Unreachable, 0x01 => Nop, - 0x02 => Block(BlockType::deserialize(reader)?, Opcodes::deserialize(reader)?), - 0x03 => Loop(BlockType::deserialize(reader)?, Opcodes::deserialize(reader)?), - 0x04 => If(BlockType::deserialize(reader)?, Opcodes::deserialize(reader)?), + 0x02 => Block(BlockType::deserialize(reader)?), + 0x03 => Loop(BlockType::deserialize(reader)?), + 0x04 => If(BlockType::deserialize(reader)?), 0x05 => Else, 0x0b => End, @@ -599,17 +613,14 @@ impl Serialize for Opcode { match self { Unreachable => op!(writer, 0x00), Nop => op!(writer, 0x01), - Block(block_type, ops) => op!(writer, 0x02, { + Block(block_type) => op!(writer, 0x02, { block_type.serialize(writer)?; - ops.serialize(writer)?; }), - Loop(block_type, ops) => op!(writer, 0x03, { + Loop(block_type) => op!(writer, 0x03, { block_type.serialize(writer)?; - ops.serialize(writer)?; }), - If(block_type, ops) => op!(writer, 0x04, { + If(block_type) => op!(writer, 0x04, { block_type.serialize(writer)?; - ops.serialize(writer)?; }), Else => op!(writer, 0x05), End => op!(writer, 0x0b), @@ -926,20 +937,19 @@ impl Serialize for InitExpr { #[test] fn ifelse() { // see if-else.wast/if-else.wasm - let opcode = super::deserialize_buffer::(vec![0x04, 0x7F, 0x41, 0x05, 0x05, 0x41, 0x07, 0x0B]) + let opcode = super::deserialize_buffer::(vec![0x04, 0x7F, 0x41, 0x05, 0x05, 0x41, 0x07, 0x0B, 0x0B]) .expect("valid hex of if instruction"); - match opcode { - Opcode::If(_, ops) => { - let before_else = ops.elements().iter() - .take_while(|op| match **op { Opcode::Else => false, _ => true }).count(); - let after_else = ops.elements().iter() - .skip_while(|op| match **op { Opcode::Else => false, _ => true }) - .take_while(|op| match **op { Opcode::End => false, _ => true }) - .count() - - 1; // minus Opcode::Else itself - - assert_eq!(before_else, after_else); - }, - _ => { panic!("Should be deserialized as if opcode"); } + let opcodes = opcode.elements(); + match &opcodes[0] { + &Opcode::If(_) => (), + _ => panic!("Should be deserialized as if opcode"), } -} \ No newline at end of file + let before_else = opcodes.iter().skip(1) + .take_while(|op| match **op { Opcode::Else => false, _ => true }).count(); + let after_else = opcodes.iter().skip(1) + .skip_while(|op| match **op { Opcode::Else => false, _ => true }) + .take_while(|op| match **op { Opcode::End => false, _ => true }) + .count() + - 1; // minus Opcode::Else itself + assert_eq!(before_else, after_else); +} diff --git a/src/elements/section.rs b/src/elements/section.rs index 8416770..c470da3 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -1016,13 +1016,9 @@ mod tests { FuncBody::new( vec![Local::new(1, ValueType::I32)], Opcodes::new(vec![ - Block( - BlockType::Value(ValueType::I32), - Opcodes::new(vec![ - GetGlobal(0), - End - ]) - ), + Block(BlockType::Value(ValueType::I32)), + GetGlobal(0), + End, End, ]) ) diff --git a/src/interpreter/env.rs b/src/interpreter/env.rs index ec6ead8..eef3fa2 100644 --- a/src/interpreter/env.rs +++ b/src/interpreter/env.rs @@ -92,9 +92,9 @@ impl EnvModuleInstance { } impl ModuleInstanceInterface for EnvModuleInstance { - fn instantiate<'a>(&self, is_user_module: bool, externals: Option<&'a HashMap>>) -> Result<(), Error> { + /*fn instantiate<'a>(&self, is_user_module: bool, externals: Option<&'a HashMap>>) -> Result<(), Error> { self.instance.instantiate(is_user_module, externals) - } + }*/ fn execute_index(&self, index: u32, params: ExecutionParams) -> Result, Error> { self.instance.execute_index(index, params) diff --git a/src/interpreter/env_native.rs b/src/interpreter/env_native.rs index 3d3d4e9..4b66800 100644 --- a/src/interpreter/env_native.rs +++ b/src/interpreter/env_native.rs @@ -110,9 +110,9 @@ impl<'a> NativeModuleInstance<'a> { } impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { - fn instantiate<'b>(&self, is_user_module: bool, externals: Option<&'b HashMap>>) -> Result<(), Error> { + /*fn instantiate<'b>(&self, is_user_module: bool, externals: Option<&'b HashMap>>) -> Result<(), Error> { self.env.instantiate(is_user_module, externals) - } + }*/ fn execute_index(&self, index: u32, params: ExecutionParams) -> Result, Error> { self.env.execute_index(index, params) diff --git a/src/interpreter/module.rs b/src/interpreter/module.rs index 557390e..3018324 100644 --- a/src/interpreter/module.rs +++ b/src/interpreter/module.rs @@ -39,10 +39,14 @@ pub enum ExportEntryType { Global(VariableType), } +pub struct InstantiationParams { + +} + /// Module instance API. pub trait ModuleInstanceInterface { /// Run instantiation-time procedures (validation and start function [if any] call). Module is not completely validated until this call. - fn instantiate<'a>(&self, is_user_module: bool, externals: Option<&'a HashMap>>) -> Result<(), Error>; + //fn instantiate<'a>(&self, is_user_module: bool, externals: Option<&'a HashMap>>) -> Result<(), Error>; /// Execute function with the given index. fn execute_index(&self, index: u32, params: ExecutionParams) -> Result, Error>; /// Execute function with the given export name. @@ -86,6 +90,8 @@ pub struct ModuleInstance { name: String, /// Module. module: Module, + /// Function labels. + functions_labels: HashMap>, /// Module imports. imports: ModuleImports, /// Tables. @@ -129,6 +135,8 @@ pub struct InternalFunction<'a> { pub locals: &'a [Local], /// Function body. pub body: &'a [Opcode], + /// Function labels. + pub labels: &'a HashMap, } impl<'a> ExecutionParams<'a> { @@ -199,38 +207,14 @@ impl ModuleInstance { name: name, module: module, imports: imports, + functions_labels: HashMap::new(), memory: memory, tables: tables, globals: globals, }) } - 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"), - ItemIndex::Internal(index) => self.module.function_section() - .ok_or(Error::Function(format!("missing internal function {}", index))) - .and_then(|s| s.entries().get(index as usize) - .ok_or(Error::Function(format!("missing internal function {}", index)))) - .map(|f| f.type_ref()), - ItemIndex::External(index) => self.module.import_section() - .ok_or(Error::Function(format!("missing external function {}", index))) - .and_then(|s| s.entries().get(index as usize) - .ok_or(Error::Function(format!("missing external function {}", index)))) - .and_then(|import| match import.external() { - &External::Function(type_idx) => Ok(type_idx), - _ => Err(Error::Function(format!("external function {} is pointing to non-function import", index))), - }), - } - } -} - -impl ModuleInstanceInterface for ModuleInstance { - fn instantiate<'a>(&self, is_user_module: bool, externals: Option<&'a HashMap>>) -> Result<(), Error> { + pub fn instantiate<'a>(&mut self, is_user_module: bool, externals: Option<&'a HashMap>>) -> Result<(), Error> { // validate start section if let Some(start_function) = self.module.start_section() { let func_type_index = self.require_function(ItemIndex::IndexSpace(start_function))?; @@ -352,6 +336,7 @@ impl ModuleInstanceInterface for ModuleInstance { e } })?; + self.functions_labels.insert(index as u32, context.function_labels()); } } @@ -381,14 +366,42 @@ impl ModuleInstanceInterface for ModuleInstance { } } + Ok(()) + } + + pub fn run_start_function(&self) -> Result<(), Error> { // execute start function (if any) if let Some(start_function) = self.module.start_section() { self.execute_index(start_function, ExecutionParams::default())?; } - Ok(()) } + fn self_ref<'a>(&self, externals: Option<&'a HashMap>>) -> Result, Error> { + self.imports.module(externals, &self.name).map_err(|_| panic!("xxx")) + } + + fn require_function(&self, index: ItemIndex) -> Result { + match self.imports.parse_function_index(index) { + ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"), + ItemIndex::Internal(index) => self.module.function_section() + .ok_or(Error::Function(format!("missing internal function {}", index))) + .and_then(|s| s.entries().get(index as usize) + .ok_or(Error::Function(format!("missing internal function {}", index)))) + .map(|f| f.type_ref()), + ItemIndex::External(index) => self.module.import_section() + .ok_or(Error::Function(format!("missing external function {}", index))) + .and_then(|s| s.entries().get(index as usize) + .ok_or(Error::Function(format!("missing external function {}", index)))) + .and_then(|import| match import.external() { + &External::Function(type_idx) => Ok(type_idx), + _ => Err(Error::Function(format!("external function {} is pointing to non-function import", index))), + }), + } + } +} + +impl ModuleInstanceInterface for ModuleInstance { fn execute_index(&self, index: u32, params: ExecutionParams) -> Result, Error> { let ExecutionParams { args, externals } = params; let mut args = StackWithLimit::with_data(args, DEFAULT_VALUE_STACK_LIMIT); @@ -549,18 +562,22 @@ impl ModuleInstanceInterface for ModuleInstance { .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()))))?; + let function_labels = self.functions_labels.get(&internal_index) + .ok_or(Error::Function(format!("trying to call non-validated internal function {}", internal_index)))?; Ok(Some(InternalFunction { locals: function_body.locals(), body: function_body.code().elements(), + labels: function_labels, })) } fn call_internal_function(&self, mut outer: CallerContext, index: u32) -> Result, Error> { + let function_labels = self.functions_labels.get(&index).ok_or(Error::Function(format!("trying to call non-validated internal function {}", index)))?; 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); + let inner = FunctionContext::new(function_ref, outer.externals, function_labels.clone(), outer.value_stack_limit, outer.frame_stack_limit, &function_type, args); Interpreter::run_function(inner) } } diff --git a/src/interpreter/program.rs b/src/interpreter/program.rs index 5eb3ff8..0427f85 100644 --- a/src/interpreter/program.rs +++ b/src/interpreter/program.rs @@ -33,7 +33,14 @@ 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)?); + let mut module_instance = ModuleInstance::new(Arc::downgrade(&self.essence), name.into(), module)?; + module_instance.instantiate(true, externals)?; + + let module_instance = Arc::new(module_instance); + self.essence.modules.write().insert(name.into(), module_instance.clone()); + module_instance.run_start_function()?; + Ok(module_instance) + /*let module_instance = Arc::new(ModuleInstance::new(Arc::downgrade(&self.essence), name.into(), module)?); self.essence.modules.write().insert(name.into(), module_instance.clone()); // replace existing module with the same name with new one match module_instance.instantiate(true, externals) { @@ -42,21 +49,7 @@ impl ProgramInstance { 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)?); - self.essence.modules.write().insert(name.into(), module_instance.clone()); - // 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 504b2d4..e2f4440 100644 --- a/src/interpreter/runner.rs +++ b/src/interpreter/runner.rs @@ -1,6 +1,6 @@ use std::mem; use std::ops; -use std::u32; +use std::{u32, usize}; use std::sync::Arc; use std::fmt::{self, Display}; use std::iter::repeat; @@ -31,6 +31,8 @@ pub struct FunctionContext<'a> { pub function: InternalFunctionReference<'a>, /// Execution-local external modules. pub externals: &'a HashMap>, + /// Function labels. + pub function_labels: HashMap, /// Function return type. pub return_type: BlockType, /// Local variables. @@ -52,8 +54,10 @@ pub enum InstructionOutcome<'a> { RunNextInstruction, /// Branch to given frame. Branch(usize), - /// Execute block. - ExecuteBlock, + /// Skip if-false (aka else) branch. + SkipIfFalse, + /// Run if-false (aka else) branch (if any). + RunIfFalse, /// Execute function call. ExecuteCall(InternalFunctionReference<'a>), /// End current frame. @@ -82,6 +86,8 @@ pub struct BlockFrame { /// Type of block frame. #[derive(Debug, Clone, Copy, PartialEq)] pub enum BlockFrameType { + /// Function frame. + Function, /// Usual block frame. Block, /// Loop frame (branching to the beginning of block). @@ -89,7 +95,7 @@ pub enum BlockFrameType { /// True-subblock of if expression. IfTrue, /// False-subblock of if expression. - IfElse, + IfFalse, } /// Function run result. @@ -112,10 +118,12 @@ impl Interpreter { let function_return = match function_body { Some(function_body) => { +println!("=== body: {:?}", function_body.body); +println!("=== labels: {:?}", function_context.function_labels); 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)?; + function_context.initialize(function_body.locals, function_body.labels.clone())?; + function_context.push_frame(BlockFrameType::Function, return_type)?; } Interpreter::do_run_function(&mut function_context, function_body.body)? @@ -150,88 +158,90 @@ impl Interpreter { } fn do_run_function<'a>(function_context: &mut FunctionContext<'a>, function_body: &[Opcode]) -> Result, Error> { - // 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) { - 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); - } - - let non_empty_stack_reason = "body_stack contains entry for every frame_stack; frame_stack is not empty; qed"; loop { - let block_result = Interpreter::run_block_instructions(function_context, body_stack.back().expect(non_empty_stack_reason))?; + let instruction = &function_body[function_context.position]; - match block_result { - InstructionOutcome::RunInstruction | InstructionOutcome::RunNextInstruction => unreachable!("managed by run_block_instructions"), + debug!(target: "interpreter", "running {:?}", instruction); +println!("running {:?} at {}", instruction, function_context.position); + match Interpreter::run_instruction(function_context, instruction)? { + InstructionOutcome::RunInstruction => (), + InstructionOutcome::RunNextInstruction => function_context.position += 1, InstructionOutcome::Branch(mut index) => { // 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()?), - BlockType::NoResult => None, - })); + break; } }, - InstructionOutcome::ExecuteBlock => { - function_context.position = 0; + InstructionOutcome::SkipIfFalse => { + // skip until else/end is found + let mut block_count = 1; + loop { + function_context.position += 1; + debug_assert!(function_context.position < function_body.len()); - let top_frame = function_context.frame_stack().top().expect(non_empty_stack_reason); - let instruction = &body_stack.back().expect(non_empty_stack_reason)[top_frame.begin_position]; - let block_body = Interpreter::into_block(instruction, top_frame.frame_type)?; - body_stack.push_back(block_body); + let instruction = &function_body[function_context.position]; + match instruction { + &Opcode::End if block_count == 1 => break, + &Opcode::Block(_) | &Opcode::Loop(_) | &Opcode::If(_) => block_count += 1, + &Opcode::End => block_count -= 1, + _ => (), + } + } + function_context.position += 1; }, - InstructionOutcome::ExecuteCall(func_ref) => return Ok(RunResult::NestedCall(function_context.nested(func_ref)?)), - InstructionOutcome::End if !function_context.frame_stack().is_empty() => { - assert!(body_stack.pop_back().is_some()); + InstructionOutcome::RunIfFalse => { + // skip until else/end is found + let mut block_count = 1; + loop { + function_context.position += 1; + debug_assert!(function_context.position < function_body.len()); + + let instruction = &function_body[function_context.position]; + match instruction { + &Opcode::End | &Opcode::Else if block_count == 1 => break, + &Opcode::Block(_) | &Opcode::Loop(_) | &Opcode::If(_) => block_count += 1, + &Opcode::End => block_count -= 1, + _ => (), + } + } + function_context.position += 1; }, - 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, 'b>(context: &'b mut FunctionContext<'a>, body: &[Opcode]) -> Result, Error> { - loop { - let instruction = &body[context.position]; - - debug!(target: "interpreter", "running {:?}", instruction); - match Interpreter::run_instruction(context, instruction)? { - InstructionOutcome::RunInstruction => (), - InstructionOutcome::RunNextInstruction => context.position += 1, - InstructionOutcome::Branch(index) => return Ok(InstructionOutcome::Branch(index)), - InstructionOutcome::ExecuteBlock => return Ok(InstructionOutcome::ExecuteBlock), InstructionOutcome::ExecuteCall(func_ref) => { - context.position += 1; - return Ok(InstructionOutcome::ExecuteCall(func_ref)); + function_context.position += 1; + return Ok(RunResult::NestedCall(function_context.nested(func_ref)?)); }, InstructionOutcome::End => { - context.pop_frame(false)?; - return Ok(InstructionOutcome::End); + if function_context.frame_stack().is_empty() { + break; + } + + //function_context.position += 1; }, - InstructionOutcome::Return => return Ok(InstructionOutcome::Return), + InstructionOutcome::Return => break, } +//println!("=== {:?}", function_context.frame_stack().len()); } + + Ok(RunResult::Return(match function_context.return_type { + BlockType::Value(_) => Some(function_context.value_stack_mut().pop()?), + BlockType::NoResult => None, + })) } 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), - &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::Block(block_type) => Interpreter::run_block(context, block_type), + &Opcode::Loop(block_type) => Interpreter::run_loop(context, block_type), + &Opcode::If(block_type) => Interpreter::run_if(context, block_type), &Opcode::Else => Interpreter::run_else(context), &Opcode::End => Interpreter::run_end(context), &Opcode::Br(idx) => Interpreter::run_br(context, idx), @@ -419,26 +429,6 @@ impl Interpreter { } } - fn into_block(opcode: &Opcode, frame_type: BlockFrameType) -> Result<&[Opcode], Error> { - match opcode { - &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], 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 frame_type == BlockFrameType::IfTrue { - (0, else_index + 1) - } else { - (else_index + 1, body_len) - }; - &body[begin_index..end_index] - } - fn run_unreachable<'a>(_context: &mut FunctionContext) -> Result, Error> { Err(Error::Trap("programmatic".into())) } @@ -448,36 +438,46 @@ impl Interpreter { } 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) + context.push_frame(BlockFrameType::Block, block_type)?; + Ok(InstructionOutcome::RunNextInstruction) } 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) + context.push_frame(BlockFrameType::Loop, block_type)?; + Ok(InstructionOutcome::RunNextInstruction) } - fn run_if<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType, body: &[Opcode]) -> Result, Error> { + fn run_if<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType) -> Result, Error> { let branch = context.value_stack_mut().pop_as()?; - let block_frame_type = if branch { BlockFrameType::IfTrue } else { BlockFrameType::IfElse }; - let branch_body = Interpreter::separate_if(body, block_frame_type); + let block_frame_type = if branch { BlockFrameType::IfTrue } else { +//println!("=== position = {}", context.position); + let else_pos = context.function_labels[&context.position]; +//println!("=== else_pos = {}", else_pos); +//println!("=== labels[else_pos] = {:?}", context.function_labels.get(&else_pos)); + if !context.function_labels.contains_key(&else_pos) { + context.position = else_pos; + return Ok(InstructionOutcome::RunNextInstruction); + } - if branch_body.len() != 0 { - 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 { + context.position = else_pos; + BlockFrameType::IfFalse + }; + context.push_frame(block_frame_type, block_type)?; + + //if branch { Ok(InstructionOutcome::RunNextInstruction) - } + /*} else { + Ok(InstructionOutcome::RunIfFalse) + }*/ } - fn run_else<'a>(_context: &mut FunctionContext) -> Result, Error> { - Ok(InstructionOutcome::End) + fn run_else<'a>(context: &mut FunctionContext) -> Result, Error> { + context.pop_frame(false)?; + Ok(InstructionOutcome::SkipIfFalse) } - fn run_end<'a>(_context: &mut FunctionContext) -> Result, Error> { + fn run_end<'a>(context: &mut FunctionContext) -> Result, Error> { + context.pop_frame(false)?; Ok(InstructionOutcome::End) } @@ -1017,11 +1017,12 @@ impl Interpreter { } impl<'a> FunctionContext<'a> { - pub fn new(function: InternalFunctionReference<'a>, externals: &'a HashMap>, value_stack_limit: usize, frame_stack_limit: usize, function_type: &FunctionType, args: Vec) -> Self { + pub fn new(function: InternalFunctionReference<'a>, externals: &'a HashMap>, function_labels: HashMap, value_stack_limit: usize, frame_stack_limit: usize, function_type: &FunctionType, args: Vec) -> Self { FunctionContext { is_initialized: false, function: function, externals: externals, + function_labels: function_labels, 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), @@ -1039,6 +1040,7 @@ impl<'a> FunctionContext<'a> { is_initialized: false, function: function, externals: self.externals, + function_labels: HashMap::new(), 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()), @@ -1051,7 +1053,7 @@ impl<'a> FunctionContext<'a> { self.is_initialized } - pub fn initialize(&mut self, locals: &[Local]) -> Result<(), Error> { + pub fn initialize(&mut self, locals: &[Local], labels: HashMap) -> Result<(), Error> { debug_assert!(!self.is_initialized); self.is_initialized = true; @@ -1060,6 +1062,7 @@ impl<'a> FunctionContext<'a> { .map(|vt| VariableInstance::new(true, vt, RuntimeValue::default(vt))) .collect::, _>>()?; self.locals.extend(locals); + self.function_labels = labels; Ok(()) } @@ -1100,7 +1103,24 @@ impl<'a> FunctionContext<'a> { &mut self.frame_stack } - pub fn push_frame(&mut self, frame_type: BlockFrameType, begin_position: usize, branch_position: usize, end_position: usize, signature: BlockType) -> Result<(), Error> { + pub fn push_frame(&mut self, frame_type: BlockFrameType, signature: BlockType) -> Result<(), Error> { + let begin_position = self.position; + let branch_position = match frame_type { + BlockFrameType::Function => usize::MAX, + BlockFrameType::Loop => begin_position, + BlockFrameType::IfTrue => { + let else_pos = self.function_labels[&begin_position]; + 1usize + match self.function_labels.get(&else_pos) { + Some(end_pos) => *end_pos, + None => else_pos, + } + }, + _ => self.function_labels[&begin_position] + 1, + }; + let end_position = match frame_type { + BlockFrameType::Function => usize::MAX, + _ => self.function_labels[&begin_position] + 1, + }; self.frame_stack.push(BlockFrame { frame_type: frame_type, begin_position: begin_position, @@ -1128,6 +1148,7 @@ impl<'a> FunctionContext<'a> { }; self.value_stack.resize(frame.value_limit, RuntimeValue::I32(0)); self.position = if is_branch { frame.branch_position } else { frame.end_position }; +//println!("=== pop_frame: position = {}", self.position); if let Some(frame_value) = frame_value { self.value_stack.push(frame_value)?; } diff --git a/src/interpreter/stack.rs b/src/interpreter/stack.rs index 78d1093..3acfa86 100644 --- a/src/interpreter/stack.rs +++ b/src/interpreter/stack.rs @@ -46,12 +46,14 @@ impl StackWithLimit where T: Clone { self.values .back() .ok_or(Error::Stack("non-empty stack expected".into())) +.map_err(|_| 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(|_| panic!("2")) } pub fn get(&self, index: usize) -> Result<&T, Error> { @@ -88,6 +90,7 @@ impl StackWithLimit where T: Clone { self.values .pop_back() .ok_or(Error::Stack("non-empty stack expected".into())) +.map_err(|_| panic!("3")) } pub fn resize(&mut self, new_size: usize, dummy: T) { diff --git a/src/interpreter/tests/basics.rs b/src/interpreter/tests/basics.rs index d253197..0a89392 100644 --- a/src/interpreter/tests/basics.rs +++ b/src/interpreter/tests/basics.rs @@ -82,7 +82,6 @@ fn wrong_import() { fn global_get_set() { let module = module() .with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, true), InitExpr::new(vec![Opcode::I32Const(42)]))) - .with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const(777)]))) .function() .signature().return_type().i32().build() .body().with_opcodes(Opcodes::new(vec![ @@ -94,33 +93,11 @@ fn global_get_set() { Opcode::End, ])).build() .build() - .function() - .signature().return_type().i32().build() - .body().with_opcodes(Opcodes::new(vec![ - Opcode::GetGlobal(1), - Opcode::I32Const(8), - Opcode::I32Add, - Opcode::SetGlobal(1), - Opcode::GetGlobal(1), - Opcode::End, - ])).build() - .build() - .function() - .signature().return_type().i32().build() - .body().with_opcodes(Opcodes::new(vec![ - Opcode::I64Const(8), - Opcode::SetGlobal(0), - Opcode::GetGlobal(0), - Opcode::End, - ])).build() - .build() .build(); let program = ProgramInstance::new().unwrap(); - let module = program.add_module_without_validation("main", module, None).unwrap(); // validation is failing (accessing immutable global) + let module = program.add_module("main", module, None).unwrap(); assert_eq!(module.execute_index(0, vec![].into()).unwrap().unwrap(), RuntimeValue::I32(50)); - assert_eq!(module.execute_index(1, vec![].into()).unwrap_err(), Error::Variable("trying to update immutable variable".into())); - assert_eq!(module.execute_index(2, vec![].into()).unwrap_err(), Error::Variable("trying to update variable of type I32 with value of type Some(I64)".into())); } const SIGNATURE_I32: &'static [ValueType] = &[ValueType::I32]; @@ -255,17 +232,15 @@ fn if_else_with_return_type_validation() { Validator::validate_function(&mut context, BlockType::NoResult, &[ Opcode::I32Const(1), - Opcode::If(BlockType::NoResult, Opcodes::new(vec![ + Opcode::If(BlockType::NoResult), Opcode::I32Const(1), - Opcode::If(BlockType::Value(ValueType::I32), Opcodes::new(vec![ + Opcode::If(BlockType::Value(ValueType::I32)), Opcode::I32Const(1), - Opcode::Else, + Opcode::Else, Opcode::I32Const(2), - Opcode::End, - ])), - Opcode::Drop, Opcode::End, - ])), + Opcode::Drop, + Opcode::End, Opcode::End, ]).unwrap(); } diff --git a/src/interpreter/tests/wabt.rs b/src/interpreter/tests/wabt.rs index f7fec05..1244c74 100644 --- a/src/interpreter/tests/wabt.rs +++ b/src/interpreter/tests/wabt.rs @@ -55,13 +55,11 @@ fn nop() { #[test] fn expr_block() { let (_program, module) = make_function_i32(Opcodes::new(vec![ - Opcode::Block(BlockType::Value(ValueType::I32), // mark block - Opcodes::new(vec![ - Opcode::I32Const(10), // [10] - Opcode::Drop, - Opcode::I32Const(1), // [1] - Opcode::End, - ])), + Opcode::Block(BlockType::Value(ValueType::I32)), + Opcode::I32Const(10), // [10] + Opcode::Drop, + Opcode::I32Const(1), // [1] + Opcode::End, Opcode::End])); assert_eq!(run_function_i32(&module, 0).unwrap(), 1); @@ -71,26 +69,23 @@ fn expr_block() { #[test] fn loop_test() { let (_program, module) = make_function_i32(Opcodes::new(vec![ - Opcode::Loop(BlockType::NoResult, // loop - Opcodes::new(vec![ - Opcode::GetLocal(1), // [local1] - Opcode::GetLocal(0), // [local1, arg] - Opcode::I32Add, // [arg + local1] - Opcode::SetLocal(1), // [] + local1 = arg + local1 - Opcode::GetLocal(0), // [arg] - Opcode::I32Const(1), // [arg, 1] - Opcode::I32Add, // [arg + 1] - Opcode::SetLocal(0), // [] + arg = arg + 1 - Opcode::GetLocal(0), // [arg] - Opcode::I32Const(5), // [arg, 5] - Opcode::I32LtS, // [arg < 5] - Opcode::If(BlockType::NoResult, - Opcodes::new(vec![ - Opcode::Br(1), // break loop - Opcode::End, - ])), - Opcode::End])), // end loop - Opcode::GetLocal(1), // [local1] + Opcode::Loop(BlockType::NoResult), // loop + Opcode::GetLocal(1), // [local1] + Opcode::GetLocal(0), // [local1, arg] + Opcode::I32Add, // [arg + local1] + Opcode::SetLocal(1), // [] + local1 = arg + local1 + Opcode::GetLocal(0), // [arg] + Opcode::I32Const(1), // [arg, 1] + Opcode::I32Add, // [arg + 1] + Opcode::SetLocal(0), // [] + arg = arg + 1 + Opcode::GetLocal(0), // [arg] + Opcode::I32Const(5), // [arg, 5] + Opcode::I32LtS, // [arg < 5] + Opcode::If(BlockType::NoResult), + Opcode::Br(1), // break loop + Opcode::End, + Opcode::End, // end loop + Opcode::GetLocal(1), // [local1] Opcode::End])); assert_eq!(run_function_i32(&module, 0).unwrap(), 10); @@ -103,23 +98,19 @@ fn if_1() { Opcode::I32Const(0), // [0] Opcode::SetLocal(0), // [] + arg = 0 Opcode::I32Const(1), // [1] - Opcode::If(BlockType::NoResult, // if 1 - Opcodes::new(vec![ - Opcode::GetLocal(0), // [arg] - Opcode::I32Const(1), // [arg, 1] - Opcode::I32Add, // [arg + 1] - Opcode::SetLocal(0), // [] + arg = arg + 1 - Opcode::End, // end if - ])), + Opcode::If(BlockType::NoResult), // if 1 + Opcode::GetLocal(0), // [arg] + Opcode::I32Const(1), // [arg, 1] + Opcode::I32Add, // [arg + 1] + Opcode::SetLocal(0), // [] + arg = arg + 1 + Opcode::End, // end if Opcode::I32Const(0), // [0] - Opcode::If(BlockType::NoResult, // if 0 - Opcodes::new(vec![ - Opcode::GetLocal(0), // [arg] - Opcode::I32Const(1), // [arg, 1] - Opcode::I32Add, // [arg + 1] - Opcode::SetLocal(0), // [] + arg = arg + 1 - Opcode::End, // end if - ])), + Opcode::If(BlockType::NoResult), // if 0 + Opcode::GetLocal(0), // [arg] + Opcode::I32Const(1), // [arg, 1] + Opcode::I32Add, // [arg + 1] + Opcode::SetLocal(0), // [] + arg = arg + 1 + Opcode::End, // end if Opcode::GetLocal(0), // [arg] Opcode::End])); @@ -131,25 +122,21 @@ fn if_1() { fn if_2() { let (_program, module) = make_function_i32(Opcodes::new(vec![ Opcode::I32Const(1), // [1] - Opcode::If(BlockType::NoResult, // if 1 - Opcodes::new(vec![ - Opcode::I32Const(1), // [1] - Opcode::SetLocal(0), // [] + arg = 1 - Opcode::Else, // else - Opcode::I32Const(2), // [2] - Opcode::SetLocal(0), // [] + arg = 2 - Opcode::End, // end if - ])), + Opcode::If(BlockType::NoResult), // if 1 + Opcode::I32Const(1), // [1] + Opcode::SetLocal(0), // [] + arg = 1 + Opcode::Else, // else + Opcode::I32Const(2), // [2] + Opcode::SetLocal(0), // [] + arg = 2 + Opcode::End, // end if Opcode::I32Const(0), // [0] - Opcode::If(BlockType::NoResult, // if 0 - Opcodes::new(vec![ - Opcode::I32Const(4), // [4] - Opcode::SetLocal(1), // [] + local1 = 4 - Opcode::Else, // else - Opcode::I32Const(8), // [8] - Opcode::SetLocal(1), // [] + local1 = 8 - Opcode::End, // end if - ])), + Opcode::If(BlockType::NoResult), // if 0 + Opcode::I32Const(4), // [4] + Opcode::SetLocal(1), // [] + local1 = 4 + Opcode::Else, // else + Opcode::I32Const(8), // [8] + Opcode::SetLocal(1), // [] + local1 = 8 + Opcode::End, // end if Opcode::GetLocal(0), // [arg] Opcode::GetLocal(1), // [arg, local1] Opcode::I32Add, // [arg + local1] @@ -165,13 +152,11 @@ fn expr_if() { Opcode::GetLocal(0), // [arg] Opcode::I32Const(0), // [arg, 0] Opcode::I32Eq, // [arg == 0] - Opcode::If(BlockType::Value(ValueType::I32), // if arg == 0 - Opcodes::new(vec![ - Opcode::I32Const(1), // [1] - Opcode::Else, // else - Opcode::I32Const(2), // [2] - Opcode::End, // end if - ])), + Opcode::If(BlockType::Value(ValueType::I32)), // if arg == 0 + Opcode::I32Const(1), // [1] + Opcode::Else, // else + Opcode::I32Const(2), // [2] + Opcode::End, // end if Opcode::End])); assert_eq!(run_function_i32(&module, 0).unwrap(), 1); @@ -182,23 +167,17 @@ fn expr_if() { #[test] fn nested_if() { let (_program, module) = make_function_i32(Opcodes::new(vec![ - Opcode::Block(BlockType::NoResult, - Opcodes::new(vec![ - Opcode::I32Const(1), - Opcode::If(BlockType::NoResult, - Opcodes::new(vec![ - Opcode::I32Const(2), - Opcode::Drop, - Opcode::I32Const(3), - Opcode::If(BlockType::NoResult, - Opcodes::new(vec![ - Opcode::Br(2), - Opcode::End, - ])), - Opcode::End, - ])), + Opcode::Block(BlockType::NoResult), + Opcode::I32Const(1), + Opcode::If(BlockType::NoResult), + Opcode::I32Const(2), + Opcode::Drop, + Opcode::I32Const(3), + Opcode::If(BlockType::NoResult), + Opcode::Br(2), Opcode::End, - ])), + Opcode::End, + Opcode::End, Opcode::I32Const(4), Opcode::End])); @@ -209,18 +188,14 @@ fn nested_if() { #[test] fn br_0() { let (_program, module) = make_function_i32(Opcodes::new(vec![ - Opcode::Block(BlockType::NoResult, // mark block - Opcodes::new(vec![ - Opcode::I32Const(1), // [1] - Opcode::If(BlockType::NoResult, // if 1 - Opcodes::new(vec![ - Opcode::Br(1), // break from block - Opcode::End, // end if - ])), - Opcode::I32Const(1), // [1] - Opcode::SetLocal(0), // [] + arg = 1 - Opcode::End, // end block - ])), + Opcode::Block(BlockType::NoResult), // mark block + Opcode::I32Const(1), // [1] + Opcode::If(BlockType::NoResult), // if 1 + Opcode::Br(1), // break from block + Opcode::End, // end if + Opcode::I32Const(1), // [1] + Opcode::SetLocal(0), // [] + arg = 1 + Opcode::End, // end block Opcode::I32Const(1), // [1] Opcode::SetLocal(1), // [] + local1 = 1 Opcode::GetLocal(0), // [arg] @@ -239,24 +214,18 @@ fn br_0() { #[test] fn br_1() { let (_program, module) = make_function_i32(Opcodes::new(vec![ - Opcode::Block(BlockType::NoResult, // block1 - Opcodes::new(vec![ - Opcode::Block(BlockType::NoResult, // block2 - Opcodes::new(vec![ - Opcode::I32Const(1), // [1] - Opcode::If(BlockType::NoResult, // if 1 - Opcodes::new(vec![ - Opcode::Br(2), // break from block2 - Opcode::End, // end if - ])), - Opcode::I32Const(1), // [1] - Opcode::SetLocal(0), // [] + arg = 1 - Opcode::End, // end (block2) - ])), - Opcode::I32Const(1), // [1] - Opcode::SetLocal(1), // [] + local1 = 1 - Opcode::End, // end (block1) - ])), + Opcode::Block(BlockType::NoResult), // block1 + Opcode::Block(BlockType::NoResult), // block2 + Opcode::I32Const(1), // [1] + Opcode::If(BlockType::NoResult), // if 1 + Opcode::Br(2), // break from block2 + Opcode::End, // end if + Opcode::I32Const(1), // [1] + Opcode::SetLocal(0), // [] + arg = 1 + Opcode::End, // end (block2) + Opcode::I32Const(1), // [1] + Opcode::SetLocal(1), // [] + local1 = 1 + Opcode::End, // end (block1) Opcode::I32Const(1), // [1] Opcode::SetLocal(2), // [] + local2 = 1 Opcode::GetLocal(0), // [arg] @@ -279,22 +248,16 @@ fn br_1() { #[test] fn br_2() { let (_program, module) = make_function_i32(Opcodes::new(vec![ - Opcode::Block(BlockType::NoResult, // block1 - Opcodes::new(vec![ - Opcode::Block(BlockType::NoResult, // block2 - Opcodes::new(vec![ - Opcode::I32Const(1), // [1] - Opcode::If(BlockType::NoResult, // if 1 - Opcodes::new(vec![ - Opcode::Br(2), // break from block2 - Opcode::End, // end if - ])), - Opcode::I32Const(1), // [1] - Opcode::Return, // return 1 - Opcode::End, // end (block2) - ])), - Opcode::End, // end (block1) - ])), + Opcode::Block(BlockType::NoResult), // block1 + Opcode::Block(BlockType::NoResult), // block2 + Opcode::I32Const(1), // [1] + Opcode::If(BlockType::NoResult), // if 1 + Opcode::Br(2), // break from block2 + Opcode::End, // end if + Opcode::I32Const(1), // [1] + Opcode::Return, // return 1 + Opcode::End, // end (block2) + Opcode::End, // end (block1) Opcode::I32Const(2), // [2] Opcode::Return, // return 2 Opcode::End])); @@ -306,37 +269,29 @@ fn br_2() { #[test] fn br_3() { let (_program, module) = make_function_i32(Opcodes::new(vec![ - Opcode::Block(BlockType::NoResult, // block1 - Opcodes::new(vec![ - Opcode::Loop(BlockType::NoResult, // loop - Opcodes::new(vec![ - Opcode::GetLocal(0), // [arg] - Opcode::I32Const(1), // [arg, 1] - Opcode::I32Add, // [arg + 1] - Opcode::SetLocal(0), // [] + arg = arg + 1 - Opcode::GetLocal(0), // [arg] - Opcode::I32Const(5), // [arg, 5] - Opcode::I32GeS, // [5 >= arg] - Opcode::If(BlockType::NoResult, // if 5 >= arg - Opcodes::new(vec![ - Opcode::Br(2), // break from block1 - Opcode::End, // end - ])), - Opcode::GetLocal(0), // [arg] - Opcode::I32Const(4), // [arg, 4] - Opcode::I32Eq, // [arg == 4] - Opcode::If(BlockType::NoResult, // if arg == 4 - Opcodes::new(vec![ - Opcode::Br(1), // break from loop - Opcode::End, // end - ])), - Opcode::GetLocal(0), // [arg] - Opcode::SetLocal(1), // [] + local1 = arg - Opcode::Br(0), // continue loop - Opcode::End, // end (loop) - ])), - Opcode::End, // end (block1) - ])), + Opcode::Block(BlockType::NoResult), // block1 + Opcode::Loop(BlockType::NoResult), // loop + Opcode::GetLocal(0), // [arg] + Opcode::I32Const(1), // [arg, 1] + Opcode::I32Add, // [arg + 1] + Opcode::SetLocal(0), // [] + arg = arg + 1 + Opcode::GetLocal(0), // [arg] + Opcode::I32Const(5), // [arg, 5] + Opcode::I32GeS, // [5 >= arg] + Opcode::If(BlockType::NoResult), // if 5 >= arg + Opcode::Br(2), // break from block1 + Opcode::End, // end + Opcode::GetLocal(0), // [arg] + Opcode::I32Const(4), // [arg, 4] + Opcode::I32Eq, // [arg == 4] + Opcode::If(BlockType::NoResult), // if arg == 4 + Opcode::Br(1), // break from loop + Opcode::End, // end + Opcode::GetLocal(0), // [arg] + Opcode::SetLocal(1), // [] + local1 = arg + Opcode::Br(0), // continue loop + Opcode::End, // end (loop) + Opcode::End, // end (block1) Opcode::GetLocal(1), // [local1] Opcode::Return, // return local1 Opcode::End])); @@ -348,20 +303,16 @@ fn br_3() { #[test] fn expr_br() { let (_program, module) = make_function_i32(Opcodes::new(vec![ - Opcode::Block(BlockType::Value(ValueType::I32), // block1 - Opcodes::new(vec![ - Opcode::GetLocal(0), // [arg] - Opcode::I32Const(0), // [arg, 0] - Opcode::I32Eq, // [arg == 0] - Opcode::If(BlockType::NoResult, // if arg == 0 - Opcodes::new(vec![ - Opcode::I32Const(1), // [1] - Opcode::Br(1), // break from block1 - Opcode::End, // end (if) - ])), - Opcode::I32Const(2), // [2] - Opcode::End, // end (block1) - ])), + Opcode::Block(BlockType::Value(ValueType::I32)), // block1 + Opcode::GetLocal(0), // [arg] + Opcode::I32Const(0), // [arg, 0] + Opcode::I32Eq, // [arg == 0] + Opcode::If(BlockType::NoResult), // if arg == 0 + Opcode::I32Const(1), // [1] + Opcode::Br(1), // break from block1 + Opcode::End, // end (if) + Opcode::I32Const(2), // [2] + Opcode::End, // end (block1) Opcode::End])); assert_eq!(run_function_i32(&module, 0).unwrap(), 1); @@ -372,14 +323,12 @@ fn expr_br() { #[test] fn brif() { let (_program, module) = make_function_i32(Opcodes::new(vec![ - Opcode::Block(BlockType::NoResult, // block1 - Opcodes::new(vec![ - Opcode::GetLocal(0), // [arg] - Opcode::BrIf(0), // if arg != 0: break from block1 - Opcode::I32Const(1), // [1] - Opcode::Return, // return 1 - Opcode::End, // end (block1) - ])), + Opcode::Block(BlockType::NoResult), // block1 + Opcode::GetLocal(0), // [arg] + Opcode::BrIf(0), // if arg != 0: break from block1 + Opcode::I32Const(1), // [1] + Opcode::Return, // return 1 + Opcode::End, // end (block1) Opcode::I32Const(2), // [2] Opcode::Return, // return 2 Opcode::End])); @@ -392,18 +341,16 @@ fn brif() { #[test] fn brif_loop() { let (_program, module) = make_function_i32(Opcodes::new(vec![ - Opcode::Loop(BlockType::NoResult, // loop - Opcodes::new(vec![ - Opcode::GetLocal(1), // [local1] - Opcode::I32Const(1), // [local1, 1] - Opcode::I32Add, // [local1 + 1] - Opcode::SetLocal(1), // [] + local1 = local1 + 1 - Opcode::GetLocal(1), // [local1] - Opcode::GetLocal(0), // [local1, arg] - Opcode::I32LtS, // [local1 < arg] - Opcode::BrIf(0), // break loop if local1 < arg - Opcode::End, // end (loop) - ])), + Opcode::Loop(BlockType::NoResult), // loop + Opcode::GetLocal(1), // [local1] + Opcode::I32Const(1), // [local1, 1] + Opcode::I32Add, // [local1 + 1] + Opcode::SetLocal(1), // [] + local1 = local1 + 1 + Opcode::GetLocal(1), // [local1] + Opcode::GetLocal(0), // [local1, arg] + Opcode::I32LtS, // [local1 < arg] + Opcode::BrIf(0), // break loop if local1 < arg + Opcode::End, // end (loop) Opcode::GetLocal(1), // [local1] Opcode::Return, // return Opcode::End])); @@ -416,18 +363,16 @@ fn brif_loop() { #[test] fn expr_brif() { let (_program, module) = make_function_i32(Opcodes::new(vec![ - Opcode::Loop(BlockType::NoResult, // loop - Opcodes::new(vec![ - Opcode::GetLocal(1), // [local1] - Opcode::I32Const(1), // [local1, 1] - Opcode::I32Add, // [local1 + 1] - Opcode::SetLocal(1), // [] + local1 = local1 + 1 - Opcode::GetLocal(1), // [local1] - Opcode::GetLocal(0), // [local1, local0] - Opcode::I32LtS, // [local1 < local0] - Opcode::BrIf(0), // if local1 < local0: break from loop - Opcode::End, // end (loop) - ])), + Opcode::Loop(BlockType::NoResult), // loop + Opcode::GetLocal(1), // [local1] + Opcode::I32Const(1), // [local1, 1] + Opcode::I32Add, // [local1 + 1] + Opcode::SetLocal(1), // [] + local1 = local1 + 1 + Opcode::GetLocal(1), // [local1] + Opcode::GetLocal(0), // [local1, local0] + Opcode::I32LtS, // [local1 < local0] + Opcode::BrIf(0), // if local1 < local0: break from loop + Opcode::End, // end (loop) Opcode::GetLocal(1), // [local1] Opcode::End])); @@ -439,30 +384,22 @@ fn expr_brif() { #[test] fn brtable() { let (_program, module) = make_function_i32(Opcodes::new(vec![ - Opcode::Block(BlockType::NoResult, // block3 - Opcodes::new(vec![ - Opcode::Block(BlockType::NoResult, // block2 - Opcodes::new(vec![ - Opcode::Block(BlockType::NoResult, // block1 - Opcodes::new(vec![ - Opcode::Block(BlockType::NoResult, // block0 - Opcodes::new(vec![ - Opcode::GetLocal(0), // [arg] - Opcode::BrTable(vec![0, 1, 2], 3), // br_table - Opcode::End, // end (block0) - ])), - Opcode::I32Const(0), // [0] - Opcode::Return, // return 0 - Opcode::End, // end (block1) - ])), - Opcode::I32Const(1), // [1] - Opcode::Return, // return 1 - Opcode::End, // end (block2) - ])), - Opcode::End, // end (block3) - ])), - Opcode::I32Const(2), // [2] - Opcode::Return, // return 2 + Opcode::Block(BlockType::NoResult), // block3 + Opcode::Block(BlockType::NoResult), // block2 + Opcode::Block(BlockType::NoResult), // block1 + Opcode::Block(BlockType::NoResult), // block0 + Opcode::GetLocal(0), // [arg] + Opcode::BrTable(vec![0, 1, 2], 3), // br_table + Opcode::End, // end (block0) + Opcode::I32Const(0), // [0] + Opcode::Return, // return 0 + Opcode::End, // end (block1) + Opcode::I32Const(1), // [1] + Opcode::Return, // return 1 + Opcode::End, // end (block2) + Opcode::End, // end (block3) + Opcode::I32Const(2), // [2] + Opcode::Return, // return 2 Opcode::End])); assert_eq!(run_function_i32(&module, 0).unwrap(), 0); @@ -478,21 +415,17 @@ fn return_test() { Opcode::GetLocal(0), Opcode::I32Const(0), Opcode::I32Eq, - Opcode::If(BlockType::NoResult, - Opcodes::new(vec![ - Opcode::I32Const(1), - Opcode::Return, - Opcode::End, - ])), + Opcode::If(BlockType::NoResult), + Opcode::I32Const(1), + Opcode::Return, + Opcode::End, Opcode::GetLocal(0), Opcode::I32Const(1), Opcode::I32Eq, - Opcode::If(BlockType::NoResult, - Opcodes::new(vec![ - Opcode::I32Const(2), - Opcode::Return, - Opcode::End, - ])), + Opcode::If(BlockType::NoResult), + Opcode::I32Const(2), + Opcode::Return, + Opcode::End, Opcode::I32Const(3), Opcode::Return, Opcode::End])); @@ -509,11 +442,9 @@ fn return_void() { Opcode::GetLocal(0), Opcode::I32Const(0), Opcode::I32Eq, - Opcode::If(BlockType::NoResult, - Opcodes::new(vec![ - Opcode::Return, - Opcode::End, - ])), + Opcode::If(BlockType::NoResult), + Opcode::Return, + Opcode::End, Opcode::I32Const(0), Opcode::I32Const(1), Opcode::I32Store(2, 0), @@ -604,20 +535,18 @@ fn call_2() { Opcode::GetLocal(0), Opcode::I32Const(0), Opcode::I32GtS, - Opcode::If(BlockType::Value(ValueType::I32), - Opcodes::new(vec![ - Opcode::GetLocal(0), - Opcode::GetLocal(0), - Opcode::I32Const(1), - Opcode::I32Sub, - Opcode::Call(1), - Opcode::I32Mul, - Opcode::Return, - Opcode::Else, - Opcode::I32Const(1), - Opcode::Return, - Opcode::End, - ])), + Opcode::If(BlockType::Value(ValueType::I32)), + Opcode::GetLocal(0), + Opcode::GetLocal(0), + Opcode::I32Const(1), + Opcode::I32Sub, + Opcode::Call(1), + Opcode::I32Mul, + Opcode::Return, + Opcode::Else, + Opcode::I32Const(1), + Opcode::Return, + Opcode::End, Opcode::End, ]); diff --git a/src/interpreter/validator.rs b/src/interpreter/validator.rs index c1faad0..ab06215 100644 --- a/src/interpreter/validator.rs +++ b/src/interpreter/validator.rs @@ -1,5 +1,5 @@ use std::u32; -use std::collections::VecDeque; +use std::collections::{HashMap, VecDeque}; use elements::{Module, Opcode, BlockType, FunctionType, ValueType, External, Type}; use interpreter::Error; use interpreter::runner::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; @@ -8,6 +8,8 @@ use interpreter::module::ItemIndex; use interpreter::stack::StackWithLimit; use interpreter::variable::VariableType; +use interpreter::runner::BlockFrameType; + /// Constant from wabt' validator.cc to skip alignment validation (not a part of spec). const NATURAL_ALIGNMENT: u32 = 0xFFFFFFFF; @@ -17,6 +19,8 @@ pub struct FunctionValidationContext<'a> { module: &'a Module, /// Module imports. imports: &'a ModuleImports, + /// Position. + position: usize, /// Local variables. locals: &'a [ValueType], /// Value stack. @@ -25,6 +29,8 @@ pub struct FunctionValidationContext<'a> { frame_stack: StackWithLimit, /// Function return type. None if validating expression. return_type: Option, + /// Labels positions. + labels: HashMap, } /// Value type on the stack. @@ -41,12 +47,14 @@ pub enum StackValueType { /// Function validation frame. #[derive(Debug, Clone)] pub struct ValidationFrame { - /// Is loop frame? - pub is_loop: bool, + /// Frame type + pub frame_type: BlockFrameType, /// Return type. pub block_type: BlockType, /// Value stack len. pub value_stack_len: usize, + /// Frame instruction position. + pub position: usize, } /// Function validator. @@ -54,65 +62,48 @@ pub struct Validator; /// Instruction outcome. #[derive(Debug, Clone)] -pub enum InstructionOutcome<'a> { +pub enum InstructionOutcome { /// Continue with next instruction. ValidateNextInstruction, /// Unreachable instruction reached. Unreachable, /// Validate block. - ValidateBlock(bool, BlockType, &'a [Opcode]), - /// Validate 2 blocks. - ValidateBlock2(bool, BlockType, &'a [Opcode], &'a [Opcode]), + ValidateBlock(BlockFrameType, BlockType), } impl Validator { 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)?; + context.push_label(BlockFrameType::Function, block_type)?; + Validator::validate_function_block(context, body)?; while !context.frame_stack.is_empty() { - context.pop_label()?; + context.pop_label(false)?; } Ok(()) } - fn validate_block<'a>(context: &mut FunctionValidationContext, mut body: &[Opcode]) -> Result, Error> { - let mut block_stack = VecDeque::new(); - let mut position = 0; + fn validate_function_block<'a>(context: &mut FunctionValidationContext, mut body: &[Opcode]) -> Result { 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; - }; + if context.position >= body.len() { + return Ok(InstructionOutcome::ValidateNextInstruction); + } + let opcode = &body[context.position]; match Validator::validate_instruction(context, opcode)? { - InstructionOutcome::ValidateNextInstruction => position += 1, + InstructionOutcome::ValidateNextInstruction => context.position += 1, InstructionOutcome::Unreachable => { context.unreachable()?; - position += 1; + context.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)); + InstructionOutcome::ValidateBlock(frame_type, block_type) => { + context.push_label(frame_type, block_type)?; + context.position += 1; + //block_stack.push_back((body, position + 1, false)); - body = new_body; - position = 0; + //body = new_body; + //position = 0; }, - InstructionOutcome::ValidateBlock2(is_loop, block_type, new_body, new_body2) => { + /*InstructionOutcome::ValidateBlock2(is_loop, block_type, new_body, new_body2) => { let need_pop_value = match block_type { BlockType::NoResult => false, BlockType::Value(_) => true, @@ -124,21 +115,22 @@ impl Validator { body = new_body; position = 0; - }, + },*/ } } } - pub fn validate_instruction<'a>(context: &mut FunctionValidationContext, opcode: &'a Opcode) -> Result, Error> { + pub fn validate_instruction<'a>(context: &mut FunctionValidationContext, opcode: &'a Opcode) -> Result { debug!(target: "validator", "validating {:?}", opcode); +println!("validating {:?} at {}, len: {}", opcode, context.position, context.value_stack.len()); match opcode { &Opcode::Unreachable => Ok(InstructionOutcome::Unreachable), &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::ValidateNextInstruction), - &Opcode::End => Ok(InstructionOutcome::ValidateNextInstruction), + &Opcode::Block(block_type) => Validator::validate_block(context, block_type), + &Opcode::Loop(block_type) => Validator::validate_loop(context, block_type), + &Opcode::If(block_type) => Validator::validate_if(context, block_type), + &Opcode::Else => Validator::validate_else(context), + &Opcode::End => Validator::validate_end(context), &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), @@ -324,49 +316,49 @@ impl Validator { } } - fn validate_const<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result, Error> { + fn validate_const<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { context.push_value(value_type)?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_unop<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result, Error> { + fn validate_unop<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { context.pop_value(value_type)?; context.push_value(value_type)?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_binop<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result, Error> { + fn validate_binop<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { context.pop_value(value_type)?; context.pop_value(value_type)?; context.push_value(value_type)?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_testop<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result, Error> { + fn validate_testop<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { context.pop_value(value_type)?; context.push_value(ValueType::I32.into())?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_relop<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result, Error> { + fn validate_relop<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { context.pop_value(value_type)?; context.pop_value(value_type)?; context.push_value(ValueType::I32.into())?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_cvtop<'a>(context: &mut FunctionValidationContext, value_type1: StackValueType, value_type2: StackValueType) -> Result, Error> { + fn validate_cvtop<'a>(context: &mut FunctionValidationContext, value_type1: StackValueType, value_type2: StackValueType) -> Result { context.pop_value(value_type1)?; context.push_value(value_type2)?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_drop<'a>(context: &mut FunctionValidationContext) -> Result, Error> { + fn validate_drop<'a>(context: &mut FunctionValidationContext) -> Result { context.pop_any_value().map(|_| ())?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_select<'a>(context: &mut FunctionValidationContext) -> Result, Error> { + fn validate_select<'a>(context: &mut FunctionValidationContext) -> Result { context.pop_value(ValueType::I32.into())?; let select_type = context.pop_any_value()?; context.pop_value(select_type)?; @@ -374,13 +366,13 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_get_local<'a>(context: &mut FunctionValidationContext, index: u32) -> Result, Error> { + fn validate_get_local<'a>(context: &mut FunctionValidationContext, index: u32) -> Result { let local_type = context.require_local(index)?; context.push_value(local_type)?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_set_local<'a>(context: &mut FunctionValidationContext, index: u32) -> Result, Error> { + fn validate_set_local<'a>(context: &mut FunctionValidationContext, index: u32) -> Result { let local_type = context.require_local(index)?; let value_type = context.pop_any_value()?; if local_type != value_type { @@ -389,7 +381,7 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_tee_local<'a>(context: &mut FunctionValidationContext, index: u32) -> Result, Error> { + fn validate_tee_local<'a>(context: &mut FunctionValidationContext, index: u32) -> Result { let local_type = context.require_local(index)?; let value_type = context.tee_any_value()?; if local_type != value_type { @@ -398,13 +390,13 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_get_global<'a>(context: &mut FunctionValidationContext, index: u32) -> Result, Error> { + fn validate_get_global<'a>(context: &mut FunctionValidationContext, index: u32) -> Result { let global_type = context.require_global(index, None)?; context.push_value(global_type)?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_set_global<'a>(context: &mut FunctionValidationContext, index: u32) -> Result, Error> { + fn validate_set_global<'a>(context: &mut FunctionValidationContext, index: u32) -> Result { let global_type = context.require_global(index, Some(true))?; let value_type = context.pop_any_value()?; if global_type != value_type { @@ -413,7 +405,7 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_load<'a>(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: StackValueType) -> Result, Error> { + fn validate_load<'a>(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: StackValueType) -> Result { 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))); @@ -426,7 +418,7 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_store<'a>(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: StackValueType) -> Result, Error> { + fn validate_store<'a>(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: StackValueType) -> Result { 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))); @@ -439,13 +431,18 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - 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_block<'a>(_context: &mut FunctionValidationContext, block_type: BlockType) -> Result { + Validator::schedule_validate_block(BlockFrameType::Block, block_type, Opcode::End) } - fn validate_if<'a>(context: &mut FunctionValidationContext, block_type: BlockType, body: &'a [Opcode]) -> Result, Error> { - context.pop_value(ValueType::I32.into())?; + fn validate_loop<'a>(_context: &mut FunctionValidationContext, block_type: BlockType) -> Result { + Validator::schedule_validate_block(BlockFrameType::Loop, block_type, Opcode::End) + } + fn validate_if<'a>(context: &mut FunctionValidationContext, block_type: BlockType) -> Result { + context.pop_value(ValueType::I32.into())?; + Validator::schedule_validate_block(BlockFrameType::IfTrue, block_type, Opcode::End) // TODO: else??? +/* let body_len = body.len(); let separator_index = body.iter() .position(|op| *op == Opcode::Else) @@ -458,16 +455,26 @@ impl Validator { } Validator::schedule_validate_block(false, block_type, body, Opcode::End) - } + }*/ } - fn validate_br<'a>(context: &mut FunctionValidationContext, idx: u32) -> Result, Error> { - let (frame_is_loop, frame_block_type) = { + fn validate_else(context: &mut FunctionValidationContext) -> Result { + context.pop_label(true)?; + Ok(InstructionOutcome::ValidateNextInstruction) + } + + fn validate_end(context: &mut FunctionValidationContext) -> Result { + context.pop_label(false)?; + Ok(InstructionOutcome::ValidateNextInstruction) + } + + fn validate_br<'a>(context: &mut FunctionValidationContext, idx: u32) -> Result { + let (frame_type, frame_block_type) = { let frame = context.require_label(idx)?; - (frame.is_loop, frame.block_type) + (frame.frame_type, frame.block_type) }; - if !frame_is_loop { + if frame_type != BlockFrameType::Loop { if let BlockType::Value(value_type) = frame_block_type { context.tee_value(value_type.into())?; } @@ -475,7 +482,7 @@ impl Validator { Ok(InstructionOutcome::Unreachable) } - fn validate_br_if<'a>(context: &mut FunctionValidationContext, idx: u32) -> Result, Error> { + fn validate_br_if<'a>(context: &mut FunctionValidationContext, idx: u32) -> Result { context.pop_value(ValueType::I32.into())?; if let BlockType::Value(value_type) = context.require_label(idx)?.block_type { context.tee_value(value_type.into())?; @@ -483,18 +490,18 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_br_table<'a>(context: &mut FunctionValidationContext, table: &Vec, default: u32) -> Result, Error> { + fn validate_br_table<'a>(context: &mut FunctionValidationContext, table: &Vec, default: u32) -> Result { let mut required_block_type = None; { let default_block = context.require_label(default)?; - if !default_block.is_loop { + if default_block.frame_type != BlockFrameType::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 label_block.frame_type != BlockFrameType::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))); @@ -515,14 +522,14 @@ impl Validator { Ok(InstructionOutcome::Unreachable) } - fn validate_return<'a>(context: &mut FunctionValidationContext) -> Result, Error> { + fn validate_return<'a>(context: &mut FunctionValidationContext) -> Result { if let BlockType::Value(value_type) = context.return_type()? { context.tee_value(value_type.into())?; } Ok(InstructionOutcome::Unreachable) } - fn validate_call<'a>(context: &mut FunctionValidationContext, idx: u32) -> Result, Error> { + fn validate_call<'a>(context: &mut FunctionValidationContext, idx: u32) -> Result { let (argument_types, return_type) = context.require_function(idx)?; for argument_type in argument_types.iter().rev() { context.pop_value((*argument_type).into())?; @@ -533,7 +540,7 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_call_indirect<'a>(context: &mut FunctionValidationContext, idx: u32) -> Result, Error> { + fn validate_call_indirect<'a>(context: &mut FunctionValidationContext, idx: u32) -> Result { context.require_table(DEFAULT_TABLE_INDEX, VariableType::AnyFunc)?; context.pop_value(ValueType::I32.into())?; @@ -547,36 +554,24 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_current_memory<'a>(context: &mut FunctionValidationContext) -> Result, Error> { + fn validate_current_memory<'a>(context: &mut FunctionValidationContext) -> Result { context.require_memory(DEFAULT_MEMORY_INDEX)?; context.push_value(ValueType::I32.into())?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_grow_memory<'a>(context: &mut FunctionValidationContext) -> Result, Error> { + fn validate_grow_memory<'a>(context: &mut FunctionValidationContext) -> Result { context.require_memory(DEFAULT_MEMORY_INDEX)?; context.pop_value(ValueType::I32.into())?; context.push_value(ValueType::I32.into())?; 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 { + fn schedule_validate_block<'a>(frame_type: BlockFrameType, block_type: BlockType, 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())); - } - - 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)) + }*/ + Ok(InstructionOutcome::ValidateBlock(frame_type, block_type)) } } @@ -592,10 +587,12 @@ impl<'a> FunctionValidationContext<'a> { FunctionValidationContext { module: module, imports: imports, + position: 0, locals: locals, value_stack: StackWithLimit::with_limit(value_stack_limit), frame_stack: StackWithLimit::with_limit(frame_stack_limit), return_type: Some(function.return_type().map(BlockType::Value).unwrap_or(BlockType::NoResult)), + labels: HashMap::new(), } } @@ -646,15 +643,17 @@ impl<'a> FunctionValidationContext<'a> { self.value_stack.push(StackValueType::AnyUnlimited) } - pub fn push_label(&mut self, is_loop: bool, block_type: BlockType) -> Result<(), Error> { + pub fn push_label(&mut self, frame_type: BlockFrameType, block_type: BlockType) -> Result<(), Error> { +//println!("=== validating.push_label({})", self.position); self.frame_stack.push(ValidationFrame { - is_loop: is_loop, + frame_type: frame_type, block_type: block_type, - value_stack_len: self.value_stack.len() + value_stack_len: self.value_stack.len(), + position: self.position, }) } - pub fn pop_label(&mut self) -> Result { + pub fn pop_label(&mut self, is_else: bool) -> Result { let frame = self.frame_stack.pop()?; let actual_value_type = if self.value_stack.len() > frame.value_stack_len { Some(self.value_stack.pop()?) @@ -663,12 +662,24 @@ impl<'a> FunctionValidationContext<'a> { }; self.value_stack.resize(frame.value_stack_len, StackValueType::Any); + if !is_else && frame.frame_type == BlockFrameType::IfTrue { + if frame.block_type != BlockType::NoResult { + return Err(Error::Validation(format!("If block without else required to have NoResult block type. But it have {:?} type", frame.block_type))); + } + } + +//println!("=== validating.pop_label({}) -> {}. block_type = {:?}. value = {:?}. len: {}", frame.position, self.position, frame.block_type, actual_value_type, self.value_stack.len()); match frame.block_type { BlockType::NoResult if actual_value_type.map(|vt| vt.is_any_unlimited()).unwrap_or(true) => (), BlockType::Value(required_value_type) if actual_value_type.map(|vt| vt == required_value_type).unwrap_or(false) => (), _ => return Err(Error::Validation(format!("Expected block to return {:?} while it has returned {:?}", frame.block_type, actual_value_type))), } - if let BlockType::Value(value_type) = frame.block_type { + if !self.frame_stack.is_empty() { + self.labels.insert(frame.position, self.position); + } + if is_else { + self.push_label(BlockFrameType::IfFalse, frame.block_type)?; + } else if let BlockType::Value(value_type) = frame.block_type { self.push_value(value_type.into())?; } @@ -787,6 +798,10 @@ impl<'a> FunctionValidationContext<'a> { }) } + pub fn function_labels(self) -> HashMap { + self.labels + } + fn check_stack_access(&self) -> Result<(), Error> { let value_stack_min = self.frame_stack.top().expect("at least 1 topmost block").value_stack_len; if self.value_stack.len() > value_stack_min { From a8852a9791b2b63dbeb1b7acf616abcf56ada0ca Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Thu, 22 Jun 2017 18:03:34 +0300 Subject: [PATCH 2/9] removed debug printlns --- src/interpreter/runner.rs | 9 --------- src/interpreter/validator.rs | 3 --- 2 files changed, 12 deletions(-) diff --git a/src/interpreter/runner.rs b/src/interpreter/runner.rs index e2f4440..7de3365 100644 --- a/src/interpreter/runner.rs +++ b/src/interpreter/runner.rs @@ -118,8 +118,6 @@ impl Interpreter { let function_return = match function_body { Some(function_body) => { -println!("=== body: {:?}", function_body.body); -println!("=== labels: {:?}", function_context.function_labels); if !function_context.is_initialized() { let return_type = function_context.return_type; function_context.initialize(function_body.locals, function_body.labels.clone())?; @@ -162,7 +160,6 @@ println!("=== labels: {:?}", function_context.function_labels); let instruction = &function_body[function_context.position]; debug!(target: "interpreter", "running {:?}", instruction); -println!("running {:?} at {}", instruction, function_context.position); match Interpreter::run_instruction(function_context, instruction)? { InstructionOutcome::RunInstruction => (), InstructionOutcome::RunNextInstruction => function_context.position += 1, @@ -225,7 +222,6 @@ println!("running {:?} at {}", instruction, function_context.position); }, InstructionOutcome::Return => break, } -//println!("=== {:?}", function_context.frame_stack().len()); } Ok(RunResult::Return(match function_context.return_type { @@ -235,7 +231,6 @@ println!("running {:?} at {}", instruction, function_context.position); } 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), @@ -450,10 +445,7 @@ println!("running {:?} at {}", instruction, function_context.position); fn run_if<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType) -> Result, Error> { let branch = context.value_stack_mut().pop_as()?; let block_frame_type = if branch { BlockFrameType::IfTrue } else { -//println!("=== position = {}", context.position); let else_pos = context.function_labels[&context.position]; -//println!("=== else_pos = {}", else_pos); -//println!("=== labels[else_pos] = {:?}", context.function_labels.get(&else_pos)); if !context.function_labels.contains_key(&else_pos) { context.position = else_pos; return Ok(InstructionOutcome::RunNextInstruction); @@ -1148,7 +1140,6 @@ impl<'a> FunctionContext<'a> { }; self.value_stack.resize(frame.value_limit, RuntimeValue::I32(0)); self.position = if is_branch { frame.branch_position } else { frame.end_position }; -//println!("=== pop_frame: position = {}", self.position); if let Some(frame_value) = frame_value { self.value_stack.push(frame_value)?; } diff --git a/src/interpreter/validator.rs b/src/interpreter/validator.rs index ab06215..65db9c9 100644 --- a/src/interpreter/validator.rs +++ b/src/interpreter/validator.rs @@ -122,7 +122,6 @@ impl Validator { pub fn validate_instruction<'a>(context: &mut FunctionValidationContext, opcode: &'a Opcode) -> Result { debug!(target: "validator", "validating {:?}", opcode); -println!("validating {:?} at {}, len: {}", opcode, context.position, context.value_stack.len()); match opcode { &Opcode::Unreachable => Ok(InstructionOutcome::Unreachable), &Opcode::Nop => Ok(InstructionOutcome::ValidateNextInstruction), @@ -644,7 +643,6 @@ impl<'a> FunctionValidationContext<'a> { } pub fn push_label(&mut self, frame_type: BlockFrameType, block_type: BlockType) -> Result<(), Error> { -//println!("=== validating.push_label({})", self.position); self.frame_stack.push(ValidationFrame { frame_type: frame_type, block_type: block_type, @@ -668,7 +666,6 @@ impl<'a> FunctionValidationContext<'a> { } } -//println!("=== validating.pop_label({}) -> {}. block_type = {:?}. value = {:?}. len: {}", frame.position, self.position, frame.block_type, actual_value_type, self.value_stack.len()); match frame.block_type { BlockType::NoResult if actual_value_type.map(|vt| vt.is_any_unlimited()).unwrap_or(true) => (), BlockType::Value(required_value_type) if actual_value_type.map(|vt| vt == required_value_type).unwrap_or(false) => (), From 673392cad48a203ac40af40f8eb70754f2284425 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Fri, 23 Jun 2017 09:20:58 +0300 Subject: [PATCH 3/9] get rid of duplicate BlockFrame --- src/interpreter/runner.rs | 45 ++++---------------------- src/interpreter/validator.rs | 62 ++++++++++++++++++++---------------- 2 files changed, 41 insertions(+), 66 deletions(-) diff --git a/src/interpreter/runner.rs b/src/interpreter/runner.rs index 7de3365..b652033 100644 --- a/src/interpreter/runner.rs +++ b/src/interpreter/runner.rs @@ -13,6 +13,7 @@ use interpreter::value::{ RuntimeValue, TryInto, WrapInto, TryTruncateInto, ExtendInto, ArithmeticOps, Integer, Float, LittleEndianConvert, TransmuteInto, }; +use interpreter::validator::{BlockFrame, BlockFrameType}; use interpreter::variable::VariableInstance; /// Index of default linear memory. @@ -66,38 +67,6 @@ pub enum InstructionOutcome<'a> { Return, } -/// Control stack frame. -#[derive(Debug, Clone)] -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, - /// 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, -} - -/// Type of block frame. -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum BlockFrameType { - /// Function frame. - Function, - /// Usual block frame. - Block, - /// Loop frame (branching to the beginning of block). - Loop, - /// True-subblock of if expression. - IfTrue, - /// False-subblock of if expression. - IfFalse, -} - /// Function run result. enum RunResult<'a> { /// Function has returned (optional) value. @@ -1095,7 +1064,7 @@ impl<'a> FunctionContext<'a> { &mut self.frame_stack } - pub fn push_frame(&mut self, frame_type: BlockFrameType, signature: BlockType) -> Result<(), Error> { + pub fn push_frame(&mut self, frame_type: BlockFrameType, block_type: BlockType) -> Result<(), Error> { let begin_position = self.position; let branch_position = match frame_type { BlockFrameType::Function => usize::MAX, @@ -1115,11 +1084,11 @@ impl<'a> FunctionContext<'a> { }; self.frame_stack.push(BlockFrame { frame_type: frame_type, + block_type: block_type, begin_position: begin_position, branch_position: branch_position, end_position: end_position, - value_limit: self.value_stack.len(), - signature: signature, + value_stack_len: self.value_stack.len(), }) } @@ -1130,15 +1099,15 @@ impl<'a> FunctionContext<'a> { pub fn pop_frame(&mut self, is_branch: bool) -> Result<(), Error> { let frame = self.frame_stack.pop()?; - if frame.value_limit > self.value_stack.len() { + if frame.value_stack_len > self.value_stack.len() { return Err(Error::Stack("invalid stack len".into())); } - let frame_value = match frame.signature { + let frame_value = match frame.block_type { BlockType::Value(_) if frame.frame_type != BlockFrameType::Loop || !is_branch => Some(self.value_stack.pop()?), _ => None, }; - self.value_stack.resize(frame.value_limit, RuntimeValue::I32(0)); + self.value_stack.resize(frame.value_stack_len, RuntimeValue::I32(0)); self.position = if is_branch { frame.branch_position } else { frame.end_position }; if let Some(frame_value) = frame_value { self.value_stack.push(frame_value)?; diff --git a/src/interpreter/validator.rs b/src/interpreter/validator.rs index 65db9c9..f4bfda4 100644 --- a/src/interpreter/validator.rs +++ b/src/interpreter/validator.rs @@ -8,8 +8,6 @@ use interpreter::module::ItemIndex; use interpreter::stack::StackWithLimit; use interpreter::variable::VariableType; -use interpreter::runner::BlockFrameType; - /// Constant from wabt' validator.cc to skip alignment validation (not a part of spec). const NATURAL_ALIGNMENT: u32 = 0xFFFFFFFF; @@ -19,14 +17,14 @@ pub struct FunctionValidationContext<'a> { module: &'a Module, /// Module imports. imports: &'a ModuleImports, - /// Position. + /// Current instruction position. position: usize, /// Local variables. locals: &'a [ValueType], /// Value stack. value_stack: StackWithLimit, /// Frame stack. - frame_stack: StackWithLimit, + frame_stack: StackWithLimit, /// Function return type. None if validating expression. return_type: Option, /// Labels positions. @@ -44,17 +42,36 @@ pub enum StackValueType { Specific(ValueType), } -/// Function validation frame. +/// Control stack frame. #[derive(Debug, Clone)] -pub struct ValidationFrame { - /// Frame type +pub struct BlockFrame { + /// Frame type. pub frame_type: BlockFrameType, - /// Return type. + /// A signature, which is a block signature type indicating the number and types of result values of the region. pub block_type: BlockType, - /// Value stack len. + /// A label for reference to block instruction. + pub begin_position: usize, + /// A label for reference from branch instructions. + pub branch_position: usize, + /// A label for reference from end instructions. + pub 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. pub value_stack_len: usize, - /// Frame instruction position. - pub position: usize, +} + +/// Type of block frame. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum BlockFrameType { + /// Function frame. + Function, + /// Usual block frame. + Block, + /// Loop frame (branching to the beginning of block). + Loop, + /// True-subblock of if expression. + IfTrue, + /// False-subblock of if expression. + IfFalse, } /// Function validator. @@ -103,19 +120,6 @@ impl Validator { //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; - },*/ } } } @@ -643,11 +647,13 @@ impl<'a> FunctionValidationContext<'a> { } pub fn push_label(&mut self, frame_type: BlockFrameType, block_type: BlockType) -> Result<(), Error> { - self.frame_stack.push(ValidationFrame { + self.frame_stack.push(BlockFrame { frame_type: frame_type, block_type: block_type, + begin_position: self.position, + branch_position: self.position, + end_position: self.position, value_stack_len: self.value_stack.len(), - position: self.position, }) } @@ -672,7 +678,7 @@ impl<'a> FunctionValidationContext<'a> { _ => return Err(Error::Validation(format!("Expected block to return {:?} while it has returned {:?}", frame.block_type, actual_value_type))), } if !self.frame_stack.is_empty() { - self.labels.insert(frame.position, self.position); + self.labels.insert(frame.begin_position, self.position); } if is_else { self.push_label(BlockFrameType::IfFalse, frame.block_type)?; @@ -683,7 +689,7 @@ impl<'a> FunctionValidationContext<'a> { Ok(InstructionOutcome::ValidateNextInstruction) } - pub fn require_label(&self, idx: u32) -> Result<&ValidationFrame, Error> { + pub fn require_label(&self, idx: u32) -> Result<&BlockFrame, Error> { self.frame_stack.get(idx as usize) } From c944b4c91e05ffbd044417e33467d4091a6614bd Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Fri, 23 Jun 2017 09:53:05 +0300 Subject: [PATCH 4/9] simplify else validation --- src/interpreter/module.rs | 4 +- src/interpreter/validator.rs | 107 +++++++++++++++-------------------- 2 files changed, 49 insertions(+), 62 deletions(-) diff --git a/src/interpreter/module.rs b/src/interpreter/module.rs index 3018324..cb6e11b 100644 --- a/src/interpreter/module.rs +++ b/src/interpreter/module.rs @@ -320,8 +320,8 @@ impl ModuleInstance { 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))); let mut context = FunctionValidationContext::new( - &self.module, - &self.imports, + &self.module, + &self.imports, &locals, DEFAULT_VALUE_STACK_LIMIT, DEFAULT_FRAME_STACK_LIMIT, diff --git a/src/interpreter/validator.rs b/src/interpreter/validator.rs index f4bfda4..3313c0f 100644 --- a/src/interpreter/validator.rs +++ b/src/interpreter/validator.rs @@ -84,8 +84,6 @@ pub enum InstructionOutcome { ValidateNextInstruction, /// Unreachable instruction reached. Unreachable, - /// Validate block. - ValidateBlock(BlockFrameType, BlockType), } impl Validator { @@ -93,33 +91,28 @@ impl Validator { context.push_label(BlockFrameType::Function, block_type)?; Validator::validate_function_block(context, body)?; while !context.frame_stack.is_empty() { - context.pop_label(false)?; + context.pop_label()?; } Ok(()) } - fn validate_function_block<'a>(context: &mut FunctionValidationContext, mut body: &[Opcode]) -> Result { - loop { - if context.position >= body.len() { - return Ok(InstructionOutcome::ValidateNextInstruction); - } + fn validate_function_block<'a>(context: &mut FunctionValidationContext, body: &[Opcode]) -> Result<(), Error> { + let body_len = body.len(); + if body_len == 0 { + return Err(Error::Validation("Non-empty function body expected".into())); + } + loop { let opcode = &body[context.position]; match Validator::validate_instruction(context, opcode)? { - InstructionOutcome::ValidateNextInstruction => context.position += 1, - InstructionOutcome::Unreachable => { - context.unreachable()?; - context.position += 1; - }, - InstructionOutcome::ValidateBlock(frame_type, block_type) => { - context.push_label(frame_type, block_type)?; - context.position += 1; - //block_stack.push_back((body, position + 1, false)); + InstructionOutcome::ValidateNextInstruction => (), + InstructionOutcome::Unreachable => context.unreachable()?, + } - //body = new_body; - //position = 0; - }, + context.position += 1; + if context.position >= body_len { + return Ok(()); } } } @@ -434,41 +427,46 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_block<'a>(_context: &mut FunctionValidationContext, block_type: BlockType) -> Result { - Validator::schedule_validate_block(BlockFrameType::Block, block_type, Opcode::End) + fn validate_block<'a>(context: &mut FunctionValidationContext, block_type: BlockType) -> Result { + context.push_label(BlockFrameType::Block, block_type).map(|_| InstructionOutcome::ValidateNextInstruction) } - fn validate_loop<'a>(_context: &mut FunctionValidationContext, block_type: BlockType) -> Result { - Validator::schedule_validate_block(BlockFrameType::Loop, block_type, Opcode::End) + fn validate_loop<'a>(context: &mut FunctionValidationContext, block_type: BlockType) -> Result { + context.push_label(BlockFrameType::Loop, block_type).map(|_| InstructionOutcome::ValidateNextInstruction) } fn validate_if<'a>(context: &mut FunctionValidationContext, block_type: BlockType) -> Result { context.pop_value(ValueType::I32.into())?; - Validator::schedule_validate_block(BlockFrameType::IfTrue, block_type, Opcode::End) // TODO: else??? -/* - let body_len = body.len(); - let separator_index = body.iter() - .position(|op| *op == Opcode::Else) - .unwrap_or(body_len - 1); - if separator_index != body_len - 1 { - 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::schedule_validate_block(false, block_type, body, Opcode::End) - }*/ + context.push_label(BlockFrameType::IfTrue, block_type).map(|_| InstructionOutcome::ValidateNextInstruction) } fn validate_else(context: &mut FunctionValidationContext) -> Result { - context.pop_label(true)?; - Ok(InstructionOutcome::ValidateNextInstruction) + let block_type = { + let top_frame = context.top_label()?; + if top_frame.frame_type != BlockFrameType::IfTrue { + return Err(Error::Validation("Misplaced else instruction".into())); + } + top_frame.block_type + }; + context.pop_label()?; + + if let BlockType::Value(value_type) = block_type { + context.pop_value(value_type.into())?; + } + context.push_label(BlockFrameType::IfFalse, block_type).map(|_| InstructionOutcome::ValidateNextInstruction) } fn validate_end(context: &mut FunctionValidationContext) -> Result { - context.pop_label(false)?; - Ok(InstructionOutcome::ValidateNextInstruction) + { + let top_frame = context.top_label()?; + if top_frame.frame_type == BlockFrameType::IfTrue { + if top_frame.block_type != BlockType::NoResult { + return Err(Error::Validation(format!("If block without else required to have NoResult block type. But it have {:?} type", top_frame.block_type))); + } + } + } + + context.pop_label().map(|_| InstructionOutcome::ValidateNextInstruction) } fn validate_br<'a>(context: &mut FunctionValidationContext, idx: u32) -> Result { @@ -569,13 +567,6 @@ impl Validator { context.push_value(ValueType::I32.into())?; Ok(InstructionOutcome::ValidateNextInstruction) } - - fn schedule_validate_block<'a>(frame_type: BlockFrameType, block_type: BlockType, 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())); - }*/ - Ok(InstructionOutcome::ValidateBlock(frame_type, block_type)) - } } impl<'a> FunctionValidationContext<'a> { @@ -646,6 +637,10 @@ impl<'a> FunctionValidationContext<'a> { self.value_stack.push(StackValueType::AnyUnlimited) } + pub fn top_label(&self) -> Result<&BlockFrame, Error> { + self.frame_stack.top() + } + pub fn push_label(&mut self, frame_type: BlockFrameType, block_type: BlockType) -> Result<(), Error> { self.frame_stack.push(BlockFrame { frame_type: frame_type, @@ -657,7 +652,7 @@ impl<'a> FunctionValidationContext<'a> { }) } - pub fn pop_label(&mut self, is_else: bool) -> Result { + pub fn pop_label(&mut self) -> Result { let frame = self.frame_stack.pop()?; let actual_value_type = if self.value_stack.len() > frame.value_stack_len { Some(self.value_stack.pop()?) @@ -666,12 +661,6 @@ impl<'a> FunctionValidationContext<'a> { }; self.value_stack.resize(frame.value_stack_len, StackValueType::Any); - if !is_else && frame.frame_type == BlockFrameType::IfTrue { - if frame.block_type != BlockType::NoResult { - return Err(Error::Validation(format!("If block without else required to have NoResult block type. But it have {:?} type", frame.block_type))); - } - } - match frame.block_type { BlockType::NoResult if actual_value_type.map(|vt| vt.is_any_unlimited()).unwrap_or(true) => (), BlockType::Value(required_value_type) if actual_value_type.map(|vt| vt == required_value_type).unwrap_or(false) => (), @@ -680,9 +669,7 @@ impl<'a> FunctionValidationContext<'a> { if !self.frame_stack.is_empty() { self.labels.insert(frame.begin_position, self.position); } - if is_else { - self.push_label(BlockFrameType::IfFalse, frame.block_type)?; - } else if let BlockType::Value(value_type) = frame.block_type { + if let BlockType::Value(value_type) = frame.block_type { self.push_value(value_type.into())?; } From 8209ff7d6d8e03925b9976de12c0d998f19244ef Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Fri, 23 Jun 2017 10:39:31 +0300 Subject: [PATCH 5/9] use ModuleInstance methods for validation --- src/interpreter/module.rs | 45 ++++++----- src/interpreter/table.rs | 5 ++ src/interpreter/tests/basics.rs | 8 +- src/interpreter/validator.rs | 128 +++++++++----------------------- 4 files changed, 64 insertions(+), 122 deletions(-) diff --git a/src/interpreter/module.rs b/src/interpreter/module.rs index cb6e11b..ff6e078 100644 --- a/src/interpreter/module.rs +++ b/src/interpreter/module.rs @@ -39,14 +39,8 @@ pub enum ExportEntryType { Global(VariableType), } -pub struct InstantiationParams { - -} - /// Module instance API. pub trait ModuleInstanceInterface { - /// Run instantiation-time procedures (validation and start function [if any] call). Module is not completely validated until this call. - //fn instantiate<'a>(&self, is_user_module: bool, externals: Option<&'a HashMap>>) -> Result<(), Error>; /// Execute function with the given index. fn execute_index(&self, index: u32, params: ExecutionParams) -> Result, Error>; /// Execute function with the given export name. @@ -214,6 +208,7 @@ impl ModuleInstance { }) } + /// Run instantiation-time procedures (validation). Module is not completely validated until this call. pub fn instantiate<'a>(&mut self, is_user_module: bool, externals: Option<&'a HashMap>>) -> Result<(), Error> { // validate start section if let Some(start_function) = self.module.start_section() { @@ -319,24 +314,27 @@ impl ModuleInstance { 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))); - 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_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)) - } else { - e - } - })?; - self.functions_labels.insert(index as u32, context.function_labels()); + let function_labels = { + let mut context = FunctionValidationContext::new( + self, + &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_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)) + } else { + e + } + })?; + context.function_labels() + }; + self.functions_labels.insert(index as u32, function_labels); } } @@ -369,6 +367,7 @@ impl ModuleInstance { Ok(()) } + /// Run start function [if any]. pub fn run_start_function(&self) -> Result<(), Error> { // execute start function (if any) if let Some(start_function) = self.module.start_section() { diff --git a/src/interpreter/table.rs b/src/interpreter/table.rs index 73cb41f..98c7b52 100644 --- a/src/interpreter/table.rs +++ b/src/interpreter/table.rs @@ -29,6 +29,11 @@ impl TableInstance { })) } + /// Get variable type for this table. + pub fn variable_type(&self) -> VariableType { + self.variable_type + } + /// Get the specific value in the table pub fn get(&self, offset: u32) -> Result { let buffer = self.buffer.read(); diff --git a/src/interpreter/tests/basics.rs b/src/interpreter/tests/basics.rs index 0a89392..84ddfa4 100644 --- a/src/interpreter/tests/basics.rs +++ b/src/interpreter/tests/basics.rs @@ -6,9 +6,8 @@ use elements::{ExportEntry, Internal, ImportEntry, External, GlobalEntry, Global InitExpr, ValueType, BlockType, Opcodes, Opcode, FunctionType}; use interpreter::Error; use interpreter::env_native::{env_native_module, UserFunction, UserFunctions, UserFunctionExecutor, UserFunctionDescriptor}; -use interpreter::imports::ModuleImports; use interpreter::memory::MemoryInstance; -use interpreter::module::{ModuleInstanceInterface, CallerContext, ItemIndex, ExecutionParams, ExportEntryType}; +use interpreter::module::{ModuleInstance, ModuleInstanceInterface, CallerContext, ItemIndex, ExecutionParams, ExportEntryType}; use interpreter::program::ProgramInstance; use interpreter::validator::{FunctionValidationContext, Validator}; use interpreter::value::RuntimeValue; @@ -226,9 +225,8 @@ fn env_native_export_entry_type_check() { #[test] fn if_else_with_return_type_validation() { - let module = module().build(); - let imports = ModuleImports::new(Weak::default(), None); - let mut context = FunctionValidationContext::new(&module, &imports, &[], 1024, 1024, &FunctionType::default()); + let module_instance = ModuleInstance::new(Weak::default(), "test".into(), module().build()).unwrap(); + let mut context = FunctionValidationContext::new(&module_instance, &[], 1024, 1024, &FunctionType::default()); Validator::validate_function(&mut context, BlockType::NoResult, &[ Opcode::I32Const(1), diff --git a/src/interpreter/validator.rs b/src/interpreter/validator.rs index 3313c0f..9c7260a 100644 --- a/src/interpreter/validator.rs +++ b/src/interpreter/validator.rs @@ -1,10 +1,9 @@ use std::u32; -use std::collections::{HashMap, VecDeque}; -use elements::{Module, Opcode, BlockType, FunctionType, ValueType, External, Type}; +use std::collections::HashMap; +use elements::{Opcode, BlockType, FunctionType, ValueType}; use interpreter::Error; use interpreter::runner::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; -use interpreter::imports::ModuleImports; -use interpreter::module::ItemIndex; +use interpreter::module::{ModuleInstance, ModuleInstanceInterface, ItemIndex}; use interpreter::stack::StackWithLimit; use interpreter::variable::VariableType; @@ -13,10 +12,8 @@ const NATURAL_ALIGNMENT: u32 = 0xFFFFFFFF; /// Function validation context. pub struct FunctionValidationContext<'a> { - /// Wasm module. - module: &'a Module, - /// Module imports. - imports: &'a ModuleImports, + /// Wasm module instance (in process of instantiation). + module_instance: &'a ModuleInstance, /// Current instruction position. position: usize, /// Local variables. @@ -571,16 +568,14 @@ impl Validator { impl<'a> FunctionValidationContext<'a> { pub fn new( - module: &'a Module, - imports: &'a ModuleImports, + module_instance: &'a ModuleInstance, locals: &'a [ValueType], value_stack_limit: usize, frame_stack_limit: usize, function: &FunctionType, ) -> Self { FunctionValidationContext { - module: module, - imports: imports, + module_instance: module_instance, position: 0, locals: locals, value_stack: StackWithLimit::with_limit(value_stack_limit), @@ -692,100 +687,45 @@ impl<'a> FunctionValidationContext<'a> { } pub fn require_global(&self, idx: u32, mutability: Option) -> Result { - match self.imports.parse_global_index(ItemIndex::IndexSpace(idx)) { - ItemIndex::IndexSpace(_) => unreachable!("parse_global_index is intended to resolve this"), - ItemIndex::Internal(internal_idx) => self.module - .global_section().ok_or(Error::Validation(format!("Trying to access internal global {} in module without global section", internal_idx))) - .and_then(|s| s.entries().get(internal_idx as usize).ok_or(Error::Validation(format!("Trying to access internal global {} in module with {} globals", internal_idx, s.entries().len())))) - .and_then(|g| match mutability { - Some(true) if !g.global_type().is_mutable() => Err(Error::Validation(format!("Expected internal global {} to be mutable", internal_idx))), - Some(false) if g.global_type().is_mutable() => Err(Error::Validation(format!("Expected internal global {} to be immutable", internal_idx))), - _ => Ok(g), - }) - .map(|g| g.global_type().content_type().into()), - ItemIndex::External(external_idx) => self.module - .import_section().ok_or(Error::Validation(format!("Trying to access external global {} in module without import section", external_idx))) - .and_then(|s| s.entries().get(external_idx as usize).ok_or(Error::Validation(format!("Trying to access external global with index {} in module with {}-entries import section", external_idx, s.entries().len())))) - .and_then(|e| match e.external() { - &External::Global(ref g) => { - match mutability { - Some(true) if !g.is_mutable() => Err(Error::Validation(format!("Expected external global {} to be mutable", external_idx))), - Some(false) if g.is_mutable() => Err(Error::Validation(format!("Expected external global {} to be immutable", external_idx))), - _ => Ok(g.content_type().into()), - } - }, - _ => Err(Error::Validation(format!("Import entry {} expected to import global", external_idx))) - }), - } + self.module_instance + .global(ItemIndex::IndexSpace(idx), None) + .and_then(|g| match mutability { + Some(true) if !g.is_mutable() => Err(Error::Validation(format!("Expected global {} to be mutable", idx))), + Some(false) if g.is_mutable() => Err(Error::Validation(format!("Expected global {} to be immutable", idx))), + _ => match g.variable_type() { + VariableType::AnyFunc => Err(Error::Validation(format!("Expected global {} to have non-AnyFunc type", idx))), + VariableType::I32 => Ok(StackValueType::Specific(ValueType::I32)), + VariableType::I64 => Ok(StackValueType::Specific(ValueType::I64)), + VariableType::F32 => Ok(StackValueType::Specific(ValueType::F32)), + VariableType::F64 => Ok(StackValueType::Specific(ValueType::F64)), + } + }) } pub fn require_memory(&self, idx: u32) -> Result<(), Error> { - match self.imports.parse_memory_index(ItemIndex::IndexSpace(idx)) { - ItemIndex::IndexSpace(_) => unreachable!("parse_memory_index is intended to resolve this"), - ItemIndex::Internal(internal_idx) => self.module - .memory_section().ok_or(Error::Validation(format!("Trying to access internal memory {} in module without memory section", internal_idx))) - .and_then(|s| s.entries().get(internal_idx as usize).ok_or(Error::Validation(format!("Trying to access internal memory {} in module with {} memory regions", internal_idx, s.entries().len())))) - .map(|_| ()), - ItemIndex::External(external_idx) => self.module - .import_section().ok_or(Error::Validation(format!("Trying to access external memory {} in module without import section", external_idx))) - .and_then(|s| s.entries().get(external_idx as usize).ok_or(Error::Validation(format!("Trying to access external memory with index {} in module with {}-entries import section", external_idx, s.entries().len())))) - .and_then(|e| match e.external() { - &External::Memory(_) => Ok(()), - _ => Err(Error::Validation(format!("Import entry {} expected to import memory", external_idx))) - }), - } + self.module_instance + .memory(ItemIndex::IndexSpace(idx)) + .map(|_| ()) } pub fn require_table(&self, idx: u32, variable_type: VariableType) -> Result<(), Error> { - match self.imports.parse_table_index(ItemIndex::IndexSpace(idx)) { - ItemIndex::IndexSpace(_) => unreachable!("parse_table_index is intended to resolve this"), - ItemIndex::Internal(internal_idx) => self.module - .table_section().ok_or(Error::Validation(format!("Trying to access internal table {} in module without table section", internal_idx))) - .and_then(|s| s.entries().get(internal_idx as usize).ok_or(Error::Validation(format!("Trying to access internal table {} in module with {} tables", internal_idx, s.entries().len())))) - .and_then(|t| if variable_type == t.elem_type().into() { - Ok(()) - } else { - Err(Error::Validation(format!("Internal table {} has element type {:?} while {:?} expected", internal_idx, t.elem_type(), variable_type))) - }), - ItemIndex::External(external_idx) => self.module - .import_section().ok_or(Error::Validation(format!("Trying to access external table {} in module without import section", external_idx))) - .and_then(|s| s.entries().get(external_idx as usize).ok_or(Error::Validation(format!("Trying to access external table with index {} in module with {}-entries import section", external_idx, s.entries().len())))) - .and_then(|e| match e.external() { - &External::Table(ref t) => if variable_type == t.elem_type().into() { - Ok(()) - } else { - Err(Error::Validation(format!("External table {} has element type {:?} while {:?} expected", external_idx, t.elem_type(), variable_type))) - }, - _ => Err(Error::Validation(format!("Import entry {} expected to import table", external_idx))) - }), - } + self.module_instance + .table(ItemIndex::IndexSpace(idx)) + .and_then(|t| if t.variable_type() == variable_type { + Ok(()) + } else { + Err(Error::Validation(format!("Table {} has element type {:?} while {:?} expected", idx, t.variable_type(), variable_type))) + }) } pub fn require_function(&self, idx: u32) -> Result<(Vec, BlockType), Error> { - match self.imports.parse_function_index(ItemIndex::IndexSpace(idx)) { - ItemIndex::IndexSpace(_) => unreachable!("parse_function_index is intended to resolve this"), - ItemIndex::Internal(internal_idx) => self.module - .function_section().ok_or(Error::Validation(format!("Trying to access internal function {} in module without function section", internal_idx))) - .and_then(|s| s.entries().get(internal_idx as usize).map(|f| f.type_ref()).ok_or(Error::Validation(format!("Trying to access internal function {} in module with {} functions", internal_idx, s.entries().len())))) - .and_then(|tidx| self.require_function_type(tidx)), - ItemIndex::External(external_idx) => self.module - .import_section().ok_or(Error::Validation(format!("Trying to access external function {} in module without import section", external_idx))) - .and_then(|s| s.entries().get(external_idx as usize).ok_or(Error::Validation(format!("Trying to access external function with index {} in module with {}-entries import section", external_idx, s.entries().len())))) - .and_then(|e| match e.external() { - &External::Function(tidx) => Ok(tidx), - _ => Err(Error::Validation(format!("Import entry {} expected to import function", external_idx))) - }) - .and_then(|tidx| self.require_function_type(tidx)), - } + self.module_instance.function_type(ItemIndex::IndexSpace(idx)) + .map(|ft| (ft.params().to_vec(), ft.return_type().map(BlockType::Value).unwrap_or(BlockType::NoResult))) } pub fn require_function_type(&self, idx: u32) -> Result<(Vec, BlockType), Error> { - self.module - .type_section().ok_or(Error::Validation(format!("Trying to access internal function {} in module without type section", idx))) - .and_then(|ts| match ts.types().get(idx as usize) { - Some(&Type::Function(ref function_type)) => Ok((function_type.params().to_vec(), function_type.return_type().map(BlockType::Value).unwrap_or(BlockType::NoResult))), - _ => Err(Error::Validation(format!("Trying to access internal function {} with wrong type", idx))), - }) + self.module_instance.function_type_by_index(idx) + .map(|ft| (ft.params().to_vec(), ft.return_type().map(BlockType::Value).unwrap_or(BlockType::NoResult))) } pub fn function_labels(self) -> HashMap { From 66e2d0ae103249e971331370f8102bcf32bbbde9 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Fri, 23 Jun 2017 11:00:18 +0300 Subject: [PATCH 6/9] removed extra instruction outcomes --- src/interpreter/runner.rs | 55 +++--------------------------------- src/interpreter/validator.rs | 2 +- 2 files changed, 5 insertions(+), 52 deletions(-) diff --git a/src/interpreter/runner.rs b/src/interpreter/runner.rs index b652033..07aa170 100644 --- a/src/interpreter/runner.rs +++ b/src/interpreter/runner.rs @@ -49,16 +49,10 @@ pub struct FunctionContext<'a> { /// Interpreter action to execute after executing instruction. #[derive(Debug)] pub enum InstructionOutcome<'a> { - /// Continue with current instruction. - RunInstruction, /// Continue with next instruction. RunNextInstruction, /// Branch to given frame. Branch(usize), - /// Skip if-false (aka else) branch. - SkipIfFalse, - /// Run if-false (aka else) branch (if any). - RunIfFalse, /// Execute function call. ExecuteCall(InternalFunctionReference<'a>), /// End current frame. @@ -130,7 +124,6 @@ impl Interpreter { debug!(target: "interpreter", "running {:?}", instruction); match Interpreter::run_instruction(function_context, instruction)? { - InstructionOutcome::RunInstruction => (), InstructionOutcome::RunNextInstruction => function_context.position += 1, InstructionOutcome::Branch(mut index) => { // discard index - 1 blocks @@ -144,40 +137,6 @@ impl Interpreter { break; } }, - InstructionOutcome::SkipIfFalse => { - // skip until else/end is found - let mut block_count = 1; - loop { - function_context.position += 1; - debug_assert!(function_context.position < function_body.len()); - - let instruction = &function_body[function_context.position]; - match instruction { - &Opcode::End if block_count == 1 => break, - &Opcode::Block(_) | &Opcode::Loop(_) | &Opcode::If(_) => block_count += 1, - &Opcode::End => block_count -= 1, - _ => (), - } - } - function_context.position += 1; - }, - InstructionOutcome::RunIfFalse => { - // skip until else/end is found - let mut block_count = 1; - loop { - function_context.position += 1; - debug_assert!(function_context.position < function_body.len()); - - let instruction = &function_body[function_context.position]; - match instruction { - &Opcode::End | &Opcode::Else if block_count == 1 => break, - &Opcode::Block(_) | &Opcode::Loop(_) | &Opcode::If(_) => block_count += 1, - &Opcode::End => block_count -= 1, - _ => (), - } - } - function_context.position += 1; - }, InstructionOutcome::ExecuteCall(func_ref) => { function_context.position += 1; return Ok(RunResult::NestedCall(function_context.nested(func_ref)?)); @@ -186,8 +145,6 @@ impl Interpreter { if function_context.frame_stack().is_empty() { break; } - - //function_context.position += 1; }, InstructionOutcome::Return => break, } @@ -423,18 +380,14 @@ impl Interpreter { context.position = else_pos; BlockFrameType::IfFalse }; - context.push_frame(block_frame_type, block_type)?; - - //if branch { - Ok(InstructionOutcome::RunNextInstruction) - /*} else { - Ok(InstructionOutcome::RunIfFalse) - }*/ + context.push_frame(block_frame_type, block_type).map(|_| InstructionOutcome::RunNextInstruction) } fn run_else<'a>(context: &mut FunctionContext) -> Result, Error> { + let end_pos = context.function_labels[&context.position]; context.pop_frame(false)?; - Ok(InstructionOutcome::SkipIfFalse) + context.position = end_pos; + Ok(InstructionOutcome::RunNextInstruction) } fn run_end<'a>(context: &mut FunctionContext) -> Result, Error> { diff --git a/src/interpreter/validator.rs b/src/interpreter/validator.rs index 9c7260a..ed0a737 100644 --- a/src/interpreter/validator.rs +++ b/src/interpreter/validator.rs @@ -114,7 +114,7 @@ impl Validator { } } - pub fn validate_instruction<'a>(context: &mut FunctionValidationContext, opcode: &'a Opcode) -> Result { + fn validate_instruction<'a>(context: &mut FunctionValidationContext, opcode: &'a Opcode) -> Result { debug!(target: "validator", "validating {:?}", opcode); match opcode { &Opcode::Unreachable => Ok(InstructionOutcome::Unreachable), From b40591e121c148c5cadb530669cc0ac1d10f8500 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Fri, 23 Jun 2017 13:20:41 +0300 Subject: [PATCH 7/9] remove comments --- src/interpreter/env.rs | 4 ---- src/interpreter/env_native.rs | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/interpreter/env.rs b/src/interpreter/env.rs index eef3fa2..cfc68cd 100644 --- a/src/interpreter/env.rs +++ b/src/interpreter/env.rs @@ -92,10 +92,6 @@ impl EnvModuleInstance { } impl ModuleInstanceInterface for EnvModuleInstance { - /*fn instantiate<'a>(&self, is_user_module: bool, externals: Option<&'a HashMap>>) -> Result<(), Error> { - self.instance.instantiate(is_user_module, externals) - }*/ - fn execute_index(&self, index: u32, params: ExecutionParams) -> Result, Error> { self.instance.execute_index(index, params) } diff --git a/src/interpreter/env_native.rs b/src/interpreter/env_native.rs index 4b66800..f9e9c90 100644 --- a/src/interpreter/env_native.rs +++ b/src/interpreter/env_native.rs @@ -110,10 +110,6 @@ impl<'a> NativeModuleInstance<'a> { } impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { - /*fn instantiate<'b>(&self, is_user_module: bool, externals: Option<&'b HashMap>>) -> Result<(), Error> { - self.env.instantiate(is_user_module, externals) - }*/ - fn execute_index(&self, index: u32, params: ExecutionParams) -> Result, Error> { self.env.execute_index(index, params) } From ca001e21df4e0abc6c68d37459441767e36656dc Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Fri, 23 Jun 2017 13:21:27 +0300 Subject: [PATCH 8/9] remove comment --- src/interpreter/program.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/interpreter/program.rs b/src/interpreter/program.rs index 0427f85..482ea30 100644 --- a/src/interpreter/program.rs +++ b/src/interpreter/program.rs @@ -40,16 +40,6 @@ impl ProgramInstance { self.essence.modules.write().insert(name.into(), module_instance.clone()); module_instance.run_start_function()?; Ok(module_instance) - /*let module_instance = Arc::new(ModuleInstance::new(Arc::downgrade(&self.essence), name.into(), module)?); - self.essence.modules.write().insert(name.into(), module_instance.clone()); - // 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) - } - }*/ } /// Insert instantiated module. From a8e13030ece02ca5284c31873367fe84ac7b5cb0 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Fri, 23 Jun 2017 14:11:09 +0300 Subject: [PATCH 9/9] removed panics && lifetimes --- src/interpreter/module.rs | 2 +- src/interpreter/runner.rs | 12 ++++---- src/interpreter/stack.rs | 3 -- src/interpreter/validator.rs | 56 ++++++++++++++++++------------------ 4 files changed, 35 insertions(+), 38 deletions(-) diff --git a/src/interpreter/module.rs b/src/interpreter/module.rs index ff6e078..41d09e8 100644 --- a/src/interpreter/module.rs +++ b/src/interpreter/module.rs @@ -377,7 +377,7 @@ impl ModuleInstance { } fn self_ref<'a>(&self, externals: Option<&'a HashMap>>) -> Result, Error> { - self.imports.module(externals, &self.name).map_err(|_| panic!("xxx")) + self.imports.module(externals, &self.name) } fn require_function(&self, index: ItemIndex) -> Result { diff --git a/src/interpreter/runner.rs b/src/interpreter/runner.rs index 07aa170..e12f3f6 100644 --- a/src/interpreter/runner.rs +++ b/src/interpreter/runner.rs @@ -156,7 +156,7 @@ impl Interpreter { })) } - fn run_instruction<'a, 'b>(context: &'b mut FunctionContext<'a>, opcode: &Opcode) -> Result, Error> { + fn run_instruction<'a>(context: &mut FunctionContext<'a>, opcode: &Opcode) -> Result, Error> { match opcode { &Opcode::Unreachable => Interpreter::run_unreachable(context), &Opcode::Nop => Interpreter::run_nop(context), @@ -358,17 +358,17 @@ impl Interpreter { Ok(InstructionOutcome::RunNextInstruction) } - fn run_block<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType) -> Result, Error> { + fn run_block<'a>(context: &mut FunctionContext<'a>, block_type: BlockType) -> Result, Error> { context.push_frame(BlockFrameType::Block, block_type)?; Ok(InstructionOutcome::RunNextInstruction) } - fn run_loop<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType) -> Result, Error> { + fn run_loop<'a>(context: &mut FunctionContext<'a>, block_type: BlockType) -> Result, Error> { context.push_frame(BlockFrameType::Loop, block_type)?; Ok(InstructionOutcome::RunNextInstruction) } - fn run_if<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType) -> Result, Error> { + fn run_if<'a>(context: &mut FunctionContext<'a>, block_type: BlockType) -> Result, Error> { let branch = context.value_stack_mut().pop_as()?; let block_frame_type = if branch { BlockFrameType::IfTrue } else { let else_pos = context.function_labels[&context.position]; @@ -416,11 +416,11 @@ impl Interpreter { Ok(InstructionOutcome::Return) } - fn run_call<'a, 'b>(context: &'b mut FunctionContext<'a>, func_idx: u32) -> Result, Error> where 'a: 'b { + fn run_call<'a>(context: &mut FunctionContext<'a>, func_idx: u32) -> Result, Error> { Ok(InstructionOutcome::ExecuteCall(context.module().function_reference(ItemIndex::IndexSpace(func_idx), Some(context.externals))?)) } - fn run_call_indirect<'a, 'b>(context: &'b mut FunctionContext<'a>, type_idx: u32) -> Result, Error> { + fn run_call_indirect<'a>(context: &mut FunctionContext<'a>, type_idx: u32) -> Result, Error> { 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)?; diff --git a/src/interpreter/stack.rs b/src/interpreter/stack.rs index 3acfa86..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(|_| 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(|_| 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(|_| panic!("3")) } pub fn resize(&mut self, new_size: usize, dummy: T) { diff --git a/src/interpreter/validator.rs b/src/interpreter/validator.rs index ed0a737..6205370 100644 --- a/src/interpreter/validator.rs +++ b/src/interpreter/validator.rs @@ -94,7 +94,7 @@ impl Validator { Ok(()) } - fn validate_function_block<'a>(context: &mut FunctionValidationContext, body: &[Opcode]) -> Result<(), Error> { + fn validate_function_block(context: &mut FunctionValidationContext, body: &[Opcode]) -> Result<(), Error> { let body_len = body.len(); if body_len == 0 { return Err(Error::Validation("Non-empty function body expected".into())); @@ -114,7 +114,7 @@ impl Validator { } } - fn validate_instruction<'a>(context: &mut FunctionValidationContext, opcode: &'a Opcode) -> Result { + fn validate_instruction(context: &mut FunctionValidationContext, opcode: &Opcode) -> Result { debug!(target: "validator", "validating {:?}", opcode); match opcode { &Opcode::Unreachable => Ok(InstructionOutcome::Unreachable), @@ -309,49 +309,49 @@ impl Validator { } } - fn validate_const<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { + fn validate_const(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { context.push_value(value_type)?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_unop<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { + fn validate_unop(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { context.pop_value(value_type)?; context.push_value(value_type)?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_binop<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { + fn validate_binop(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { context.pop_value(value_type)?; context.pop_value(value_type)?; context.push_value(value_type)?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_testop<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { + fn validate_testop(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { context.pop_value(value_type)?; context.push_value(ValueType::I32.into())?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_relop<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { + fn validate_relop(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result { context.pop_value(value_type)?; context.pop_value(value_type)?; context.push_value(ValueType::I32.into())?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_cvtop<'a>(context: &mut FunctionValidationContext, value_type1: StackValueType, value_type2: StackValueType) -> Result { + fn validate_cvtop(context: &mut FunctionValidationContext, value_type1: StackValueType, value_type2: StackValueType) -> Result { context.pop_value(value_type1)?; context.push_value(value_type2)?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_drop<'a>(context: &mut FunctionValidationContext) -> Result { + fn validate_drop(context: &mut FunctionValidationContext) -> Result { context.pop_any_value().map(|_| ())?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_select<'a>(context: &mut FunctionValidationContext) -> Result { + fn validate_select(context: &mut FunctionValidationContext) -> Result { context.pop_value(ValueType::I32.into())?; let select_type = context.pop_any_value()?; context.pop_value(select_type)?; @@ -359,13 +359,13 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_get_local<'a>(context: &mut FunctionValidationContext, index: u32) -> Result { + fn validate_get_local(context: &mut FunctionValidationContext, index: u32) -> Result { let local_type = context.require_local(index)?; context.push_value(local_type)?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_set_local<'a>(context: &mut FunctionValidationContext, index: u32) -> Result { + fn validate_set_local(context: &mut FunctionValidationContext, index: u32) -> Result { let local_type = context.require_local(index)?; let value_type = context.pop_any_value()?; if local_type != value_type { @@ -374,7 +374,7 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_tee_local<'a>(context: &mut FunctionValidationContext, index: u32) -> Result { + fn validate_tee_local(context: &mut FunctionValidationContext, index: u32) -> Result { let local_type = context.require_local(index)?; let value_type = context.tee_any_value()?; if local_type != value_type { @@ -383,13 +383,13 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_get_global<'a>(context: &mut FunctionValidationContext, index: u32) -> Result { + fn validate_get_global(context: &mut FunctionValidationContext, index: u32) -> Result { let global_type = context.require_global(index, None)?; context.push_value(global_type)?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_set_global<'a>(context: &mut FunctionValidationContext, index: u32) -> Result { + fn validate_set_global(context: &mut FunctionValidationContext, index: u32) -> Result { let global_type = context.require_global(index, Some(true))?; let value_type = context.pop_any_value()?; if global_type != value_type { @@ -398,7 +398,7 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_load<'a>(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: StackValueType) -> Result { + fn validate_load(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: StackValueType) -> Result { 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))); @@ -411,7 +411,7 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_store<'a>(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: StackValueType) -> Result { + fn validate_store(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: StackValueType) -> Result { 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))); @@ -424,15 +424,15 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_block<'a>(context: &mut FunctionValidationContext, block_type: BlockType) -> Result { + fn validate_block(context: &mut FunctionValidationContext, block_type: BlockType) -> Result { context.push_label(BlockFrameType::Block, block_type).map(|_| InstructionOutcome::ValidateNextInstruction) } - fn validate_loop<'a>(context: &mut FunctionValidationContext, block_type: BlockType) -> Result { + fn validate_loop(context: &mut FunctionValidationContext, block_type: BlockType) -> Result { context.push_label(BlockFrameType::Loop, block_type).map(|_| InstructionOutcome::ValidateNextInstruction) } - fn validate_if<'a>(context: &mut FunctionValidationContext, block_type: BlockType) -> Result { + fn validate_if(context: &mut FunctionValidationContext, block_type: BlockType) -> Result { context.pop_value(ValueType::I32.into())?; context.push_label(BlockFrameType::IfTrue, block_type).map(|_| InstructionOutcome::ValidateNextInstruction) } @@ -466,7 +466,7 @@ impl Validator { context.pop_label().map(|_| InstructionOutcome::ValidateNextInstruction) } - fn validate_br<'a>(context: &mut FunctionValidationContext, idx: u32) -> Result { + fn validate_br(context: &mut FunctionValidationContext, idx: u32) -> Result { let (frame_type, frame_block_type) = { let frame = context.require_label(idx)?; (frame.frame_type, frame.block_type) @@ -480,7 +480,7 @@ impl Validator { Ok(InstructionOutcome::Unreachable) } - fn validate_br_if<'a>(context: &mut FunctionValidationContext, idx: u32) -> Result { + fn validate_br_if(context: &mut FunctionValidationContext, idx: u32) -> Result { context.pop_value(ValueType::I32.into())?; if let BlockType::Value(value_type) = context.require_label(idx)?.block_type { context.tee_value(value_type.into())?; @@ -488,7 +488,7 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_br_table<'a>(context: &mut FunctionValidationContext, table: &Vec, default: u32) -> Result { + fn validate_br_table(context: &mut FunctionValidationContext, table: &Vec, default: u32) -> Result { let mut required_block_type = None; { @@ -520,14 +520,14 @@ impl Validator { Ok(InstructionOutcome::Unreachable) } - fn validate_return<'a>(context: &mut FunctionValidationContext) -> Result { + fn validate_return(context: &mut FunctionValidationContext) -> Result { if let BlockType::Value(value_type) = context.return_type()? { context.tee_value(value_type.into())?; } Ok(InstructionOutcome::Unreachable) } - fn validate_call<'a>(context: &mut FunctionValidationContext, idx: u32) -> Result { + fn validate_call(context: &mut FunctionValidationContext, idx: u32) -> Result { let (argument_types, return_type) = context.require_function(idx)?; for argument_type in argument_types.iter().rev() { context.pop_value((*argument_type).into())?; @@ -538,7 +538,7 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_call_indirect<'a>(context: &mut FunctionValidationContext, idx: u32) -> Result { + fn validate_call_indirect(context: &mut FunctionValidationContext, idx: u32) -> Result { context.require_table(DEFAULT_TABLE_INDEX, VariableType::AnyFunc)?; context.pop_value(ValueType::I32.into())?; @@ -552,13 +552,13 @@ impl Validator { Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_current_memory<'a>(context: &mut FunctionValidationContext) -> Result { + fn validate_current_memory(context: &mut FunctionValidationContext) -> Result { context.require_memory(DEFAULT_MEMORY_INDEX)?; context.push_value(ValueType::I32.into())?; Ok(InstructionOutcome::ValidateNextInstruction) } - fn validate_grow_memory<'a>(context: &mut FunctionValidationContext) -> Result { + fn validate_grow_memory(context: &mut FunctionValidationContext) -> Result { context.require_memory(DEFAULT_MEMORY_INDEX)?; context.pop_value(ValueType::I32.into())?; context.push_value(ValueType::I32.into())?;