mirror of
https://github.com/fluencelabs/parity-wasm
synced 2025-06-24 12:12:05 +00:00
get rid of block-level recursion
This commit is contained in:
@ -314,7 +314,7 @@ impl ModuleInstanceInterface for ModuleInstance {
|
||||
locals.extend(function_body.locals().iter().flat_map(|l| repeat(l.value_type()).take(l.count() as usize)));
|
||||
let mut context = FunctionValidationContext::new(&self.module, &self.imports, &locals, DEFAULT_VALUE_STACK_LIMIT, DEFAULT_FRAME_STACK_LIMIT, &function_type);
|
||||
let block_type = function_type.return_type().map(BlockType::Value).unwrap_or(BlockType::NoResult);
|
||||
Validator::validate_block(&mut context, false, block_type, function_body.code().elements(), Opcode::End)?;
|
||||
Validator::validate_function(&mut context, block_type, function_body.code().elements())?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ use std::ops;
|
||||
use std::u32;
|
||||
use std::sync::Arc;
|
||||
use std::fmt::Display;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use elements::{Opcode, BlockType, FunctionType};
|
||||
use interpreter::Error;
|
||||
use interpreter::module::{ModuleInstance, ModuleInstanceInterface, CallerContext, ItemIndex};
|
||||
@ -41,7 +41,7 @@ pub struct FunctionContext<'a> {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum InstructionOutcome {
|
||||
pub enum InstructionOutcome<'a> {
|
||||
/// Continue with current instruction.
|
||||
RunInstruction,
|
||||
/// Continue with next instruction.
|
||||
@ -52,6 +52,8 @@ pub enum InstructionOutcome {
|
||||
End,
|
||||
/// Return from current function block.
|
||||
Return,
|
||||
/// Execute block.
|
||||
ExecuteBlock(&'a [Opcode]),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -80,7 +82,7 @@ impl Interpreter {
|
||||
}
|
||||
}
|
||||
|
||||
fn run_instruction(context: &mut FunctionContext, opcode: &Opcode) -> Result<InstructionOutcome, Error> {
|
||||
fn run_instruction<'a>(context: &mut FunctionContext, opcode: &'a Opcode) -> Result<InstructionOutcome<'a>, Error> {
|
||||
match opcode {
|
||||
&Opcode::Unreachable => Interpreter::run_unreachable(context),
|
||||
&Opcode::Nop => Interpreter::run_nop(context),
|
||||
@ -274,27 +276,27 @@ impl Interpreter {
|
||||
}
|
||||
}
|
||||
|
||||
fn run_unreachable(_context: &mut FunctionContext) -> Result<InstructionOutcome, Error> {
|
||||
fn run_unreachable<'a>(_context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
|
||||
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)
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
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 else_index = body.iter().position(|op| *op == Opcode::Else).unwrap_or(body_len - 1);
|
||||
let (begin_index, end_index) = if context.value_stack_mut().pop_as()? {
|
||||
@ -306,25 +308,25 @@ impl Interpreter {
|
||||
if begin_index != end_index {
|
||||
let frame_position = context.position + 1;
|
||||
context.push_frame(false, frame_position, frame_position, block_type.clone())?;
|
||||
Interpreter::execute_block(context, &body[begin_index..end_index])
|
||||
Ok(InstructionOutcome::ExecuteBlock(&body[begin_index..end_index]))
|
||||
} else {
|
||||
Ok(InstructionOutcome::RunNextInstruction)
|
||||
}
|
||||
}
|
||||
|
||||
fn run_else(_context: &mut FunctionContext) -> Result<InstructionOutcome, Error> {
|
||||
fn run_else<'a>(_context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
|
||||
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)
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
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()? {
|
||||
Ok(InstructionOutcome::Branch(label_idx as usize))
|
||||
} 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()?;
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
.and_then(|r| r.map(|r| context.value_stack_mut().push(r)).unwrap_or(Ok(())))
|
||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||
}
|
||||
|
||||
fn run_call_indirect(context: &mut FunctionContext, type_idx: u32) -> Result<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()?;
|
||||
context.call_function_indirect(DEFAULT_TABLE_INDEX, type_idx, table_func_idx)
|
||||
.and_then(|r| r.map(|r| context.value_stack_mut().push(r)).unwrap_or(Ok(())))
|
||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||
}
|
||||
|
||||
fn run_drop(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> {
|
||||
fn run_drop<'a>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
.pop()
|
||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||
}
|
||||
|
||||
fn run_select(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> {
|
||||
fn run_select<'a>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
.pop_triple()
|
||||
@ -376,32 +378,32 @@ impl Interpreter {
|
||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||
}
|
||||
|
||||
fn run_get_local(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Error> {
|
||||
fn run_get_local<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome<'a>, Error> {
|
||||
context.get_local(index as usize)
|
||||
.map(|value| context.value_stack_mut().push(value))
|
||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||
}
|
||||
|
||||
fn run_set_local(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Error> {
|
||||
fn run_set_local<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome<'a>, Error> {
|
||||
let arg = context.value_stack_mut().pop()?;
|
||||
context.set_local(index as usize, arg)
|
||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||
}
|
||||
|
||||
fn run_tee_local(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Error> {
|
||||
fn run_tee_local<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome<'a>, Error> {
|
||||
let arg = context.value_stack().top()?.clone();
|
||||
context.set_local(index as usize, arg)
|
||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||
}
|
||||
|
||||
fn run_get_global(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Error> {
|
||||
fn run_get_global<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome<'a>, Error> {
|
||||
context.module()
|
||||
.global(ItemIndex::IndexSpace(index), None)
|
||||
.and_then(|g| context.value_stack_mut().push(g.get()))
|
||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||
}
|
||||
|
||||
fn run_set_global(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Error> {
|
||||
fn run_set_global<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome<'a>, Error> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
.pop()
|
||||
@ -409,7 +411,7 @@ impl Interpreter {
|
||||
.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 {
|
||||
let address = effective_address(offset, context.value_stack_mut().pop_as()?)?;
|
||||
context.module()
|
||||
@ -420,7 +422,7 @@ impl Interpreter {
|
||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||
}
|
||||
|
||||
fn run_load_extend<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 {
|
||||
let address = effective_address(offset, context.value_stack_mut().pop_as()?)?;
|
||||
let stack_value: U = context.module()
|
||||
@ -434,7 +436,7 @@ impl Interpreter {
|
||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||
}
|
||||
|
||||
fn run_store<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 {
|
||||
let stack_value = context
|
||||
.value_stack_mut()
|
||||
@ -447,7 +449,7 @@ impl Interpreter {
|
||||
.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 {
|
||||
let stack_value: T = context.value_stack_mut().pop().and_then(|v| v.try_into())?;
|
||||
let stack_value = stack_value.wrap_into().into_little_endian();
|
||||
@ -458,7 +460,7 @@ impl Interpreter {
|
||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||
}
|
||||
|
||||
fn run_current_memory(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> {
|
||||
fn run_current_memory<'a>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
|
||||
context.module()
|
||||
.memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX))
|
||||
.map(|m| m.size())
|
||||
@ -466,7 +468,7 @@ impl Interpreter {
|
||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||
}
|
||||
|
||||
fn run_grow_memory(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> {
|
||||
fn run_grow_memory<'a>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
|
||||
let pages: u32 = context.value_stack_mut().pop_as()?;
|
||||
context.module()
|
||||
.memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX))
|
||||
@ -475,14 +477,14 @@ impl Interpreter {
|
||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||
}
|
||||
|
||||
fn run_const(context: &mut FunctionContext, val: RuntimeValue) -> Result<InstructionOutcome, Error> {
|
||||
fn run_const<'a>(context: &mut FunctionContext, val: RuntimeValue) -> Result<InstructionOutcome<'a>, Error> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
.push(val)
|
||||
.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 {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -492,7 +494,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -502,7 +504,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -512,7 +514,7 @@ impl Interpreter {
|
||||
.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 {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -522,7 +524,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -532,7 +534,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -542,7 +544,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -552,7 +554,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -562,7 +564,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -572,7 +574,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -582,7 +584,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -592,7 +594,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -602,7 +604,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -612,7 +614,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -624,7 +626,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -636,7 +638,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -646,7 +648,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -656,7 +658,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -666,7 +668,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -676,7 +678,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -688,7 +690,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -698,7 +700,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -708,7 +710,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -718,7 +720,7 @@ impl Interpreter {
|
||||
.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 {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -728,7 +730,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -738,7 +740,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -748,7 +750,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -758,7 +760,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -768,7 +770,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -778,7 +780,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -788,7 +790,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -798,7 +800,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -808,7 +810,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -818,7 +820,7 @@ impl Interpreter {
|
||||
.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>, {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -829,7 +831,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -840,7 +842,7 @@ impl Interpreter {
|
||||
.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> {
|
||||
context
|
||||
.value_stack_mut()
|
||||
@ -850,10 +852,11 @@ impl Interpreter {
|
||||
.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());
|
||||
|
||||
// run instructions
|
||||
let mut block_stack = VecDeque::new();
|
||||
context.position = 0;
|
||||
loop {
|
||||
let instruction = &body[context.position];
|
||||
@ -862,20 +865,33 @@ impl Interpreter {
|
||||
match Interpreter::run_instruction(context, instruction)? {
|
||||
InstructionOutcome::RunInstruction => (),
|
||||
InstructionOutcome::RunNextInstruction => context.position += 1,
|
||||
InstructionOutcome::Branch(index) => {
|
||||
if index != 0 {
|
||||
InstructionOutcome::Branch(mut index) => {
|
||||
while index >= 1 {
|
||||
context.discard_frame()?;
|
||||
return Ok(InstructionOutcome::Branch(index - 1));
|
||||
} else {
|
||||
context.pop_frame(true)?;
|
||||
return Ok(InstructionOutcome::RunInstruction);
|
||||
// there is block in block stack for each frame in context
|
||||
assert!(block_stack.pop_back().is_some());
|
||||
index -= 1;
|
||||
}
|
||||
|
||||
body = match block_stack.pop_back() {
|
||||
Some(body) => body,
|
||||
None => return Ok(InstructionOutcome::Return),
|
||||
};
|
||||
context.pop_frame(true)?;
|
||||
},
|
||||
InstructionOutcome::End => {
|
||||
body = match block_stack.pop_back() {
|
||||
Some(body) => body,
|
||||
None => return Ok(InstructionOutcome::Return),
|
||||
};
|
||||
context.pop_frame(false)?;
|
||||
return Ok(InstructionOutcome::RunInstruction);
|
||||
},
|
||||
InstructionOutcome::Return => return Ok(InstructionOutcome::Return),
|
||||
InstructionOutcome::ExecuteBlock(new_body) => {
|
||||
block_stack.push_back(body);
|
||||
body = new_body;
|
||||
context.position = 0;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use std::u32;
|
||||
use std::collections::VecDeque;
|
||||
use elements::{Module, Opcode, BlockType, FunctionType, ValueType, External, Type};
|
||||
use interpreter::Error;
|
||||
use interpreter::runner::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX};
|
||||
@ -53,39 +54,91 @@ pub struct Validator;
|
||||
|
||||
/// Instruction outcome.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum InstructionOutcome {
|
||||
pub enum InstructionOutcome<'a> {
|
||||
/// Continue with next instruction.
|
||||
RunNextInstruction,
|
||||
ValidateNextInstruction,
|
||||
/// Unreachable instruction reached.
|
||||
Unreachable,
|
||||
/// Validate block.
|
||||
ValidateBlock(bool, BlockType, &'a [Opcode]),
|
||||
/// Validate 2 blocks.
|
||||
ValidateBlock2(bool, BlockType, &'a [Opcode], &'a [Opcode]),
|
||||
}
|
||||
|
||||
impl Validator {
|
||||
pub fn validate_block(context: &mut FunctionValidationContext, is_loop: bool, block_type: BlockType, body: &[Opcode], end_instr: Opcode) -> Result<InstructionOutcome, Error> {
|
||||
if body.is_empty() || body[body.len() - 1] != end_instr {
|
||||
return Err(Error::Validation("Every block must end with end/else instruction".into()));
|
||||
pub fn validate_function(context: &mut FunctionValidationContext, block_type: BlockType, body: &[Opcode]) -> Result<(), Error> {
|
||||
context.push_label(false, block_type)?;
|
||||
Validator::validate_block(context, body)?;
|
||||
while !context.frame_stack.is_empty() {
|
||||
context.pop_label()?;
|
||||
}
|
||||
|
||||
context.push_label(is_loop, block_type)?;
|
||||
for opcode in body {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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)? {
|
||||
InstructionOutcome::RunNextInstruction => (),
|
||||
InstructionOutcome::Unreachable => context.unreachable()?,
|
||||
InstructionOutcome::ValidateNextInstruction => position += 1,
|
||||
InstructionOutcome::Unreachable => {
|
||||
context.unreachable()?;
|
||||
position += 1;
|
||||
},
|
||||
InstructionOutcome::ValidateBlock(is_loop, block_type, new_body) => {
|
||||
context.push_label(is_loop, block_type)?;
|
||||
block_stack.push_back((body, position + 1, false));
|
||||
|
||||
body = new_body;
|
||||
position = 0;
|
||||
},
|
||||
InstructionOutcome::ValidateBlock2(is_loop, block_type, new_body, new_body2) => {
|
||||
let need_pop_value = match block_type {
|
||||
BlockType::NoResult => false,
|
||||
BlockType::Value(_) => true,
|
||||
};
|
||||
context.push_label(is_loop, block_type)?;
|
||||
context.push_label(is_loop, block_type)?;
|
||||
block_stack.push_back((body, position + 1, false));
|
||||
block_stack.push_back((new_body2, 0, need_pop_value));
|
||||
|
||||
body = new_body;
|
||||
position = 0;
|
||||
},
|
||||
}
|
||||
}
|
||||
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);
|
||||
match opcode {
|
||||
&Opcode::Unreachable => Ok(InstructionOutcome::Unreachable),
|
||||
&Opcode::Nop => Ok(InstructionOutcome::RunNextInstruction),
|
||||
&Opcode::Block(block_type, ref ops) => Validator::validate_block(context, false, block_type, ops.elements(), Opcode::End),
|
||||
&Opcode::Nop => Ok(InstructionOutcome::ValidateNextInstruction),
|
||||
&Opcode::Block(block_type, ref ops) => Validator::schedule_validate_block(false, block_type, ops.elements(), Opcode::End),
|
||||
&Opcode::Loop(block_type, ref ops) => Validator::validate_loop(context, block_type, ops.elements()),
|
||||
&Opcode::If(block_type, ref ops) => Validator::validate_if(context, block_type, ops.elements()),
|
||||
&Opcode::Else => Ok(InstructionOutcome::RunNextInstruction),
|
||||
&Opcode::End => Ok(InstructionOutcome::RunNextInstruction),
|
||||
&Opcode::Else => Ok(InstructionOutcome::ValidateNextInstruction),
|
||||
&Opcode::End => Ok(InstructionOutcome::ValidateNextInstruction),
|
||||
&Opcode::Br(idx) => Validator::validate_br(context, idx),
|
||||
&Opcode::BrIf(idx) => Validator::validate_br_if(context, idx),
|
||||
&Opcode::BrTable(ref table, default) => Validator::validate_br_table(context, table, default),
|
||||
@ -271,96 +324,96 @@ impl Validator {
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_const(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result<InstructionOutcome, Error> {
|
||||
fn validate_const<'a>(context: &mut FunctionValidationContext, value_type: StackValueType) -> Result<InstructionOutcome<'a>, Error> {
|
||||
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.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.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.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.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.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(|_| ())?;
|
||||
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())?;
|
||||
let select_type = context.pop_any_value()?;
|
||||
context.pop_value(select_type)?;
|
||||
context.push_value(select_type)?;
|
||||
Ok(InstructionOutcome::RunNextInstruction)
|
||||
Ok(InstructionOutcome::ValidateNextInstruction)
|
||||
}
|
||||
|
||||
fn validate_get_local(context: &mut FunctionValidationContext, index: u32) -> Result<InstructionOutcome, Error> {
|
||||
fn validate_get_local<'a>(context: &mut FunctionValidationContext, index: u32) -> Result<InstructionOutcome<'a>, Error> {
|
||||
let local_type = context.require_local(index)?;
|
||||
context.push_value(local_type)?;
|
||||
Ok(InstructionOutcome::RunNextInstruction)
|
||||
Ok(InstructionOutcome::ValidateNextInstruction)
|
||||
}
|
||||
|
||||
fn validate_set_local(context: &mut FunctionValidationContext, index: u32) -> Result<InstructionOutcome, Error> {
|
||||
fn validate_set_local<'a>(context: &mut FunctionValidationContext, index: u32) -> Result<InstructionOutcome<'a>, Error> {
|
||||
let local_type = context.require_local(index)?;
|
||||
let value_type = context.pop_any_value()?;
|
||||
if local_type != value_type {
|
||||
return Err(Error::Validation(format!("Trying to update local {} of type {:?} with value of type {:?}", index, local_type, value_type)));
|
||||
}
|
||||
Ok(InstructionOutcome::RunNextInstruction)
|
||||
Ok(InstructionOutcome::ValidateNextInstruction)
|
||||
}
|
||||
|
||||
fn validate_tee_local(context: &mut FunctionValidationContext, index: u32) -> Result<InstructionOutcome, Error> {
|
||||
fn validate_tee_local<'a>(context: &mut FunctionValidationContext, index: u32) -> Result<InstructionOutcome<'a>, Error> {
|
||||
let local_type = context.require_local(index)?;
|
||||
let value_type = context.tee_any_value()?;
|
||||
if local_type != value_type {
|
||||
return Err(Error::Validation(format!("Trying to update local {} of type {:?} with value of type {:?}", index, local_type, value_type)));
|
||||
}
|
||||
Ok(InstructionOutcome::RunNextInstruction)
|
||||
Ok(InstructionOutcome::ValidateNextInstruction)
|
||||
}
|
||||
|
||||
fn validate_get_global(context: &mut FunctionValidationContext, index: u32) -> Result<InstructionOutcome, Error> {
|
||||
fn validate_get_global<'a>(context: &mut FunctionValidationContext, index: u32) -> Result<InstructionOutcome<'a>, Error> {
|
||||
let global_type = context.require_global(index, None)?;
|
||||
context.push_value(global_type)?;
|
||||
Ok(InstructionOutcome::RunNextInstruction)
|
||||
Ok(InstructionOutcome::ValidateNextInstruction)
|
||||
}
|
||||
|
||||
fn validate_set_global(context: &mut FunctionValidationContext, index: u32) -> Result<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 value_type = context.pop_any_value()?;
|
||||
if global_type != value_type {
|
||||
return Err(Error::Validation(format!("Trying to update global {} of type {:?} with value of type {:?}", index, global_type, value_type)));
|
||||
}
|
||||
Ok(InstructionOutcome::RunNextInstruction)
|
||||
Ok(InstructionOutcome::ValidateNextInstruction)
|
||||
}
|
||||
|
||||
fn validate_load(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: StackValueType) -> Result<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 1u32.checked_shl(align).unwrap_or(u32::MAX) > max_align {
|
||||
return Err(Error::Validation(format!("Too large memory alignment 2^{} (expected at most {})", align, max_align)));
|
||||
@ -370,10 +423,10 @@ impl Validator {
|
||||
context.pop_value(ValueType::I32.into())?;
|
||||
context.require_memory(DEFAULT_MEMORY_INDEX)?;
|
||||
context.push_value(value_type)?;
|
||||
Ok(InstructionOutcome::RunNextInstruction)
|
||||
Ok(InstructionOutcome::ValidateNextInstruction)
|
||||
}
|
||||
|
||||
fn validate_store(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: StackValueType) -> Result<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 1u32.checked_shl(align).unwrap_or(u32::MAX) > max_align {
|
||||
return Err(Error::Validation(format!("Too large memory alignment 2^{} (expected at most {})", align, max_align)));
|
||||
@ -383,14 +436,14 @@ impl Validator {
|
||||
context.require_memory(DEFAULT_MEMORY_INDEX)?;
|
||||
context.pop_value(value_type)?;
|
||||
context.pop_value(ValueType::I32.into())?;
|
||||
Ok(InstructionOutcome::RunNextInstruction)
|
||||
Ok(InstructionOutcome::ValidateNextInstruction)
|
||||
}
|
||||
|
||||
fn validate_loop(context: &mut FunctionValidationContext, block_type: BlockType, body: &[Opcode]) -> Result<InstructionOutcome, Error> {
|
||||
Validator::validate_block(context, true, block_type, body, Opcode::End)
|
||||
fn validate_loop<'a>(_context: &mut FunctionValidationContext, block_type: BlockType, body: &'a [Opcode]) -> Result<InstructionOutcome<'a>, Error> {
|
||||
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())?;
|
||||
|
||||
let body_len = body.len();
|
||||
@ -398,18 +451,17 @@ impl Validator {
|
||||
.position(|op| *op == Opcode::Else)
|
||||
.unwrap_or(body_len - 1);
|
||||
if separator_index != body_len - 1 {
|
||||
Validator::validate_block(context, false, block_type, &body[..separator_index + 1], Opcode::Else)?;
|
||||
Validator::validate_block(context, false, block_type, &body[separator_index+1..], Opcode::End)
|
||||
Validator::schedule_validate_block2(false, block_type, &body[..separator_index + 1], Opcode::Else, &body[separator_index+1..], Opcode::End)
|
||||
} else {
|
||||
if block_type != BlockType::NoResult {
|
||||
return Err(Error::Validation(format!("If block without else required to have NoResult block type. But it have {:?} type", block_type)));
|
||||
}
|
||||
|
||||
Validator::validate_block(context, false, block_type, body, Opcode::End)
|
||||
Validator::schedule_validate_block(false, block_type, body, Opcode::End)
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_br(context: &mut FunctionValidationContext, idx: u32) -> Result<InstructionOutcome, Error> {
|
||||
fn validate_br<'a>(context: &mut FunctionValidationContext, idx: u32) -> Result<InstructionOutcome<'a>, Error> {
|
||||
let (frame_is_loop, frame_block_type) = {
|
||||
let frame = context.require_label(idx)?;
|
||||
(frame.is_loop, frame.block_type)
|
||||
@ -423,15 +475,15 @@ impl Validator {
|
||||
Ok(InstructionOutcome::Unreachable)
|
||||
}
|
||||
|
||||
fn validate_br_if(context: &mut FunctionValidationContext, idx: u32) -> Result<InstructionOutcome, Error> {
|
||||
fn validate_br_if<'a>(context: &mut FunctionValidationContext, idx: u32) -> Result<InstructionOutcome<'a>, Error> {
|
||||
context.pop_value(ValueType::I32.into())?;
|
||||
if let BlockType::Value(value_type) = context.require_label(idx)?.block_type {
|
||||
context.tee_value(value_type.into())?;
|
||||
}
|
||||
Ok(InstructionOutcome::RunNextInstruction)
|
||||
Ok(InstructionOutcome::ValidateNextInstruction)
|
||||
}
|
||||
|
||||
fn validate_br_table(context: &mut FunctionValidationContext, table: &Vec<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;
|
||||
|
||||
{
|
||||
@ -463,14 +515,14 @@ impl Validator {
|
||||
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()? {
|
||||
context.tee_value(value_type.into())?;
|
||||
}
|
||||
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)?;
|
||||
for argument_type in argument_types.iter().rev() {
|
||||
context.pop_value((*argument_type).into())?;
|
||||
@ -478,10 +530,10 @@ impl Validator {
|
||||
if let BlockType::Value(value_type) = return_type {
|
||||
context.push_value(value_type.into())?;
|
||||
}
|
||||
Ok(InstructionOutcome::RunNextInstruction)
|
||||
Ok(InstructionOutcome::ValidateNextInstruction)
|
||||
}
|
||||
|
||||
fn validate_call_indirect(context: &mut FunctionValidationContext, idx: u32) -> Result<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.pop_value(ValueType::I32.into())?;
|
||||
@ -492,20 +544,39 @@ impl Validator {
|
||||
if let BlockType::Value(value_type) = return_type {
|
||||
context.push_value(value_type.into())?;
|
||||
}
|
||||
Ok(InstructionOutcome::RunNextInstruction)
|
||||
Ok(InstructionOutcome::ValidateNextInstruction)
|
||||
}
|
||||
|
||||
fn validate_current_memory(context: &mut FunctionValidationContext) -> Result<InstructionOutcome, Error> {
|
||||
fn validate_current_memory<'a>(context: &mut FunctionValidationContext) -> Result<InstructionOutcome<'a>, Error> {
|
||||
context.require_memory(DEFAULT_MEMORY_INDEX)?;
|
||||
context.push_value(ValueType::I32.into())?;
|
||||
Ok(InstructionOutcome::RunNextInstruction)
|
||||
Ok(InstructionOutcome::ValidateNextInstruction)
|
||||
}
|
||||
|
||||
fn validate_grow_memory(context: &mut FunctionValidationContext) -> Result<InstructionOutcome, Error> {
|
||||
fn validate_grow_memory<'a>(context: &mut FunctionValidationContext) -> Result<InstructionOutcome<'a>, Error> {
|
||||
context.require_memory(DEFAULT_MEMORY_INDEX)?;
|
||||
context.pop_value(ValueType::I32.into())?;
|
||||
context.push_value(ValueType::I32.into())?;
|
||||
Ok(InstructionOutcome::RunNextInstruction)
|
||||
Ok(InstructionOutcome::ValidateNextInstruction)
|
||||
}
|
||||
|
||||
fn schedule_validate_block<'a>(is_loop: bool, block_type: BlockType, body: &'a [Opcode], end_instr: Opcode) -> Result<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())?;
|
||||
}
|
||||
|
||||
Ok(InstructionOutcome::RunNextInstruction)
|
||||
Ok(InstructionOutcome::ValidateNextInstruction)
|
||||
}
|
||||
|
||||
pub fn require_label(&self, idx: u32) -> Result<&ValidationFrame, Error> {
|
||||
|
Reference in New Issue
Block a user