wasmi/validation/src/func.rs

1220 lines
39 KiB
Rust
Raw Normal View History

#[allow(unused_imports)]
2019-04-15 15:45:54 +00:00
use alloc::prelude::v1::*;
2018-01-17 15:32:33 +00:00
2019-04-15 15:25:34 +00:00
use crate::{
2019-04-15 18:17:44 +00:00
context::ModuleContext, stack::StackWithLimit, util::Locals, Error, FuncValidator,
2019-04-15 15:34:09 +00:00
DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX,
2019-04-15 15:25:34 +00:00
};
2018-01-17 15:32:33 +00:00
2019-04-15 15:25:34 +00:00
use core::u32;
use parity_wasm::elements::{BlockType, Func, FuncBody, Instruction, TableElementType, ValueType};
2018-01-17 15:32:33 +00:00
/// Maximum number of entries in value stack per function.
2018-01-17 15:32:33 +00:00
const DEFAULT_VALUE_STACK_LIMIT: usize = 16384;
/// Maximum number of entries in frame stack per function.
const DEFAULT_FRAME_STACK_LIMIT: usize = 16384;
2018-01-17 15:32:33 +00:00
/// Control stack frame.
#[derive(Debug, Clone)]
2019-04-08 14:20:21 +00:00
pub struct BlockFrame {
2019-04-05 11:38:12 +00:00
/// The opcode that started this block frame.
2019-04-08 14:20:21 +00:00
pub started_with: StartedWith,
2019-03-29 17:13:36 +00:00
/// A signature, which is a block signature type indicating the number and types of result
/// values of the region.
2019-04-08 14:20:21 +00:00
pub block_type: BlockType,
2019-03-29 17:13:36 +00:00
/// A limit integer value, which is an index into the value stack indicating where to reset it
/// to on a branch to that label.
2019-04-08 14:20:21 +00:00
pub value_stack_len: usize,
2019-03-29 17:13:36 +00:00
/// Boolean which signals whether value stack became polymorphic. Value stack starts in
/// a non-polymorphic state and becomes polymorphic only after an instruction that never passes
/// control further is executed, i.e. `unreachable`, `br` (but not `br_if`!), etc.
2019-04-08 14:20:21 +00:00
pub polymorphic_stack: bool,
}
2019-04-05 11:38:12 +00:00
/// An opcode that opened the particular frame.
///
/// We need that to ensure proper combinations with `End` instruction.
2019-04-05 11:41:25 +00:00
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
2019-04-08 14:20:21 +00:00
pub enum StartedWith {
2019-04-05 11:38:12 +00:00
Block,
If,
Else,
Loop,
}
2018-01-17 15:32:33 +00:00
/// Value type on the stack.
#[derive(Debug, Clone, Copy)]
2019-04-08 14:20:21 +00:00
pub enum StackValueType {
2018-12-11 11:54:06 +00:00
/// Any value type.
Any,
/// Concrete value type.
Specific(ValueType),
2018-01-17 15:32:33 +00:00
}
impl From<ValueType> for StackValueType {
2018-12-11 11:54:06 +00:00
fn from(value_type: ValueType) -> Self {
StackValueType::Specific(value_type)
}
}
impl PartialEq<StackValueType> for StackValueType {
2018-12-11 11:54:06 +00:00
fn eq(&self, other: &StackValueType) -> bool {
match (*self, *other) {
// Any type is equal with any other type.
(StackValueType::Any, _) => true,
(_, StackValueType::Any) => true,
(StackValueType::Specific(self_ty), StackValueType::Specific(other_ty)) => {
self_ty == other_ty
}
2018-12-11 11:54:06 +00:00
}
}
}
impl PartialEq<ValueType> for StackValueType {
2018-12-11 11:54:06 +00:00
fn eq(&self, other: &ValueType) -> bool {
match *self {
StackValueType::Any => true,
StackValueType::Specific(value_ty) => value_ty == *other,
2018-12-11 11:54:06 +00:00
}
}
}
impl PartialEq<StackValueType> for ValueType {
2018-12-11 11:54:06 +00:00
fn eq(&self, other: &StackValueType) -> bool {
other == self
}
}
2018-01-17 15:32:33 +00:00
2019-04-15 18:17:44 +00:00
pub fn drive<T: FuncValidator>(
2019-04-08 12:49:53 +00:00
module: &ModuleContext,
func: &Func,
body: &FuncBody,
) -> Result<T::Output, Error> {
let (params, result_ty) = module.require_function_type(func.type_ref())?;
let code = body.code().elements();
let code_len = code.len();
if code_len == 0 {
return Err(Error("Non-empty function body expected".into()));
}
2019-04-08 12:49:53 +00:00
let mut context = FunctionValidationContext::new(
&module,
Locals::new(params, body.locals())?,
DEFAULT_VALUE_STACK_LIMIT,
DEFAULT_FRAME_STACK_LIMIT,
result_ty,
)?;
2019-04-08 12:49:53 +00:00
2019-04-16 14:14:10 +00:00
let mut validator = T::new(&context, body);
2019-04-08 12:49:53 +00:00
for (position, instruction) in code.iter().enumerate() {
validator
.next_instruction(&mut context, instruction)
2019-04-08 12:49:53 +00:00
.map_err(|err| {
Error(format!(
"At instruction {:?}(@{}): {}",
instruction, position, err
2019-04-08 12:49:53 +00:00
))
})?;
}
// The last `end` opcode should pop last instruction.
2019-04-15 17:44:02 +00:00
// parity-wasm ensures that there is always `End` opcode at
// the end of the function body.
assert!(context.frame_stack.is_empty());
2019-04-08 12:49:53 +00:00
Ok(validator.finish())
}
2019-04-05 16:48:45 +00:00
/// Function validation context.
pub struct FunctionValidationContext<'a> {
2019-04-05 16:48:45 +00:00
/// Wasm module
2019-04-08 14:20:21 +00:00
pub module: &'a ModuleContext,
2019-04-05 16:48:45 +00:00
/// Local variables.
2019-04-08 14:20:21 +00:00
pub locals: Locals<'a>,
2019-04-05 16:48:45 +00:00
/// Value stack.
2019-04-08 14:20:21 +00:00
pub value_stack: StackWithLimit<StackValueType>,
2019-04-05 16:48:45 +00:00
/// Frame stack.
2019-04-08 14:20:21 +00:00
pub frame_stack: StackWithLimit<BlockFrame>,
2019-04-05 16:48:45 +00:00
/// Function return type.
2019-04-08 14:20:21 +00:00
pub return_type: BlockType,
2019-04-05 16:48:45 +00:00
}
2019-04-05 14:39:41 +00:00
2019-04-05 16:48:45 +00:00
impl<'a> FunctionValidationContext<'a> {
fn new(
module: &'a ModuleContext,
locals: Locals<'a>,
value_stack_limit: usize,
frame_stack_limit: usize,
return_type: BlockType,
) -> Result<Self, Error> {
let mut ctx = FunctionValidationContext {
2019-04-05 16:48:45 +00:00
module: module,
locals: locals,
value_stack: StackWithLimit::with_limit(value_stack_limit),
frame_stack: StackWithLimit::with_limit(frame_stack_limit),
return_type: return_type,
};
push_label(
StartedWith::Block,
return_type,
&ctx.value_stack,
&mut ctx.frame_stack,
)?;
Ok(ctx)
}
2018-12-11 11:54:06 +00:00
pub fn step(&mut self, instruction: &Instruction) -> Result<(), Error> {
2019-04-05 16:48:45 +00:00
use self::Instruction::*;
2018-12-11 11:54:06 +00:00
2019-04-05 16:48:45 +00:00
match *instruction {
// Nop instruction doesn't do anything. It is safe to just skip it.
Nop => {}
2018-12-11 11:54:06 +00:00
2019-04-05 16:48:45 +00:00
Unreachable => {
make_top_frame_polymorphic(&mut self.value_stack, &mut self.frame_stack);
}
2018-12-11 11:54:06 +00:00
2019-04-05 16:48:45 +00:00
Block(block_type) => {
push_label(
StartedWith::Block,
block_type,
&self.value_stack,
&mut self.frame_stack,
)?;
}
Loop(block_type) => {
push_label(
StartedWith::Loop,
block_type,
&self.value_stack,
&mut self.frame_stack,
)?;
}
If(block_type) => {
pop_value(
&mut self.value_stack,
&self.frame_stack,
ValueType::I32.into(),
)?;
push_label(
StartedWith::If,
block_type,
&self.value_stack,
&mut self.frame_stack,
)?;
}
Else => {
let block_type = {
let top = top_label(&self.frame_stack);
if top.started_with != StartedWith::If {
return Err(Error("Misplaced else instruction".into()));
}
top.block_type
};
2018-12-11 11:54:06 +00:00
2019-04-05 16:48:45 +00:00
// Then, we pop the current label. It discards all values that pushed in the current
// frame.
pop_label(&mut self.value_stack, &mut self.frame_stack)?;
push_label(
StartedWith::Else,
block_type,
&self.value_stack,
&mut self.frame_stack,
)?;
}
End => {
2019-04-05 21:41:29 +00:00
let block_type = {
2019-04-05 16:48:45 +00:00
let top = top_label(&self.frame_stack);
2018-12-11 11:54:06 +00:00
2019-04-05 16:48:45 +00:00
if top.started_with == StartedWith::If && top.block_type != BlockType::NoResult
{
// A `if` without an `else` can't return a result.
return Err(Error(format!(
"If block without else required to have NoResult block type. But it has {:?} type",
top.block_type
)));
}
2018-12-11 11:54:06 +00:00
2019-04-05 21:41:29 +00:00
top.block_type
2019-04-05 16:48:45 +00:00
};
2018-12-11 11:54:06 +00:00
2019-04-05 16:48:45 +00:00
if self.frame_stack.len() == 1 {
2019-04-16 14:29:49 +00:00
// We are about to close the last frame.
2018-12-11 11:54:06 +00:00
2019-04-05 16:48:45 +00:00
// Check the return type.
2019-04-08 14:20:21 +00:00
if let BlockType::Value(value_type) = self.return_type {
2019-04-05 16:48:45 +00:00
tee_value(&mut self.value_stack, &self.frame_stack, value_type.into())?;
}
2018-12-11 11:54:06 +00:00
2019-04-16 14:29:49 +00:00
pop_label(&mut self.value_stack, &mut self.frame_stack)?;
2018-12-11 11:54:06 +00:00
2019-04-16 14:29:49 +00:00
// We just poped the last frame. To avoid some difficulties
// we prefer to keep this branch explicit and bail out here.
()
} else {
pop_label(&mut self.value_stack, &mut self.frame_stack)?;
// Push the result value.
if let BlockType::Value(value_type) = block_type {
push_value(&mut self.value_stack, value_type.into())?;
}
2019-04-05 16:48:45 +00:00
}
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
Br(depth) => {
self.validate_br(depth)?;
make_top_frame_polymorphic(&mut self.value_stack, &mut self.frame_stack);
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
BrIf(depth) => {
self.validate_br_if(depth)?;
}
BrTable(ref table, default) => {
self.validate_br_table(table, default)?;
make_top_frame_polymorphic(&mut self.value_stack, &mut self.frame_stack);
}
Return => {
2019-04-08 14:20:21 +00:00
if let BlockType::Value(value_type) = self.return_type {
2019-04-05 16:48:45 +00:00
tee_value(&mut self.value_stack, &self.frame_stack, value_type.into())?;
}
2019-04-05 16:48:45 +00:00
make_top_frame_polymorphic(&mut self.value_stack, &mut self.frame_stack);
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
Call(index) => {
self.validate_call(index)?;
}
CallIndirect(index, _reserved) => {
self.validate_call_indirect(index)?;
}
2018-12-11 11:54:06 +00:00
2019-04-05 16:48:45 +00:00
Drop => {
self.validate_drop()?;
}
Select => {
self.validate_select()?;
}
2018-12-11 11:54:06 +00:00
2019-04-05 16:48:45 +00:00
GetLocal(index) => {
self.validate_get_local(index)?;
}
SetLocal(index) => {
self.validate_set_local(index)?;
}
TeeLocal(index) => {
self.validate_tee_local(index)?;
}
GetGlobal(index) => {
self.validate_get_global(index)?;
}
SetGlobal(index) => {
self.validate_set_global(index)?;
}
2018-12-11 11:54:06 +00:00
2019-04-05 21:41:29 +00:00
I32Load(align, _) => {
2019-04-05 16:48:45 +00:00
self.validate_load(align, 4, ValueType::I32)?;
}
2019-04-05 21:41:29 +00:00
I64Load(align, _) => {
2019-04-05 16:48:45 +00:00
self.validate_load(align, 8, ValueType::I64)?;
}
2019-04-05 21:41:29 +00:00
F32Load(align, _) => {
2019-04-05 16:48:45 +00:00
self.validate_load(align, 4, ValueType::F32)?;
}
2019-04-05 21:41:29 +00:00
F64Load(align, _) => {
2019-04-05 16:48:45 +00:00
self.validate_load(align, 8, ValueType::F64)?;
}
2019-04-05 21:41:29 +00:00
I32Load8S(align, _) => {
2019-04-05 16:48:45 +00:00
self.validate_load(align, 1, ValueType::I32)?;
}
2019-04-05 21:41:29 +00:00
I32Load8U(align, _) => {
2019-04-05 16:48:45 +00:00
self.validate_load(align, 1, ValueType::I32)?;
}
2019-04-05 21:41:29 +00:00
I32Load16S(align, _) => {
2019-04-05 16:48:45 +00:00
self.validate_load(align, 2, ValueType::I32)?;
}
2019-04-05 21:41:29 +00:00
I32Load16U(align, _) => {
2019-04-05 16:48:45 +00:00
self.validate_load(align, 2, ValueType::I32)?;
}
2019-04-05 21:41:29 +00:00
I64Load8S(align, _) => {
2019-04-05 16:48:45 +00:00
self.validate_load(align, 1, ValueType::I64)?;
}
2019-04-05 21:41:29 +00:00
I64Load8U(align, _) => {
2019-04-05 16:48:45 +00:00
self.validate_load(align, 1, ValueType::I64)?;
}
2019-04-05 21:41:29 +00:00
I64Load16S(align, _) => {
2019-04-05 16:48:45 +00:00
self.validate_load(align, 2, ValueType::I64)?;
}
2019-04-05 21:41:29 +00:00
I64Load16U(align, _) => {
2019-04-05 16:48:45 +00:00
self.validate_load(align, 2, ValueType::I64)?;
}
2019-04-05 21:41:29 +00:00
I64Load32S(align, _) => {
2019-04-05 16:48:45 +00:00
self.validate_load(align, 4, ValueType::I64)?;
}
2019-04-05 21:41:29 +00:00
I64Load32U(align, _) => {
2019-04-05 16:48:45 +00:00
self.validate_load(align, 4, ValueType::I64)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 21:41:29 +00:00
I32Store(align, _) => {
2019-04-05 16:48:45 +00:00
self.validate_store(align, 4, ValueType::I32)?;
}
2019-04-05 21:41:29 +00:00
I64Store(align, _) => {
2019-04-05 16:48:45 +00:00
self.validate_store(align, 8, ValueType::I64)?;
}
2019-04-05 21:41:29 +00:00
F32Store(align, _) => {
2019-04-05 16:48:45 +00:00
self.validate_store(align, 4, ValueType::F32)?;
}
2019-04-05 21:41:29 +00:00
F64Store(align, _) => {
2019-04-05 16:48:45 +00:00
self.validate_store(align, 8, ValueType::F64)?;
}
2019-04-05 21:41:29 +00:00
I32Store8(align, _) => {
2019-04-05 16:48:45 +00:00
self.validate_store(align, 1, ValueType::I32)?;
}
2019-04-05 21:41:29 +00:00
I32Store16(align, _) => {
2019-04-05 16:48:45 +00:00
self.validate_store(align, 2, ValueType::I32)?;
}
2019-04-05 21:41:29 +00:00
I64Store8(align, _) => {
2019-04-05 16:48:45 +00:00
self.validate_store(align, 1, ValueType::I64)?;
}
2019-04-05 21:41:29 +00:00
I64Store16(align, _) => {
2019-04-05 16:48:45 +00:00
self.validate_store(align, 2, ValueType::I64)?;
}
2019-04-05 21:41:29 +00:00
I64Store32(align, _) => {
2019-04-05 16:48:45 +00:00
self.validate_store(align, 4, ValueType::I64)?;
}
2018-12-11 11:54:06 +00:00
2019-04-05 16:48:45 +00:00
CurrentMemory(_) => {
self.validate_current_memory()?;
}
GrowMemory(_) => {
self.validate_grow_memory()?;
}
2018-12-11 11:54:06 +00:00
2019-04-05 21:41:29 +00:00
I32Const(_) => {
2019-04-05 16:48:45 +00:00
self.validate_const(ValueType::I32)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 21:41:29 +00:00
I64Const(_) => {
2019-04-05 16:48:45 +00:00
self.validate_const(ValueType::I64)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 21:41:29 +00:00
F32Const(_) => {
2019-04-05 16:48:45 +00:00
self.validate_const(ValueType::F32)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 21:41:29 +00:00
F64Const(_) => {
2019-04-05 16:48:45 +00:00
self.validate_const(ValueType::F64)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 12:17:15 +00:00
2019-04-05 16:48:45 +00:00
I32Eqz => {
self.validate_testop(ValueType::I32)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
I32Eq => {
self.validate_relop(ValueType::I32)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
I32Ne => {
self.validate_relop(ValueType::I32)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
I32LtS => {
self.validate_relop(ValueType::I32)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
I32LtU => {
self.validate_relop(ValueType::I32)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
I32GtS => {
self.validate_relop(ValueType::I32)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
I32GtU => {
self.validate_relop(ValueType::I32)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
I32LeS => {
self.validate_relop(ValueType::I32)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
I32LeU => {
self.validate_relop(ValueType::I32)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
I32GeS => {
self.validate_relop(ValueType::I32)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
I32GeU => {
self.validate_relop(ValueType::I32)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
I64Eqz => {
self.validate_testop(ValueType::I64)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
I64Eq => {
self.validate_relop(ValueType::I64)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
I64Ne => {
self.validate_relop(ValueType::I64)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
I64LtS => {
self.validate_relop(ValueType::I64)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
I64LtU => {
self.validate_relop(ValueType::I64)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
I64GtS => {
self.validate_relop(ValueType::I64)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
I64GtU => {
self.validate_relop(ValueType::I64)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
I64LeS => {
self.validate_relop(ValueType::I64)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
I64LeU => {
self.validate_relop(ValueType::I64)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
I64GeS => {
self.validate_relop(ValueType::I64)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
I64GeU => {
self.validate_relop(ValueType::I64)?;
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
F32Eq => {
self.validate_relop(ValueType::F32)?;
}
F32Ne => {
2019-04-05 16:48:45 +00:00
self.validate_relop(ValueType::F32)?;
}
F32Lt => {
2019-04-05 16:48:45 +00:00
self.validate_relop(ValueType::F32)?;
}
F32Gt => {
2019-04-05 16:48:45 +00:00
self.validate_relop(ValueType::F32)?;
}
F32Le => {
2019-04-05 16:48:45 +00:00
self.validate_relop(ValueType::F32)?;
}
F32Ge => {
2019-04-05 16:48:45 +00:00
self.validate_relop(ValueType::F32)?;
}
F64Eq => {
2019-04-05 16:48:45 +00:00
self.validate_relop(ValueType::F64)?;
}
F64Ne => {
2019-04-05 16:48:45 +00:00
self.validate_relop(ValueType::F64)?;
}
F64Lt => {
2019-04-05 16:48:45 +00:00
self.validate_relop(ValueType::F64)?;
}
F64Gt => {
2019-04-05 16:48:45 +00:00
self.validate_relop(ValueType::F64)?;
}
F64Le => {
2019-04-05 16:48:45 +00:00
self.validate_relop(ValueType::F64)?;
}
F64Ge => {
2019-04-05 16:48:45 +00:00
self.validate_relop(ValueType::F64)?;
}
I32Clz => {
2019-04-05 16:48:45 +00:00
self.validate_unop(ValueType::I32)?;
}
I32Ctz => {
2019-04-05 16:48:45 +00:00
self.validate_unop(ValueType::I32)?;
}
I32Popcnt => {
2019-04-05 16:48:45 +00:00
self.validate_unop(ValueType::I32)?;
}
I32Add => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I32)?;
}
I32Sub => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I32)?;
}
I32Mul => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I32)?;
}
I32DivS => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I32)?;
}
I32DivU => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I32)?;
}
I32RemS => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I32)?;
}
I32RemU => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I32)?;
}
I32And => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I32)?;
}
I32Or => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I32)?;
}
I32Xor => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I32)?;
}
I32Shl => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I32)?;
}
I32ShrS => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I32)?;
}
I32ShrU => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I32)?;
}
I32Rotl => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I32)?;
}
I32Rotr => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I32)?;
}
I64Clz => {
2019-04-05 16:48:45 +00:00
self.validate_unop(ValueType::I64)?;
}
I64Ctz => {
2019-04-05 16:48:45 +00:00
self.validate_unop(ValueType::I64)?;
}
I64Popcnt => {
2019-04-05 16:48:45 +00:00
self.validate_unop(ValueType::I64)?;
}
I64Add => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I64)?;
}
I64Sub => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I64)?;
}
I64Mul => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I64)?;
}
I64DivS => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I64)?;
}
I64DivU => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I64)?;
}
I64RemS => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I64)?;
}
I64RemU => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I64)?;
}
I64And => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I64)?;
}
I64Or => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I64)?;
}
I64Xor => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I64)?;
}
I64Shl => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I64)?;
}
I64ShrS => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I64)?;
}
I64ShrU => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I64)?;
}
I64Rotl => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I64)?;
}
I64Rotr => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::I64)?;
}
F32Abs => {
2019-04-05 16:48:45 +00:00
self.validate_unop(ValueType::F32)?;
}
F32Neg => {
2019-04-05 16:48:45 +00:00
self.validate_unop(ValueType::F32)?;
}
F32Ceil => {
2019-04-05 16:48:45 +00:00
self.validate_unop(ValueType::F32)?;
}
F32Floor => {
2019-04-05 16:48:45 +00:00
self.validate_unop(ValueType::F32)?;
}
F32Trunc => {
2019-04-05 16:48:45 +00:00
self.validate_unop(ValueType::F32)?;
}
F32Nearest => {
2019-04-05 16:48:45 +00:00
self.validate_unop(ValueType::F32)?;
}
F32Sqrt => {
2019-04-05 16:48:45 +00:00
self.validate_unop(ValueType::F32)?;
}
F32Add => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::F32)?;
}
F32Sub => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::F32)?;
}
F32Mul => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::F32)?;
}
F32Div => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::F32)?;
}
F32Min => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::F32)?;
}
F32Max => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::F32)?;
}
F32Copysign => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::F32)?;
}
F64Abs => {
2019-04-05 16:48:45 +00:00
self.validate_unop(ValueType::F64)?;
}
F64Neg => {
2019-04-05 16:48:45 +00:00
self.validate_unop(ValueType::F64)?;
}
F64Ceil => {
2019-04-05 16:48:45 +00:00
self.validate_unop(ValueType::F64)?;
}
F64Floor => {
2019-04-05 16:48:45 +00:00
self.validate_unop(ValueType::F64)?;
}
F64Trunc => {
2019-04-05 16:48:45 +00:00
self.validate_unop(ValueType::F64)?;
}
F64Nearest => {
2019-04-05 16:48:45 +00:00
self.validate_unop(ValueType::F64)?;
}
F64Sqrt => {
2019-04-05 16:48:45 +00:00
self.validate_unop(ValueType::F64)?;
}
F64Add => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::F64)?;
}
F64Sub => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::F64)?;
}
F64Mul => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::F64)?;
}
F64Div => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::F64)?;
}
F64Min => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::F64)?;
2018-12-11 11:54:06 +00:00
}
F64Max => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::F64)?;
2018-12-11 11:54:06 +00:00
}
F64Copysign => {
2019-04-05 16:48:45 +00:00
self.validate_binop(ValueType::F64)?;
2018-12-11 11:54:06 +00:00
}
I32WrapI64 => {
2019-04-05 16:48:45 +00:00
self.validate_cvtop(ValueType::I64, ValueType::I32)?;
2018-12-11 11:54:06 +00:00
}
I32TruncSF32 => {
2019-04-05 16:48:45 +00:00
self.validate_cvtop(ValueType::F32, ValueType::I32)?;
2018-12-11 11:54:06 +00:00
}
I32TruncUF32 => {
2019-04-05 16:48:45 +00:00
self.validate_cvtop(ValueType::F32, ValueType::I32)?;
2018-12-11 11:54:06 +00:00
}
I32TruncSF64 => {
2019-04-05 16:48:45 +00:00
self.validate_cvtop(ValueType::F64, ValueType::I32)?;
2018-12-11 11:54:06 +00:00
}
I32TruncUF64 => {
2019-04-05 16:48:45 +00:00
self.validate_cvtop(ValueType::F64, ValueType::I32)?;
2018-12-11 11:54:06 +00:00
}
I64ExtendSI32 => {
2019-04-05 16:48:45 +00:00
self.validate_cvtop(ValueType::I32, ValueType::I64)?;
2018-12-11 11:54:06 +00:00
}
I64ExtendUI32 => {
2019-04-05 16:48:45 +00:00
self.validate_cvtop(ValueType::I32, ValueType::I64)?;
2018-12-11 11:54:06 +00:00
}
I64TruncSF32 => {
2019-04-05 16:48:45 +00:00
self.validate_cvtop(ValueType::F32, ValueType::I64)?;
2018-12-11 11:54:06 +00:00
}
I64TruncUF32 => {
2019-04-05 16:48:45 +00:00
self.validate_cvtop(ValueType::F32, ValueType::I64)?;
2018-12-11 11:54:06 +00:00
}
I64TruncSF64 => {
2019-04-05 16:48:45 +00:00
self.validate_cvtop(ValueType::F64, ValueType::I64)?;
2018-12-11 11:54:06 +00:00
}
I64TruncUF64 => {
2019-04-05 16:48:45 +00:00
self.validate_cvtop(ValueType::F64, ValueType::I64)?;
2018-12-11 11:54:06 +00:00
}
F32ConvertSI32 => {
2019-04-05 16:48:45 +00:00
self.validate_cvtop(ValueType::I32, ValueType::F32)?;
2018-12-11 11:54:06 +00:00
}
F32ConvertUI32 => {
2019-04-05 16:48:45 +00:00
self.validate_cvtop(ValueType::I32, ValueType::F32)?;
2018-12-11 11:54:06 +00:00
}
F32ConvertSI64 => {
2019-04-05 16:48:45 +00:00
self.validate_cvtop(ValueType::I64, ValueType::F32)?;
2018-12-11 11:54:06 +00:00
}
F32ConvertUI64 => {
2019-04-05 16:48:45 +00:00
self.validate_cvtop(ValueType::I64, ValueType::F32)?;
2018-12-11 11:54:06 +00:00
}
F32DemoteF64 => {
2019-04-05 16:48:45 +00:00
self.validate_cvtop(ValueType::F64, ValueType::F32)?;
2018-12-11 11:54:06 +00:00
}
F64ConvertSI32 => {
2019-04-05 16:48:45 +00:00
self.validate_cvtop(ValueType::I32, ValueType::F64)?;
2018-12-11 11:54:06 +00:00
}
F64ConvertUI32 => {
2019-04-05 16:48:45 +00:00
self.validate_cvtop(ValueType::I32, ValueType::F64)?;
2018-12-11 11:54:06 +00:00
}
F64ConvertSI64 => {
2019-04-05 16:48:45 +00:00
self.validate_cvtop(ValueType::I64, ValueType::F64)?;
2018-12-11 11:54:06 +00:00
}
F64ConvertUI64 => {
2019-04-05 16:48:45 +00:00
self.validate_cvtop(ValueType::I64, ValueType::F64)?;
2018-12-11 11:54:06 +00:00
}
F64PromoteF32 => {
2019-04-05 16:48:45 +00:00
self.validate_cvtop(ValueType::F32, ValueType::F64)?;
2018-12-11 11:54:06 +00:00
}
I32ReinterpretF32 => {
2019-04-05 16:48:45 +00:00
self.validate_cvtop(ValueType::F32, ValueType::I32)?;
2018-12-11 11:54:06 +00:00
}
I64ReinterpretF64 => {
2019-04-05 16:48:45 +00:00
self.validate_cvtop(ValueType::F64, ValueType::I64)?;
2018-12-11 11:54:06 +00:00
}
F32ReinterpretI32 => {
2019-04-05 16:48:45 +00:00
self.validate_cvtop(ValueType::I32, ValueType::F32)?;
2018-12-11 11:54:06 +00:00
}
F64ReinterpretI64 => {
2019-04-05 16:48:45 +00:00
self.validate_cvtop(ValueType::I64, ValueType::F64)?;
2018-12-11 11:54:06 +00:00
}
}
2019-04-05 11:25:17 +00:00
Ok(())
2018-12-11 11:54:06 +00:00
}
2019-04-05 16:48:45 +00:00
2019-04-05 21:21:19 +00:00
fn validate_const(&mut self, value_type: ValueType) -> Result<(), Error> {
2019-04-05 16:48:45 +00:00
push_value(&mut self.value_stack, value_type.into())?;
Ok(())
}
2019-04-05 21:21:19 +00:00
fn validate_unop(&mut self, value_type: ValueType) -> Result<(), Error> {
pop_value(&mut self.value_stack, &self.frame_stack, value_type.into())?;
2019-04-05 16:48:45 +00:00
push_value(&mut self.value_stack, value_type.into())?;
Ok(())
}
2019-04-05 21:21:19 +00:00
fn validate_binop(&mut self, value_type: ValueType) -> Result<(), Error> {
pop_value(&mut self.value_stack, &self.frame_stack, value_type.into())?;
pop_value(&mut self.value_stack, &self.frame_stack, value_type.into())?;
2019-04-05 16:48:45 +00:00
push_value(&mut self.value_stack, value_type.into())?;
Ok(())
}
2019-04-05 21:21:19 +00:00
fn validate_testop(&mut self, value_type: ValueType) -> Result<(), Error> {
pop_value(&mut self.value_stack, &self.frame_stack, value_type.into())?;
2019-04-05 16:48:45 +00:00
push_value(&mut self.value_stack, ValueType::I32.into())?;
Ok(())
}
2019-04-05 21:21:19 +00:00
fn validate_relop(&mut self, value_type: ValueType) -> Result<(), Error> {
pop_value(&mut self.value_stack, &self.frame_stack, value_type.into())?;
pop_value(&mut self.value_stack, &self.frame_stack, value_type.into())?;
2019-04-05 16:48:45 +00:00
push_value(&mut self.value_stack, ValueType::I32.into())?;
Ok(())
}
fn validate_cvtop(
&mut self,
value_type1: ValueType,
value_type2: ValueType,
) -> Result<(), Error> {
2019-04-05 21:21:19 +00:00
pop_value(&mut self.value_stack, &self.frame_stack, value_type1.into())?;
2019-04-05 16:48:45 +00:00
push_value(&mut self.value_stack, value_type2.into())?;
Ok(())
}
fn validate_drop(&mut self) -> Result<(), Error> {
pop_value(
&mut self.value_stack,
&self.frame_stack,
StackValueType::Any,
)?;
Ok(())
}
fn validate_select(&mut self) -> Result<(), Error> {
pop_value(
&mut self.value_stack,
&self.frame_stack,
ValueType::I32.into(),
)?;
let select_type = pop_value(
&mut self.value_stack,
&self.frame_stack,
StackValueType::Any,
)?;
pop_value(&mut self.value_stack, &self.frame_stack, select_type)?;
push_value(&mut self.value_stack, select_type)?;
Ok(())
}
2019-04-05 21:21:19 +00:00
fn validate_get_local(&mut self, index: u32) -> Result<(), Error> {
2019-04-05 16:48:45 +00:00
let local_type = require_local(&self.locals, index)?;
push_value(&mut self.value_stack, local_type.into())?;
Ok(())
}
2019-04-05 21:21:19 +00:00
fn validate_set_local(&mut self, index: u32) -> Result<(), Error> {
2019-04-05 16:48:45 +00:00
let local_type = require_local(&self.locals, index)?;
let value_type = pop_value(
&mut self.value_stack,
&self.frame_stack,
StackValueType::Any,
)?;
if StackValueType::from(local_type) != value_type {
return Err(Error(format!(
"Trying to update local {} of type {:?} with value of type {:?}",
index, local_type, value_type
)));
}
Ok(())
}
2019-04-05 21:21:19 +00:00
fn validate_tee_local(&mut self, index: u32) -> Result<(), Error> {
2019-04-05 16:48:45 +00:00
let local_type = require_local(&self.locals, index)?;
2019-04-05 21:21:19 +00:00
tee_value(&mut self.value_stack, &self.frame_stack, local_type.into())?;
2019-04-05 16:48:45 +00:00
Ok(())
}
2019-04-05 21:21:19 +00:00
fn validate_get_global(&mut self, index: u32) -> Result<(), Error> {
2019-04-05 16:48:45 +00:00
let global_type: StackValueType = {
let global = self.module.require_global(index, None)?;
global.content_type().into()
};
push_value(&mut self.value_stack, global_type)?;
Ok(())
}
2019-04-05 21:21:19 +00:00
fn validate_set_global(&mut self, index: u32) -> Result<(), Error> {
2019-04-05 16:48:45 +00:00
let global_type: StackValueType = {
let global = self.module.require_global(index, Some(true))?;
global.content_type().into()
};
let value_type = pop_value(
&mut self.value_stack,
&self.frame_stack,
StackValueType::Any,
)?;
if global_type != value_type {
return Err(Error(format!(
"Trying to update global {} of type {:?} with value of type {:?}",
index, global_type, value_type
)));
}
Ok(())
}
fn validate_load(
&mut self,
align: u32,
max_align: u32,
value_type: ValueType,
) -> Result<(), Error> {
if 1u32.checked_shl(align).unwrap_or(u32::MAX) > max_align {
return Err(Error(format!(
"Too large memory alignment 2^{} (expected at most {})",
align, max_align
)));
}
pop_value(
&mut self.value_stack,
&self.frame_stack,
ValueType::I32.into(),
)?;
self.module.require_memory(DEFAULT_MEMORY_INDEX)?;
push_value(&mut self.value_stack, value_type.into())?;
Ok(())
}
fn validate_store(
&mut self,
align: u32,
max_align: u32,
value_type: ValueType,
) -> Result<(), Error> {
if 1u32.checked_shl(align).unwrap_or(u32::MAX) > max_align {
return Err(Error(format!(
"Too large memory alignment 2^{} (expected at most {})",
align, max_align
)));
}
self.module.require_memory(DEFAULT_MEMORY_INDEX)?;
2019-04-05 21:21:19 +00:00
pop_value(&mut self.value_stack, &self.frame_stack, value_type.into())?;
2019-04-05 16:48:45 +00:00
pop_value(
&mut self.value_stack,
&self.frame_stack,
ValueType::I32.into(),
)?;
Ok(())
}
fn validate_br(&mut self, depth: u32) -> Result<(), Error> {
let (started_with, frame_block_type) = {
let frame = require_label(depth, &self.frame_stack)?;
(frame.started_with, frame.block_type)
};
if started_with != StartedWith::Loop {
if let BlockType::Value(value_type) = frame_block_type {
2019-04-05 21:21:19 +00:00
tee_value(&mut self.value_stack, &self.frame_stack, value_type.into())?;
2019-04-05 16:48:45 +00:00
}
}
Ok(())
}
fn validate_br_if(&mut self, depth: u32) -> Result<(), Error> {
pop_value(
&mut self.value_stack,
&self.frame_stack,
ValueType::I32.into(),
)?;
let (started_with, frame_block_type) = {
let frame = require_label(depth, &self.frame_stack)?;
(frame.started_with, frame.block_type)
};
if started_with != StartedWith::Loop {
if let BlockType::Value(value_type) = frame_block_type {
2019-04-05 21:21:19 +00:00
tee_value(&mut self.value_stack, &self.frame_stack, value_type.into())?;
2019-04-05 16:48:45 +00:00
}
}
Ok(())
}
2019-04-05 21:21:19 +00:00
fn validate_br_table(&mut self, table: &[u32], default: u32) -> Result<(), Error> {
2019-04-05 16:48:45 +00:00
let required_block_type: BlockType = {
let default_block = require_label(default, &self.frame_stack)?;
let required_block_type = if default_block.started_with == StartedWith::Loop {
BlockType::NoResult
} else {
default_block.block_type
};
for label in table {
let label_block = require_label(*label, &self.frame_stack)?;
let label_block_type = if label_block.started_with == StartedWith::Loop {
BlockType::NoResult
} else {
label_block.block_type
};
if required_block_type != label_block_type {
return Err(Error(format!(
"Labels in br_table points to block of different types: {:?} and {:?}",
required_block_type, label_block.block_type
)));
}
}
required_block_type
};
pop_value(
&mut self.value_stack,
&self.frame_stack,
ValueType::I32.into(),
)?;
if let BlockType::Value(value_type) = required_block_type {
2019-04-05 21:21:19 +00:00
tee_value(&mut self.value_stack, &self.frame_stack, value_type.into())?;
2019-04-05 16:48:45 +00:00
}
Ok(())
}
fn validate_call(&mut self, idx: u32) -> Result<(), Error> {
let (argument_types, return_type) = self.module.require_function(idx)?;
for argument_type in argument_types.iter().rev() {
pop_value(
&mut self.value_stack,
&self.frame_stack,
(*argument_type).into(),
)?;
}
if let BlockType::Value(value_type) = return_type {
push_value(&mut self.value_stack, value_type.into())?;
}
Ok(())
}
2019-04-05 21:21:19 +00:00
fn validate_call_indirect(&mut self, idx: u32) -> Result<(), Error> {
2019-04-05 16:48:45 +00:00
{
let table = self.module.require_table(DEFAULT_TABLE_INDEX)?;
if table.elem_type() != TableElementType::AnyFunc {
return Err(Error(format!(
"Table {} has element type {:?} while `anyfunc` expected",
idx,
table.elem_type()
)));
}
}
pop_value(
&mut self.value_stack,
&self.frame_stack,
ValueType::I32.into(),
)?;
let (argument_types, return_type) = self.module.require_function_type(idx)?;
for argument_type in argument_types.iter().rev() {
pop_value(
&mut self.value_stack,
&self.frame_stack,
(*argument_type).into(),
)?;
}
if let BlockType::Value(value_type) = return_type {
push_value(&mut self.value_stack, value_type.into())?;
}
Ok(())
}
fn validate_current_memory(&mut self) -> Result<(), Error> {
self.module.require_memory(DEFAULT_MEMORY_INDEX)?;
push_value(&mut self.value_stack, ValueType::I32.into())?;
Ok(())
}
fn validate_grow_memory(&mut self) -> Result<(), Error> {
self.module.require_memory(DEFAULT_MEMORY_INDEX)?;
pop_value(
&mut self.value_stack,
&self.frame_stack,
ValueType::I32.into(),
)?;
push_value(&mut self.value_stack, ValueType::I32.into())?;
Ok(())
}
}
fn make_top_frame_polymorphic(
2018-12-11 11:54:06 +00:00
value_stack: &mut StackWithLimit<StackValueType>,
frame_stack: &mut StackWithLimit<BlockFrame>,
) {
2018-12-11 11:54:06 +00:00
let frame = frame_stack
.top_mut()
.expect("make_top_frame_polymorphic is called with empty frame stack");
value_stack.resize(frame.value_stack_len, StackValueType::Any);
frame.polymorphic_stack = true;
}
fn push_value(
2018-12-11 11:54:06 +00:00
value_stack: &mut StackWithLimit<StackValueType>,
value_type: StackValueType,
) -> Result<(), Error> {
2018-12-11 11:54:06 +00:00
Ok(value_stack.push(value_type.into())?)
}
fn pop_value(
2018-12-11 11:54:06 +00:00
value_stack: &mut StackWithLimit<StackValueType>,
frame_stack: &StackWithLimit<BlockFrame>,
2019-04-16 14:36:16 +00:00
expected_value_ty: StackValueType,
) -> Result<StackValueType, Error> {
2018-12-11 11:54:06 +00:00
let (is_stack_polymorphic, label_value_stack_len) = {
let frame = top_label(frame_stack);
(frame.polymorphic_stack, frame.value_stack_len)
};
let stack_is_empty = value_stack.len() == label_value_stack_len;
let actual_value = if stack_is_empty && is_stack_polymorphic {
StackValueType::Any
} else {
let value_stack_min = frame_stack
.top()
.expect("at least 1 topmost block")
.value_stack_len;
if value_stack.len() <= value_stack_min {
return Err(Error("Trying to access parent frame stack values.".into()));
}
value_stack.pop()?
};
match actual_value {
2019-04-16 14:36:16 +00:00
StackValueType::Specific(stack_value_type) if stack_value_type == expected_value_ty => {
2018-12-11 11:54:06 +00:00
Ok(actual_value)
}
StackValueType::Any => Ok(actual_value),
stack_value_type @ _ => Err(Error(format!(
"Expected value of type {:?} on top of stack. Got {:?}",
2019-04-16 14:36:16 +00:00
expected_value_ty, stack_value_type
2018-12-11 11:54:06 +00:00
))),
}
}
2018-01-17 15:32:33 +00:00
fn tee_value(
2018-12-11 11:54:06 +00:00
value_stack: &mut StackWithLimit<StackValueType>,
frame_stack: &StackWithLimit<BlockFrame>,
value_type: StackValueType,
) -> Result<(), Error> {
2018-12-11 11:54:06 +00:00
let _ = pop_value(value_stack, frame_stack, value_type)?;
push_value(value_stack, value_type)?;
Ok(())
}
2018-01-17 15:32:33 +00:00
fn push_label(
2019-04-05 11:38:12 +00:00
started_with: StartedWith,
2018-12-11 11:54:06 +00:00
block_type: BlockType,
value_stack: &StackWithLimit<StackValueType>,
frame_stack: &mut StackWithLimit<BlockFrame>,
) -> Result<(), Error> {
2018-12-11 11:54:06 +00:00
Ok(frame_stack.push(BlockFrame {
2019-04-05 11:38:12 +00:00
started_with,
2018-12-11 11:54:06 +00:00
block_type: block_type,
value_stack_len: value_stack.len(),
polymorphic_stack: false,
})?)
}
// TODO: Refactor
fn pop_label(
2018-12-11 11:54:06 +00:00
value_stack: &mut StackWithLimit<StackValueType>,
frame_stack: &mut StackWithLimit<BlockFrame>,
) -> Result<(), Error> {
2018-12-11 11:54:06 +00:00
// Don't pop frame yet. This is essential since we still might pop values from the value stack
// and this in turn requires current frame to check whether or not we've reached
// unreachable.
let block_type = frame_stack.top()?.block_type;
match block_type {
BlockType::NoResult => (),
BlockType::Value(required_value_type) => {
let _ = pop_value(
value_stack,
frame_stack,
StackValueType::Specific(required_value_type),
)?;
}
}
let frame = frame_stack.pop()?;
if value_stack.len() != frame.value_stack_len {
return Err(Error(format!(
"Unexpected stack height {}, expected {}",
value_stack.len(),
frame.value_stack_len
)));
}
Ok(())
}
2019-04-16 14:35:16 +00:00
/// Returns the top most frame from the frame stack.
///
/// # Panics
///
/// Can be called only when the frame stack is not empty: that is, it is ok to call this function
/// after initialization of the validation and until the validation reached the latest `End`
/// operator.
2019-04-08 14:20:21 +00:00
pub fn top_label(frame_stack: &StackWithLimit<BlockFrame>) -> &BlockFrame {
2018-12-11 11:54:06 +00:00
frame_stack
.top()
.expect("this function can't be called with empty frame stack")
}
2019-04-08 14:20:21 +00:00
pub fn require_label(
2018-12-11 11:54:06 +00:00
depth: u32,
frame_stack: &StackWithLimit<BlockFrame>,
) -> Result<&BlockFrame, Error> {
2018-12-11 11:54:06 +00:00
Ok(frame_stack.get(depth as usize)?)
}
fn require_local(locals: &Locals, idx: u32) -> Result<ValueType, Error> {
2018-12-11 11:54:06 +00:00
Ok(locals.type_of_local(idx)?)
}