get rid of block-level recursion

This commit is contained in:
Svyatoslav Nikolsky
2017-06-13 17:16:38 +03:00
parent 9e9b573d84
commit b8405955c1
3 changed files with 233 additions and 146 deletions

View File

@ -314,7 +314,7 @@ impl ModuleInstanceInterface for ModuleInstance {
locals.extend(function_body.locals().iter().flat_map(|l| repeat(l.value_type()).take(l.count() as usize))); 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 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); let block_type = function_type.return_type().map(BlockType::Value).unwrap_or(BlockType::NoResult);
Validator::validate_block(&mut context, false, block_type, function_body.code().elements(), Opcode::End)?; Validator::validate_function(&mut context, block_type, function_body.code().elements())?;
} }
} }

View File

@ -3,7 +3,7 @@ use std::ops;
use std::u32; use std::u32;
use std::sync::Arc; use std::sync::Arc;
use std::fmt::Display; use std::fmt::Display;
use std::collections::HashMap; use std::collections::{HashMap, VecDeque};
use elements::{Opcode, BlockType, FunctionType}; use elements::{Opcode, BlockType, FunctionType};
use interpreter::Error; use interpreter::Error;
use interpreter::module::{ModuleInstance, ModuleInstanceInterface, CallerContext, ItemIndex}; use interpreter::module::{ModuleInstance, ModuleInstanceInterface, CallerContext, ItemIndex};
@ -41,7 +41,7 @@ pub struct FunctionContext<'a> {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum InstructionOutcome { pub enum InstructionOutcome<'a> {
/// Continue with current instruction. /// Continue with current instruction.
RunInstruction, RunInstruction,
/// Continue with next instruction. /// Continue with next instruction.
@ -52,6 +52,8 @@ pub enum InstructionOutcome {
End, End,
/// Return from current function block. /// Return from current function block.
Return, Return,
/// Execute block.
ExecuteBlock(&'a [Opcode]),
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -80,7 +82,7 @@ impl Interpreter {
} }
} }
fn run_instruction(context: &mut FunctionContext, opcode: &Opcode) -> Result<InstructionOutcome, Error> { fn run_instruction<'a>(context: &mut FunctionContext, opcode: &'a Opcode) -> Result<InstructionOutcome<'a>, Error> {
match opcode { match opcode {
&Opcode::Unreachable => Interpreter::run_unreachable(context), &Opcode::Unreachable => Interpreter::run_unreachable(context),
&Opcode::Nop => Interpreter::run_nop(context), &Opcode::Nop => Interpreter::run_nop(context),
@ -274,27 +276,27 @@ impl Interpreter {
} }
} }
fn run_unreachable(_context: &mut FunctionContext) -> Result<InstructionOutcome, Error> { fn run_unreachable<'a>(_context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
Err(Error::Trap("programmatic".into())) Err(Error::Trap("programmatic".into()))
} }
fn run_nop(_context: &mut FunctionContext) -> Result<InstructionOutcome, Error> { fn run_nop<'a>(_context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
fn run_block(context: &mut FunctionContext, block_type: BlockType, body: &[Opcode]) -> Result<InstructionOutcome, Error> { fn run_block<'a>(context: &mut FunctionContext, block_type: BlockType, body: &'a [Opcode]) -> Result<InstructionOutcome<'a>, Error> {
let frame_position = context.position + 1; let frame_position = context.position + 1;
context.push_frame(false, frame_position, frame_position, block_type.clone())?; context.push_frame(false, frame_position, frame_position, block_type.clone())?;
Interpreter::execute_block(context, body) Ok(InstructionOutcome::ExecuteBlock(body))
} }
fn run_loop(context: &mut FunctionContext, block_type: BlockType, body: &[Opcode]) -> Result<InstructionOutcome, Error> { fn run_loop<'a>(context: &mut FunctionContext, block_type: BlockType, body: &'a [Opcode]) -> Result<InstructionOutcome<'a>, Error> {
let frame_position = context.position; let frame_position = context.position;
context.push_frame(true, frame_position, frame_position + 1, block_type.clone())?; context.push_frame(true, frame_position, frame_position + 1, block_type.clone())?;
Interpreter::execute_block(context, body) Ok(InstructionOutcome::ExecuteBlock(body))
} }
fn run_if(context: &mut FunctionContext, block_type: BlockType, body: &[Opcode]) -> Result<InstructionOutcome, Error> { fn run_if<'a>(context: &mut FunctionContext, block_type: BlockType, body: &'a [Opcode]) -> Result<InstructionOutcome<'a>, Error> {
let body_len = body.len(); let body_len = body.len();
let else_index = body.iter().position(|op| *op == Opcode::Else).unwrap_or(body_len - 1); let else_index = body.iter().position(|op| *op == Opcode::Else).unwrap_or(body_len - 1);
let (begin_index, end_index) = if context.value_stack_mut().pop_as()? { let (begin_index, end_index) = if context.value_stack_mut().pop_as()? {
@ -306,25 +308,25 @@ impl Interpreter {
if begin_index != end_index { if begin_index != end_index {
let frame_position = context.position + 1; let frame_position = context.position + 1;
context.push_frame(false, frame_position, frame_position, block_type.clone())?; context.push_frame(false, frame_position, frame_position, block_type.clone())?;
Interpreter::execute_block(context, &body[begin_index..end_index]) Ok(InstructionOutcome::ExecuteBlock(&body[begin_index..end_index]))
} else { } else {
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::RunNextInstruction)
} }
} }
fn run_else(_context: &mut FunctionContext) -> Result<InstructionOutcome, Error> { fn run_else<'a>(_context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
Ok(InstructionOutcome::End) Ok(InstructionOutcome::End)
} }
fn run_end(_context: &mut FunctionContext) -> Result<InstructionOutcome, Error> { fn run_end<'a>(_context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
Ok(InstructionOutcome::End) Ok(InstructionOutcome::End)
} }
fn run_br(_context: &mut FunctionContext, label_idx: u32) -> Result<InstructionOutcome, Error> { fn run_br<'a>(_context: &mut FunctionContext, label_idx: u32) -> Result<InstructionOutcome<'a>, Error> {
Ok(InstructionOutcome::Branch(label_idx as usize)) Ok(InstructionOutcome::Branch(label_idx as usize))
} }
fn run_br_if(context: &mut FunctionContext, label_idx: u32) -> Result<InstructionOutcome, Error> { fn run_br_if<'a>(context: &mut FunctionContext, label_idx: u32) -> Result<InstructionOutcome<'a>, Error> {
if context.value_stack_mut().pop_as()? { if context.value_stack_mut().pop_as()? {
Ok(InstructionOutcome::Branch(label_idx as usize)) Ok(InstructionOutcome::Branch(label_idx as usize))
} else { } else {
@ -332,36 +334,36 @@ impl Interpreter {
} }
} }
fn run_br_table(context: &mut FunctionContext, table: &Vec<u32>, default: u32) -> Result<InstructionOutcome, Error> { fn run_br_table<'a>(context: &mut FunctionContext, table: &Vec<u32>, default: u32) -> Result<InstructionOutcome<'a>, Error> {
let index: u32 = context.value_stack_mut().pop_as()?; let index: u32 = context.value_stack_mut().pop_as()?;
Ok(InstructionOutcome::Branch(table.get(index as usize).cloned().unwrap_or(default) as usize)) Ok(InstructionOutcome::Branch(table.get(index as usize).cloned().unwrap_or(default) as usize))
} }
fn run_return(_context: &mut FunctionContext) -> Result<InstructionOutcome, Error> { fn run_return<'a>(_context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
Ok(InstructionOutcome::Return) Ok(InstructionOutcome::Return)
} }
fn run_call(context: &mut FunctionContext, func_idx: u32) -> Result<InstructionOutcome, Error> { fn run_call<'a>(context: &mut FunctionContext, func_idx: u32) -> Result<InstructionOutcome<'a>, Error> {
context.call_function(func_idx) context.call_function(func_idx)
.and_then(|r| r.map(|r| context.value_stack_mut().push(r)).unwrap_or(Ok(()))) .and_then(|r| r.map(|r| context.value_stack_mut().push(r)).unwrap_or(Ok(())))
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_call_indirect(context: &mut FunctionContext, type_idx: u32) -> Result<InstructionOutcome, Error> { fn run_call_indirect<'a>(context: &mut FunctionContext, type_idx: u32) -> Result<InstructionOutcome<'a>, Error> {
let table_func_idx: u32 = context.value_stack_mut().pop_as()?; let table_func_idx: u32 = context.value_stack_mut().pop_as()?;
context.call_function_indirect(DEFAULT_TABLE_INDEX, type_idx, table_func_idx) context.call_function_indirect(DEFAULT_TABLE_INDEX, type_idx, table_func_idx)
.and_then(|r| r.map(|r| context.value_stack_mut().push(r)).unwrap_or(Ok(()))) .and_then(|r| r.map(|r| context.value_stack_mut().push(r)).unwrap_or(Ok(())))
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_drop(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> { fn run_drop<'a>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
context context
.value_stack_mut() .value_stack_mut()
.pop() .pop()
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_select(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> { fn run_select<'a>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
context context
.value_stack_mut() .value_stack_mut()
.pop_triple() .pop_triple()
@ -376,32 +378,32 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_get_local(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Error> { fn run_get_local<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome<'a>, Error> {
context.get_local(index as usize) context.get_local(index as usize)
.map(|value| context.value_stack_mut().push(value)) .map(|value| context.value_stack_mut().push(value))
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_set_local(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Error> { fn run_set_local<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome<'a>, Error> {
let arg = context.value_stack_mut().pop()?; let arg = context.value_stack_mut().pop()?;
context.set_local(index as usize, arg) context.set_local(index as usize, arg)
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_tee_local(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Error> { fn run_tee_local<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome<'a>, Error> {
let arg = context.value_stack().top()?.clone(); let arg = context.value_stack().top()?.clone();
context.set_local(index as usize, arg) context.set_local(index as usize, arg)
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_get_global(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Error> { fn run_get_global<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome<'a>, Error> {
context.module() context.module()
.global(ItemIndex::IndexSpace(index), None) .global(ItemIndex::IndexSpace(index), None)
.and_then(|g| context.value_stack_mut().push(g.get())) .and_then(|g| context.value_stack_mut().push(g.get()))
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_set_global(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Error> { fn run_set_global<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome<'a>, Error> {
context context
.value_stack_mut() .value_stack_mut()
.pop() .pop()
@ -409,7 +411,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_load<T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome, Error> fn run_load<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<T>, T: LittleEndianConvert { where RuntimeValue: From<T>, T: LittleEndianConvert {
let address = effective_address(offset, context.value_stack_mut().pop_as()?)?; let address = effective_address(offset, context.value_stack_mut().pop_as()?)?;
context.module() context.module()
@ -420,7 +422,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_load_extend<T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome, Error> fn run_load_extend<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome<'a>, Error>
where T: ExtendInto<U>, RuntimeValue: From<U>, T: LittleEndianConvert { where T: ExtendInto<U>, RuntimeValue: From<U>, T: LittleEndianConvert {
let address = effective_address(offset, context.value_stack_mut().pop_as()?)?; let address = effective_address(offset, context.value_stack_mut().pop_as()?)?;
let stack_value: U = context.module() let stack_value: U = context.module()
@ -434,7 +436,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_store<T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome, Error> fn run_store<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: TryInto<T, Error>, T: LittleEndianConvert { where RuntimeValue: TryInto<T, Error>, T: LittleEndianConvert {
let stack_value = context let stack_value = context
.value_stack_mut() .value_stack_mut()
@ -447,7 +449,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_store_wrap<T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome, Error> fn run_store_wrap<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: TryInto<T, Error>, T: WrapInto<U>, U: LittleEndianConvert { where RuntimeValue: TryInto<T, Error>, T: WrapInto<U>, U: LittleEndianConvert {
let stack_value: T = context.value_stack_mut().pop().and_then(|v| v.try_into())?; let stack_value: T = context.value_stack_mut().pop().and_then(|v| v.try_into())?;
let stack_value = stack_value.wrap_into().into_little_endian(); let stack_value = stack_value.wrap_into().into_little_endian();
@ -458,7 +460,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_current_memory(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> { fn run_current_memory<'a>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
context.module() context.module()
.memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX)) .memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX))
.map(|m| m.size()) .map(|m| m.size())
@ -466,7 +468,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_grow_memory(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> { fn run_grow_memory<'a>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
let pages: u32 = context.value_stack_mut().pop_as()?; let pages: u32 = context.value_stack_mut().pop_as()?;
context.module() context.module()
.memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX)) .memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX))
@ -475,14 +477,14 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_const(context: &mut FunctionContext, val: RuntimeValue) -> Result<InstructionOutcome, Error> { fn run_const<'a>(context: &mut FunctionContext, val: RuntimeValue) -> Result<InstructionOutcome<'a>, Error> {
context context
.value_stack_mut() .value_stack_mut()
.push(val) .push(val)
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_eqz<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_eqz<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> + Default { where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> + Default {
context context
.value_stack_mut() .value_stack_mut()
@ -492,7 +494,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_eq<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_eq<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> { where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -502,7 +504,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_ne<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_ne<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> { where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -512,7 +514,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_lt<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_lt<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> + Display { where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> + Display {
context context
.value_stack_mut() .value_stack_mut()
@ -522,7 +524,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_gt<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_gt<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> { where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -532,7 +534,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_lte<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_lte<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> { where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -542,7 +544,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_gte<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_gte<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> { where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -552,7 +554,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_clz<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_clz<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -562,7 +564,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_ctz<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_ctz<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -572,7 +574,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_popcnt<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_popcnt<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -582,7 +584,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_add<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_add<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -592,7 +594,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_sub<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_sub<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -602,7 +604,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_mul<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_mul<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -612,7 +614,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_div<T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_div<'a, T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U> + Display, U: ArithmeticOps<U> + TransmuteInto<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U> + Display, U: ArithmeticOps<U> + TransmuteInto<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -624,7 +626,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_rem<T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_rem<'a, T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U>, U: Integer<U> + TransmuteInto<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U>, U: Integer<U> + TransmuteInto<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -636,7 +638,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_and<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_and<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<<T as ops::BitAnd>::Output> + TryInto<T, Error>, T: ops::BitAnd<T> { where RuntimeValue: From<<T as ops::BitAnd>::Output> + TryInto<T, Error>, T: ops::BitAnd<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -646,7 +648,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_or<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_or<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<<T as ops::BitOr>::Output> + TryInto<T, Error>, T: ops::BitOr<T> { where RuntimeValue: From<<T as ops::BitOr>::Output> + TryInto<T, Error>, T: ops::BitOr<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -656,7 +658,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_xor<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_xor<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<<T as ops::BitXor>::Output> + TryInto<T, Error>, T: ops::BitXor<T> { where RuntimeValue: From<<T as ops::BitXor>::Output> + TryInto<T, Error>, T: ops::BitXor<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -666,7 +668,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_shl<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_shl<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<<T as ops::Shl<T>>::Output> + TryInto<T, Error>, T: ops::Shl<T> { where RuntimeValue: From<<T as ops::Shl<T>>::Output> + TryInto<T, Error>, T: ops::Shl<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -676,7 +678,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_shr<T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_shr<'a, T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U>, U: ops::Shr<U>, <U as ops::Shr<U>>::Output: TransmuteInto<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U>, U: ops::Shr<U>, <U as ops::Shr<U>>::Output: TransmuteInto<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -688,7 +690,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_rotl<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_rotl<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -698,7 +700,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_rotr<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_rotr<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -708,7 +710,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_abs<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_abs<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -718,7 +720,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_neg<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_neg<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<<T as ops::Neg>::Output> + TryInto<T, Error>, T: ops::Neg { where RuntimeValue: From<<T as ops::Neg>::Output> + TryInto<T, Error>, T: ops::Neg {
context context
.value_stack_mut() .value_stack_mut()
@ -728,7 +730,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_ceil<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_ceil<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -738,7 +740,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_floor<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_floor<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -748,7 +750,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_trunc<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_trunc<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -758,7 +760,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_nearest<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_nearest<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -768,7 +770,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_sqrt<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_sqrt<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -778,7 +780,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_min<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_min<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -788,7 +790,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_max<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_max<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -798,7 +800,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_copysign<T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_copysign<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> { where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
context context
.value_stack_mut() .value_stack_mut()
@ -808,7 +810,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_wrap<T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_wrap<'a, T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<U> + TryInto<T, Error>, T: WrapInto<U> { where RuntimeValue: From<U> + TryInto<T, Error>, T: WrapInto<U> {
context context
.value_stack_mut() .value_stack_mut()
@ -818,7 +820,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_trunc_to_int<T, U, V>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_trunc_to_int<'a, T, U, V>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<V> + TryInto<T, Error>, T: TryTruncateInto<U, Error>, U: TransmuteInto<V>, { where RuntimeValue: From<V> + TryInto<T, Error>, T: TryTruncateInto<U, Error>, U: TransmuteInto<V>, {
context context
.value_stack_mut() .value_stack_mut()
@ -829,7 +831,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_extend<T, U, V>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_extend<'a, T, U, V>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<V> + TryInto<T, Error>, T: ExtendInto<U>, U: TransmuteInto<V> { where RuntimeValue: From<V> + TryInto<T, Error>, T: ExtendInto<U>, U: TransmuteInto<V> {
context context
.value_stack_mut() .value_stack_mut()
@ -840,7 +842,7 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn run_reinterpret<T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_reinterpret<'a, T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
where RuntimeValue: From<U>, RuntimeValue: TryInto<T, Error>, T: TransmuteInto<U> { where RuntimeValue: From<U>, RuntimeValue: TryInto<T, Error>, T: TransmuteInto<U> {
context context
.value_stack_mut() .value_stack_mut()
@ -850,10 +852,11 @@ impl Interpreter {
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
} }
fn execute_block(context: &mut FunctionContext, body: &[Opcode]) -> Result<InstructionOutcome, Error> { fn execute_block<'a>(context: &mut FunctionContext, mut body: &[Opcode]) -> Result<InstructionOutcome<'a>, Error> {
debug_assert!(!context.frame_stack.is_empty()); debug_assert!(!context.frame_stack.is_empty());
// run instructions // run instructions
let mut block_stack = VecDeque::new();
context.position = 0; context.position = 0;
loop { loop {
let instruction = &body[context.position]; let instruction = &body[context.position];
@ -862,20 +865,33 @@ impl Interpreter {
match Interpreter::run_instruction(context, instruction)? { match Interpreter::run_instruction(context, instruction)? {
InstructionOutcome::RunInstruction => (), InstructionOutcome::RunInstruction => (),
InstructionOutcome::RunNextInstruction => context.position += 1, InstructionOutcome::RunNextInstruction => context.position += 1,
InstructionOutcome::Branch(index) => { InstructionOutcome::Branch(mut index) => {
if index != 0 { while index >= 1 {
context.discard_frame()?; context.discard_frame()?;
return Ok(InstructionOutcome::Branch(index - 1)); // there is block in block stack for each frame in context
} else { assert!(block_stack.pop_back().is_some());
context.pop_frame(true)?; index -= 1;
return Ok(InstructionOutcome::RunInstruction);
} }
body = match block_stack.pop_back() {
Some(body) => body,
None => return Ok(InstructionOutcome::Return),
};
context.pop_frame(true)?;
}, },
InstructionOutcome::End => { InstructionOutcome::End => {
body = match block_stack.pop_back() {
Some(body) => body,
None => return Ok(InstructionOutcome::Return),
};
context.pop_frame(false)?; context.pop_frame(false)?;
return Ok(InstructionOutcome::RunInstruction);
}, },
InstructionOutcome::Return => return Ok(InstructionOutcome::Return), InstructionOutcome::Return => return Ok(InstructionOutcome::Return),
InstructionOutcome::ExecuteBlock(new_body) => {
block_stack.push_back(body);
body = new_body;
context.position = 0;
},
} }
} }
} }

View File

@ -1,4 +1,5 @@
use std::u32; use std::u32;
use std::collections::VecDeque;
use elements::{Module, Opcode, BlockType, FunctionType, ValueType, External, Type}; use elements::{Module, Opcode, BlockType, FunctionType, ValueType, External, Type};
use interpreter::Error; use interpreter::Error;
use interpreter::runner::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; use interpreter::runner::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX};
@ -53,39 +54,91 @@ pub struct Validator;
/// Instruction outcome. /// Instruction outcome.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum InstructionOutcome { pub enum InstructionOutcome<'a> {
/// Continue with next instruction. /// Continue with next instruction.
RunNextInstruction, ValidateNextInstruction,
/// Unreachable instruction reached. /// Unreachable instruction reached.
Unreachable, Unreachable,
/// Validate block.
ValidateBlock(bool, BlockType, &'a [Opcode]),
/// Validate 2 blocks.
ValidateBlock2(bool, BlockType, &'a [Opcode], &'a [Opcode]),
} }
impl Validator { impl Validator {
pub fn validate_block(context: &mut FunctionValidationContext, is_loop: bool, block_type: BlockType, body: &[Opcode], end_instr: Opcode) -> Result<InstructionOutcome, Error> { pub fn validate_function(context: &mut FunctionValidationContext, block_type: BlockType, body: &[Opcode]) -> Result<(), Error> {
if body.is_empty() || body[body.len() - 1] != end_instr { context.push_label(false, block_type)?;
return Err(Error::Validation("Every block must end with end/else instruction".into())); Validator::validate_block(context, body)?;
while !context.frame_stack.is_empty() {
context.pop_label()?;
} }
context.push_label(is_loop, block_type)?; Ok(())
for opcode in body { }
fn validate_block<'a>(context: &mut FunctionValidationContext, mut body: &[Opcode]) -> Result<InstructionOutcome<'a>, Error> {
let mut block_stack = VecDeque::new();
let mut position = 0;
loop {
let opcode = if position < body.len() {
&body[position]
} else {
let body_and_position = match block_stack.pop_back() {
Some((new_body, new_position, need_pop_value)) => (new_body, new_position, need_pop_value),
None => return Ok(InstructionOutcome::ValidateNextInstruction),
};
context.pop_label()?;
if body_and_position.2 {
context.pop_any_value()?;
}
body = body_and_position.0;
position = body_and_position.1;
continue;
};
match Validator::validate_instruction(context, opcode)? { match Validator::validate_instruction(context, opcode)? {
InstructionOutcome::RunNextInstruction => (), InstructionOutcome::ValidateNextInstruction => position += 1,
InstructionOutcome::Unreachable => context.unreachable()?, InstructionOutcome::Unreachable => {
context.unreachable()?;
position += 1;
},
InstructionOutcome::ValidateBlock(is_loop, block_type, new_body) => {
context.push_label(is_loop, block_type)?;
block_stack.push_back((body, position + 1, false));
body = new_body;
position = 0;
},
InstructionOutcome::ValidateBlock2(is_loop, block_type, new_body, new_body2) => {
let need_pop_value = match block_type {
BlockType::NoResult => false,
BlockType::Value(_) => true,
};
context.push_label(is_loop, block_type)?;
context.push_label(is_loop, block_type)?;
block_stack.push_back((body, position + 1, false));
block_stack.push_back((new_body2, 0, need_pop_value));
body = new_body;
position = 0;
},
} }
} }
context.pop_label()
} }
pub fn validate_instruction(context: &mut FunctionValidationContext, opcode: &Opcode) -> Result<InstructionOutcome, Error> { pub fn validate_instruction<'a>(context: &mut FunctionValidationContext, opcode: &'a Opcode) -> Result<InstructionOutcome<'a>, Error> {
// println!("=== VALIDATING {:?}: {:?}", opcode, context.value_stack); // println!("=== VALIDATING {:?}: {:?}", opcode, context.value_stack);
match opcode { match opcode {
&Opcode::Unreachable => Ok(InstructionOutcome::Unreachable), &Opcode::Unreachable => Ok(InstructionOutcome::Unreachable),
&Opcode::Nop => Ok(InstructionOutcome::RunNextInstruction), &Opcode::Nop => Ok(InstructionOutcome::ValidateNextInstruction),
&Opcode::Block(block_type, ref ops) => Validator::validate_block(context, false, block_type, ops.elements(), Opcode::End), &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::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::If(block_type, ref ops) => Validator::validate_if(context, block_type, ops.elements()),
&Opcode::Else => Ok(InstructionOutcome::RunNextInstruction), &Opcode::Else => Ok(InstructionOutcome::ValidateNextInstruction),
&Opcode::End => Ok(InstructionOutcome::RunNextInstruction), &Opcode::End => Ok(InstructionOutcome::ValidateNextInstruction),
&Opcode::Br(idx) => Validator::validate_br(context, idx), &Opcode::Br(idx) => Validator::validate_br(context, idx),
&Opcode::BrIf(idx) => Validator::validate_br_if(context, idx), &Opcode::BrIf(idx) => Validator::validate_br_if(context, idx),
&Opcode::BrTable(ref table, default) => Validator::validate_br_table(context, table, default), &Opcode::BrTable(ref table, default) => Validator::validate_br_table(context, table, default),
@ -271,96 +324,96 @@ impl Validator {
} }
} }
fn validate_const(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result<InstructionOutcome, Error> { fn validate_const<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result<InstructionOutcome<'a>, Error> {
context.push_value(value_type)?; context.push_value(value_type)?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_unop(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result<InstructionOutcome, Error> { fn validate_unop<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result<InstructionOutcome<'a>, Error> {
context.pop_value(value_type)?; context.pop_value(value_type)?;
context.push_value(value_type)?; context.push_value(value_type)?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_binop(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result<InstructionOutcome, Error> { fn validate_binop<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result<InstructionOutcome<'a>, Error> {
context.pop_value(value_type)?; context.pop_value(value_type)?;
context.pop_value(value_type)?; context.pop_value(value_type)?;
context.push_value(value_type)?; context.push_value(value_type)?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_testop(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result<InstructionOutcome, Error> { fn validate_testop<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result<InstructionOutcome<'a>, Error> {
context.pop_value(value_type)?; context.pop_value(value_type)?;
context.push_value(ValueType::I32.into())?; context.push_value(ValueType::I32.into())?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_relop(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result<InstructionOutcome, Error> { fn validate_relop<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result<InstructionOutcome<'a>, Error> {
context.pop_value(value_type)?; context.pop_value(value_type)?;
context.pop_value(value_type)?; context.pop_value(value_type)?;
context.push_value(ValueType::I32.into())?; context.push_value(ValueType::I32.into())?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_cvtop(context: &mut FunctionValidationContext, value_type1: StackValueType, value_type2: StackValueType) -> Result<InstructionOutcome, Error> { fn validate_cvtop<'a>(context: &mut FunctionValidationContext, value_type1: StackValueType, value_type2: StackValueType) -> Result<InstructionOutcome<'a>, Error> {
context.pop_value(value_type1)?; context.pop_value(value_type1)?;
context.push_value(value_type2)?; context.push_value(value_type2)?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_drop(context: &mut FunctionValidationContext) -> Result<InstructionOutcome, Error> { fn validate_drop<'a>(context: &mut FunctionValidationContext) -> Result<InstructionOutcome<'a>, Error> {
context.pop_any_value().map(|_| ())?; context.pop_any_value().map(|_| ())?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_select(context: &mut FunctionValidationContext) -> Result<InstructionOutcome, Error> { fn validate_select<'a>(context: &mut FunctionValidationContext) -> Result<InstructionOutcome<'a>, Error> {
context.pop_value(ValueType::I32.into())?; context.pop_value(ValueType::I32.into())?;
let select_type = context.pop_any_value()?; let select_type = context.pop_any_value()?;
context.pop_value(select_type)?; context.pop_value(select_type)?;
context.push_value(select_type)?; context.push_value(select_type)?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_get_local(context: &mut FunctionValidationContext, index: u32) -> Result<InstructionOutcome, Error> { fn validate_get_local<'a>(context: &mut FunctionValidationContext, index: u32) -> Result<InstructionOutcome<'a>, Error> {
let local_type = context.require_local(index)?; let local_type = context.require_local(index)?;
context.push_value(local_type)?; context.push_value(local_type)?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_set_local(context: &mut FunctionValidationContext, index: u32) -> Result<InstructionOutcome, Error> { fn validate_set_local<'a>(context: &mut FunctionValidationContext, index: u32) -> Result<InstructionOutcome<'a>, Error> {
let local_type = context.require_local(index)?; let local_type = context.require_local(index)?;
let value_type = context.pop_any_value()?; let value_type = context.pop_any_value()?;
if local_type != value_type { if local_type != value_type {
return Err(Error::Validation(format!("Trying to update local {} of type {:?} with value of type {:?}", index, local_type, value_type))); return Err(Error::Validation(format!("Trying to update local {} of type {:?} with value of type {:?}", index, local_type, value_type)));
} }
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_tee_local(context: &mut FunctionValidationContext, index: u32) -> Result<InstructionOutcome, Error> { fn validate_tee_local<'a>(context: &mut FunctionValidationContext, index: u32) -> Result<InstructionOutcome<'a>, Error> {
let local_type = context.require_local(index)?; let local_type = context.require_local(index)?;
let value_type = context.tee_any_value()?; let value_type = context.tee_any_value()?;
if local_type != value_type { if local_type != value_type {
return Err(Error::Validation(format!("Trying to update local {} of type {:?} with value of type {:?}", index, local_type, value_type))); return Err(Error::Validation(format!("Trying to update local {} of type {:?} with value of type {:?}", index, local_type, value_type)));
} }
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_get_global(context: &mut FunctionValidationContext, index: u32) -> Result<InstructionOutcome, Error> { fn validate_get_global<'a>(context: &mut FunctionValidationContext, index: u32) -> Result<InstructionOutcome<'a>, Error> {
let global_type = context.require_global(index, None)?; let global_type = context.require_global(index, None)?;
context.push_value(global_type)?; context.push_value(global_type)?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_set_global(context: &mut FunctionValidationContext, index: u32) -> Result<InstructionOutcome, Error> { fn validate_set_global<'a>(context: &mut FunctionValidationContext, index: u32) -> Result<InstructionOutcome<'a>, Error> {
let global_type = context.require_global(index, Some(true))?; let global_type = context.require_global(index, Some(true))?;
let value_type = context.pop_any_value()?; let value_type = context.pop_any_value()?;
if global_type != value_type { if global_type != value_type {
return Err(Error::Validation(format!("Trying to update global {} of type {:?} with value of type {:?}", index, global_type, value_type))); return Err(Error::Validation(format!("Trying to update global {} of type {:?} with value of type {:?}", index, global_type, value_type)));
} }
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_load(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: StackValueType) -> Result<InstructionOutcome, Error> { fn validate_load<'a>(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: StackValueType) -> Result<InstructionOutcome<'a>, Error> {
if align != NATURAL_ALIGNMENT { if align != NATURAL_ALIGNMENT {
if 1u32.checked_shl(align).unwrap_or(u32::MAX) > max_align { 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))); return Err(Error::Validation(format!("Too large memory alignment 2^{} (expected at most {})", align, max_align)));
@ -370,10 +423,10 @@ impl Validator {
context.pop_value(ValueType::I32.into())?; context.pop_value(ValueType::I32.into())?;
context.require_memory(DEFAULT_MEMORY_INDEX)?; context.require_memory(DEFAULT_MEMORY_INDEX)?;
context.push_value(value_type)?; context.push_value(value_type)?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_store(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: StackValueType) -> Result<InstructionOutcome, Error> { fn validate_store<'a>(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: StackValueType) -> Result<InstructionOutcome<'a>, Error> {
if align != NATURAL_ALIGNMENT { if align != NATURAL_ALIGNMENT {
if 1u32.checked_shl(align).unwrap_or(u32::MAX) > max_align { 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))); return Err(Error::Validation(format!("Too large memory alignment 2^{} (expected at most {})", align, max_align)));
@ -383,14 +436,14 @@ impl Validator {
context.require_memory(DEFAULT_MEMORY_INDEX)?; context.require_memory(DEFAULT_MEMORY_INDEX)?;
context.pop_value(value_type)?; context.pop_value(value_type)?;
context.pop_value(ValueType::I32.into())?; context.pop_value(ValueType::I32.into())?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_loop(context: &mut FunctionValidationContext, block_type: BlockType, body: &[Opcode]) -> Result<InstructionOutcome, Error> { fn validate_loop<'a>(_context: &mut FunctionValidationContext, block_type: BlockType, body: &'a [Opcode]) -> Result<InstructionOutcome<'a>, Error> {
Validator::validate_block(context, true, block_type, body, Opcode::End) Validator::schedule_validate_block(true, block_type, body, Opcode::End)
} }
fn validate_if(context: &mut FunctionValidationContext, block_type: BlockType, body: &[Opcode]) -> Result<InstructionOutcome, Error> { fn validate_if<'a>(context: &mut FunctionValidationContext, block_type: BlockType, body: &'a [Opcode]) -> Result<InstructionOutcome<'a>, Error> {
context.pop_value(ValueType::I32.into())?; context.pop_value(ValueType::I32.into())?;
let body_len = body.len(); let body_len = body.len();
@ -398,18 +451,17 @@ impl Validator {
.position(|op| *op == Opcode::Else) .position(|op| *op == Opcode::Else)
.unwrap_or(body_len - 1); .unwrap_or(body_len - 1);
if separator_index != body_len - 1 { if separator_index != body_len - 1 {
Validator::validate_block(context, false, block_type, &body[..separator_index + 1], Opcode::Else)?; Validator::schedule_validate_block2(false, block_type, &body[..separator_index + 1], Opcode::Else, &body[separator_index+1..], Opcode::End)
Validator::validate_block(context, false, block_type, &body[separator_index+1..], Opcode::End)
} else { } else {
if block_type != BlockType::NoResult { 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))); return Err(Error::Validation(format!("If block without else required to have NoResult block type. But it have {:?} type", block_type)));
} }
Validator::validate_block(context, false, block_type, body, Opcode::End) Validator::schedule_validate_block(false, block_type, body, Opcode::End)
} }
} }
fn validate_br(context: &mut FunctionValidationContext, idx: u32) -> Result<InstructionOutcome, Error> { fn validate_br<'a>(context: &mut FunctionValidationContext, idx: u32) -> Result<InstructionOutcome<'a>, Error> {
let (frame_is_loop, frame_block_type) = { let (frame_is_loop, frame_block_type) = {
let frame = context.require_label(idx)?; let frame = context.require_label(idx)?;
(frame.is_loop, frame.block_type) (frame.is_loop, frame.block_type)
@ -423,15 +475,15 @@ impl Validator {
Ok(InstructionOutcome::Unreachable) Ok(InstructionOutcome::Unreachable)
} }
fn validate_br_if(context: &mut FunctionValidationContext, idx: u32) -> Result<InstructionOutcome, Error> { fn validate_br_if<'a>(context: &mut FunctionValidationContext, idx: u32) -> Result<InstructionOutcome<'a>, Error> {
context.pop_value(ValueType::I32.into())?; context.pop_value(ValueType::I32.into())?;
if let BlockType::Value(value_type) = context.require_label(idx)?.block_type { if let BlockType::Value(value_type) = context.require_label(idx)?.block_type {
context.tee_value(value_type.into())?; context.tee_value(value_type.into())?;
} }
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_br_table(context: &mut FunctionValidationContext, table: &Vec<u32>, default: u32) -> Result<InstructionOutcome, Error> { fn validate_br_table<'a>(context: &mut FunctionValidationContext, table: &Vec<u32>, default: u32) -> Result<InstructionOutcome<'a>, Error> {
let mut required_block_type = None; let mut required_block_type = None;
{ {
@ -463,14 +515,14 @@ impl Validator {
Ok(InstructionOutcome::Unreachable) Ok(InstructionOutcome::Unreachable)
} }
fn validate_return(context: &mut FunctionValidationContext) -> Result<InstructionOutcome, Error> { fn validate_return<'a>(context: &mut FunctionValidationContext) -> Result<InstructionOutcome<'a>, Error> {
if let BlockType::Value(value_type) = context.return_type()? { if let BlockType::Value(value_type) = context.return_type()? {
context.tee_value(value_type.into())?; context.tee_value(value_type.into())?;
} }
Ok(InstructionOutcome::Unreachable) Ok(InstructionOutcome::Unreachable)
} }
fn validate_call(context: &mut FunctionValidationContext, idx: u32) -> Result<InstructionOutcome, Error> { fn validate_call<'a>(context: &mut FunctionValidationContext, idx: u32) -> Result<InstructionOutcome<'a>, Error> {
let (argument_types, return_type) = context.require_function(idx)?; let (argument_types, return_type) = context.require_function(idx)?;
for argument_type in argument_types.iter().rev() { for argument_type in argument_types.iter().rev() {
context.pop_value((*argument_type).into())?; context.pop_value((*argument_type).into())?;
@ -478,10 +530,10 @@ impl Validator {
if let BlockType::Value(value_type) = return_type { if let BlockType::Value(value_type) = return_type {
context.push_value(value_type.into())?; context.push_value(value_type.into())?;
} }
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_call_indirect(context: &mut FunctionValidationContext, idx: u32) -> Result<InstructionOutcome, Error> { fn validate_call_indirect<'a>(context: &mut FunctionValidationContext, idx: u32) -> Result<InstructionOutcome<'a>, Error> {
context.require_table(DEFAULT_TABLE_INDEX, VariableType::AnyFunc)?; context.require_table(DEFAULT_TABLE_INDEX, VariableType::AnyFunc)?;
context.pop_value(ValueType::I32.into())?; context.pop_value(ValueType::I32.into())?;
@ -492,20 +544,39 @@ impl Validator {
if let BlockType::Value(value_type) = return_type { if let BlockType::Value(value_type) = return_type {
context.push_value(value_type.into())?; context.push_value(value_type.into())?;
} }
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_current_memory(context: &mut FunctionValidationContext) -> Result<InstructionOutcome, Error> { fn validate_current_memory<'a>(context: &mut FunctionValidationContext) -> Result<InstructionOutcome<'a>, Error> {
context.require_memory(DEFAULT_MEMORY_INDEX)?; context.require_memory(DEFAULT_MEMORY_INDEX)?;
context.push_value(ValueType::I32.into())?; context.push_value(ValueType::I32.into())?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
fn validate_grow_memory(context: &mut FunctionValidationContext) -> Result<InstructionOutcome, Error> { fn validate_grow_memory<'a>(context: &mut FunctionValidationContext) -> Result<InstructionOutcome<'a>, Error> {
context.require_memory(DEFAULT_MEMORY_INDEX)?; context.require_memory(DEFAULT_MEMORY_INDEX)?;
context.pop_value(ValueType::I32.into())?; context.pop_value(ValueType::I32.into())?;
context.push_value(ValueType::I32.into())?; context.push_value(ValueType::I32.into())?;
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
}
fn schedule_validate_block<'a>(is_loop: bool, block_type: BlockType, body: &'a [Opcode], end_instr: Opcode) -> Result<InstructionOutcome<'a>, Error> {
if body.is_empty() || body[body.len() - 1] != end_instr {
return Err(Error::Validation("Every block must end with end/else instruction".into()));
}
Ok(InstructionOutcome::ValidateBlock(is_loop, block_type, body))
}
fn schedule_validate_block2<'a>(is_loop: bool, block_type: BlockType, body: &'a [Opcode], end_instr: Opcode, body2: &'a [Opcode], end_instr2: Opcode) -> Result<InstructionOutcome<'a>, Error> {
if body.is_empty() || body[body.len() - 1] != end_instr {
return Err(Error::Validation("Every block must end with end/else instruction".into()));
}
if body2.is_empty() || body2[body2.len() - 1] != end_instr2 {
return Err(Error::Validation("Every block must end with end/else instruction".into()));
}
Ok(InstructionOutcome::ValidateBlock2(is_loop, block_type, body, body2))
} }
} }
@ -594,7 +665,7 @@ impl<'a> FunctionValidationContext<'a> {
self.push_value(value_type.into())?; self.push_value(value_type.into())?;
} }
Ok(InstructionOutcome::RunNextInstruction) Ok(InstructionOutcome::ValidateNextInstruction)
} }
pub fn require_label(&self, idx: u32) -> Result<&ValidationFrame, Error> { pub fn require_label(&self, idx: u32) -> Result<&ValidationFrame, Error> {