optimize drop_keep
This commit is contained in:
parent
76c104ddc0
commit
57c48ecada
|
@ -1,3 +1,2 @@
|
||||||
/target
|
target
|
||||||
*.trace
|
*.trace
|
||||||
|
|
||||||
|
|
|
@ -92,14 +92,10 @@ impl<T> StackWithLimit<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn pop(&mut self) -> Option<T> {
|
pub(crate) fn pop(&mut self) -> Option<T> {
|
||||||
debug_assert!(
|
|
||||||
self.stack.len() <= self.limit,
|
|
||||||
"Stack length should never be larger than stack limit."
|
|
||||||
);
|
|
||||||
self.stack.pop()
|
self.stack.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return optional reference to item in stack
|
/// Return optional reference to item `depth` distance away from top
|
||||||
///
|
///
|
||||||
/// `bstack.get_relative_to_top(0)` gets the top of the stack
|
/// `bstack.get_relative_to_top(0)` gets the top of the stack
|
||||||
///
|
///
|
||||||
|
@ -112,17 +108,44 @@ impl<T> StackWithLimit<T> {
|
||||||
// In debug builds, underflow panics, but in release mode, underflow is not checked.
|
// In debug builds, underflow panics, but in release mode, underflow is not checked.
|
||||||
|
|
||||||
let index = self.stack.len().checked_sub(1)?.checked_sub(depth)?;
|
let index = self.stack.len().checked_sub(1)?.checked_sub(depth)?;
|
||||||
self.stack.get(index)
|
debug_assert!(self.stack.len() > index, "guaranteed by previous line");
|
||||||
|
Some(&self.stack[index])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// mutable version of get_relative_to_top
|
/// Return mutable reference to item `depth` distance away from top
|
||||||
///
|
///
|
||||||
/// `bstack.get_relative_to_top(0)` gets the top of the stack
|
/// Does not check whether depth is in range.
|
||||||
|
pub(crate) fn get_relative_to_top_mut_unchecked(&mut self, depth: usize) -> &mut T {
|
||||||
|
let offset = self.stack.len() - 1 - depth;
|
||||||
|
&mut self.stack[offset]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Swaps two elements in the stack.
|
||||||
///
|
///
|
||||||
/// `bstack.get_relative_to_top(1)` gets the item just below the stack
|
/// # Arguments
|
||||||
pub(crate) fn get_relative_to_top_mut(&mut self, depth: usize) -> Option<&mut T> {
|
///
|
||||||
let index = self.stack.len().checked_sub(1)?.checked_sub(depth)?;
|
/// * a - The index of the first element
|
||||||
self.stack.get_mut(index)
|
/// * b - The index of the second element
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if `a` or `b` are out of bound.
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn swap(&mut self, a: usize, b: usize) {
|
||||||
|
self.stack.swap(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes an element from the vector and returns it.
|
||||||
|
///
|
||||||
|
/// The removed element is replaced by the last element of the vector.
|
||||||
|
///
|
||||||
|
/// This does not preserve ordering, but is O(1).
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if `index` is out of bounds.
|
||||||
|
pub fn swap_remove(&mut self, index: usize) -> T {
|
||||||
|
self.stack.swap_remove(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn top(&self) -> Option<&T> {
|
pub(crate) fn top(&self) -> Option<&T> {
|
||||||
|
@ -138,6 +161,7 @@ impl<T> StackWithLimit<T> {
|
||||||
self.stack.truncate(new_size)
|
self.stack.truncate(new_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub(crate) fn len(&self) -> usize {
|
pub(crate) fn len(&self) -> usize {
|
||||||
self.stack.len()
|
self.stack.len()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1255,24 +1255,18 @@ struct ValueStack(StackWithLimit<RuntimeValueInternal>);
|
||||||
impl ValueStack {
|
impl ValueStack {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn drop_keep(&mut self, drop_keep: isa::DropKeep) {
|
fn drop_keep(&mut self, drop_keep: isa::DropKeep) {
|
||||||
|
let drop = drop_keep.drop as usize;
|
||||||
|
let len = self.0.len();
|
||||||
match drop_keep.keep {
|
match drop_keep.keep {
|
||||||
isa::Keep::Single => {
|
isa::Keep::Single => {
|
||||||
let top = *self.top(); // takes a copy
|
debug_assert!(drop < len);
|
||||||
let pick = self
|
self.0.swap(len - 1 - drop, len - 1)
|
||||||
.0
|
}
|
||||||
.get_relative_to_top_mut(drop_keep.drop as usize)
|
isa::Keep::None => {
|
||||||
.expect("pre-validated");
|
debug_assert!(drop <= len, "Attempted to drop more items than were in stack.");
|
||||||
*pick = top;
|
|
||||||
}
|
}
|
||||||
isa::Keep::None => {}
|
|
||||||
};
|
};
|
||||||
self.drop_many(drop_keep.drop as usize);
|
self.0.truncate(len - drop);
|
||||||
}
|
|
||||||
|
|
||||||
fn drop_many(&mut self, count: usize) {
|
|
||||||
debug_assert!(count <= self.len(), "Attempted to drop more items than were in stack.");
|
|
||||||
let new_len = self.0.len().checked_sub(count).unwrap_or(0);
|
|
||||||
self.0.truncate(new_len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -1310,7 +1304,7 @@ impl ValueStack {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn pick_mut(&mut self, depth: usize) -> &mut RuntimeValueInternal {
|
fn pick_mut(&mut self, depth: usize) -> &mut RuntimeValueInternal {
|
||||||
self.0.get_relative_to_top_mut(depth - 1).expect("pre-validated")
|
self.0.get_relative_to_top_mut_unchecked(depth - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -2,9 +2,7 @@
|
||||||
use alloc::prelude::*;
|
use alloc::prelude::*;
|
||||||
use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX};
|
use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX};
|
||||||
use core::u32;
|
use core::u32;
|
||||||
use parity_wasm::elements::{
|
use parity_wasm::elements::{BlockType, Func, FuncBody, Instruction, TableElementType, ValueType};
|
||||||
BlockType, Func, FuncBody, Instruction, TableElementType, ValueType,
|
|
||||||
};
|
|
||||||
use validation::context::ModuleContext;
|
use validation::context::ModuleContext;
|
||||||
|
|
||||||
use validation::util::Locals;
|
use validation::util::Locals;
|
||||||
|
@ -160,11 +158,7 @@ enum Outcome {
|
||||||
pub struct FunctionReader;
|
pub struct FunctionReader;
|
||||||
|
|
||||||
impl FunctionReader {
|
impl FunctionReader {
|
||||||
pub fn read_function(
|
pub fn read_function(module: &ModuleContext, func: &Func, body: &FuncBody) -> Result<isa::Instructions, Error> {
|
||||||
module: &ModuleContext,
|
|
||||||
func: &Func,
|
|
||||||
body: &FuncBody,
|
|
||||||
) -> Result<isa::Instructions, Error> {
|
|
||||||
let (params, result_ty) = module.require_function_type(func.type_ref())?;
|
let (params, result_ty) = module.require_function_type(func.type_ref())?;
|
||||||
|
|
||||||
let ins_size_estimate = body.code().elements().len();
|
let ins_size_estimate = body.code().elements().len();
|
||||||
|
@ -192,10 +186,7 @@ impl FunctionReader {
|
||||||
Ok(context.into_code())
|
Ok(context.into_code())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_function_body(
|
fn read_function_body(context: &mut FunctionValidationContext, body: &[Instruction]) -> Result<(), Error> {
|
||||||
context: &mut FunctionValidationContext,
|
|
||||||
body: &[Instruction],
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let body_len = body.len();
|
let body_len = body.len();
|
||||||
if body_len == 0 {
|
if body_len == 0 {
|
||||||
return Err(Error("Non-empty function body expected".into()));
|
return Err(Error("Non-empty function body expected".into()));
|
||||||
|
@ -204,8 +195,7 @@ impl FunctionReader {
|
||||||
loop {
|
loop {
|
||||||
let instruction = &body[context.position];
|
let instruction = &body[context.position];
|
||||||
|
|
||||||
let outcome =
|
let outcome = FunctionReader::read_instruction(context, instruction).map_err(|err| {
|
||||||
FunctionReader::read_instruction(context, instruction).map_err(|err| {
|
|
||||||
Error(format!(
|
Error(format!(
|
||||||
"At instruction {:?}(@{}): {}",
|
"At instruction {:?}(@{}): {}",
|
||||||
instruction, context.position, err
|
instruction, context.position, err
|
||||||
|
@ -214,9 +204,7 @@ impl FunctionReader {
|
||||||
|
|
||||||
match outcome {
|
match outcome {
|
||||||
Outcome::NextInstruction => (),
|
Outcome::NextInstruction => (),
|
||||||
Outcome::Unreachable => {
|
Outcome::Unreachable => make_top_frame_polymorphic(&mut context.value_stack, &mut context.frame_stack),
|
||||||
make_top_frame_polymorphic(&mut context.value_stack, &mut context.frame_stack)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context.position += 1;
|
context.position += 1;
|
||||||
|
@ -226,10 +214,7 @@ impl FunctionReader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_instruction(
|
fn read_instruction(context: &mut FunctionValidationContext, instruction: &Instruction) -> Result<Outcome, Error> {
|
||||||
context: &mut FunctionValidationContext,
|
|
||||||
instruction: &Instruction,
|
|
||||||
) -> Result<Outcome, Error> {
|
|
||||||
use self::Instruction::*;
|
use self::Instruction::*;
|
||||||
|
|
||||||
match *instruction {
|
match *instruction {
|
||||||
|
@ -270,11 +255,7 @@ impl FunctionReader {
|
||||||
let if_not = context.sink.new_label();
|
let if_not = context.sink.new_label();
|
||||||
let end_label = context.sink.new_label();
|
let end_label = context.sink.new_label();
|
||||||
|
|
||||||
pop_value(
|
pop_value(&mut context.value_stack, &context.frame_stack, ValueType::I32.into())?;
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
ValueType::I32.into(),
|
|
||||||
)?;
|
|
||||||
push_label(
|
push_label(
|
||||||
BlockFrameType::IfTrue { if_not, end_label },
|
BlockFrameType::IfTrue { if_not, end_label },
|
||||||
block_type,
|
block_type,
|
||||||
|
@ -359,22 +340,12 @@ impl FunctionReader {
|
||||||
|
|
||||||
// Check the return type.
|
// Check the return type.
|
||||||
if let BlockType::Value(value_type) = context.return_type()? {
|
if let BlockType::Value(value_type) = context.return_type()? {
|
||||||
tee_value(
|
tee_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
value_type.into(),
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit the return instruction.
|
// Emit the return instruction.
|
||||||
let drop_keep = drop_keep_return(
|
let drop_keep = drop_keep_return(&context.locals, &context.value_stack, &context.frame_stack);
|
||||||
&context.locals,
|
context.sink.emit(isa::InstructionInternal::Return(drop_keep));
|
||||||
&context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
);
|
|
||||||
context
|
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::Return(drop_keep));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pop_label(&mut context.value_stack, &mut context.frame_stack)?;
|
pop_label(&mut context.value_stack, &mut context.frame_stack)?;
|
||||||
|
@ -406,26 +377,18 @@ impl FunctionReader {
|
||||||
let target = require_target(*depth, &context.value_stack, &context.frame_stack);
|
let target = require_target(*depth, &context.value_stack, &context.frame_stack);
|
||||||
targets.push(target);
|
targets.push(target);
|
||||||
}
|
}
|
||||||
let default_target =
|
let default_target = require_target(default, &context.value_stack, &context.frame_stack);
|
||||||
require_target(default, &context.value_stack, &context.frame_stack);
|
|
||||||
context.sink.emit_br_table(&targets, default_target);
|
context.sink.emit_br_table(&targets, default_target);
|
||||||
|
|
||||||
return Ok(Outcome::Unreachable);
|
return Ok(Outcome::Unreachable);
|
||||||
}
|
}
|
||||||
Return => {
|
Return => {
|
||||||
if let BlockType::Value(value_type) = context.return_type()? {
|
if let BlockType::Value(value_type) = context.return_type()? {
|
||||||
tee_value(
|
tee_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
value_type.into(),
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let drop_keep =
|
let drop_keep = drop_keep_return(&context.locals, &context.value_stack, &context.frame_stack);
|
||||||
drop_keep_return(&context.locals, &context.value_stack, &context.frame_stack);
|
context.sink.emit(isa::InstructionInternal::Return(drop_keep));
|
||||||
context
|
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::Return(drop_keep));
|
|
||||||
|
|
||||||
return Ok(Outcome::Unreachable);
|
return Ok(Outcome::Unreachable);
|
||||||
}
|
}
|
||||||
|
@ -436,9 +399,7 @@ impl FunctionReader {
|
||||||
}
|
}
|
||||||
CallIndirect(index, _reserved) => {
|
CallIndirect(index, _reserved) => {
|
||||||
Validator::validate_call_indirect(context, index)?;
|
Validator::validate_call_indirect(context, index)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::CallIndirect(index));
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::CallIndirect(index));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Drop => {
|
Drop => {
|
||||||
|
@ -469,15 +430,11 @@ impl FunctionReader {
|
||||||
}
|
}
|
||||||
GetGlobal(index) => {
|
GetGlobal(index) => {
|
||||||
Validator::validate_get_global(context, index)?;
|
Validator::validate_get_global(context, index)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::GetGlobal(index));
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::GetGlobal(index));
|
|
||||||
}
|
}
|
||||||
SetGlobal(index) => {
|
SetGlobal(index) => {
|
||||||
Validator::validate_set_global(context, index)?;
|
Validator::validate_set_global(context, index)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::SetGlobal(index));
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::SetGlobal(index));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
I32Load(align, offset) => {
|
I32Load(align, offset) => {
|
||||||
|
@ -498,118 +455,80 @@ impl FunctionReader {
|
||||||
}
|
}
|
||||||
I32Load8S(align, offset) => {
|
I32Load8S(align, offset) => {
|
||||||
Validator::validate_load(context, align, 1, ValueType::I32)?;
|
Validator::validate_load(context, align, 1, ValueType::I32)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::I32Load8S(offset));
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::I32Load8S(offset));
|
|
||||||
}
|
}
|
||||||
I32Load8U(align, offset) => {
|
I32Load8U(align, offset) => {
|
||||||
Validator::validate_load(context, align, 1, ValueType::I32)?;
|
Validator::validate_load(context, align, 1, ValueType::I32)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::I32Load8U(offset));
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::I32Load8U(offset));
|
|
||||||
}
|
}
|
||||||
I32Load16S(align, offset) => {
|
I32Load16S(align, offset) => {
|
||||||
Validator::validate_load(context, align, 2, ValueType::I32)?;
|
Validator::validate_load(context, align, 2, ValueType::I32)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::I32Load16S(offset));
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::I32Load16S(offset));
|
|
||||||
}
|
}
|
||||||
I32Load16U(align, offset) => {
|
I32Load16U(align, offset) => {
|
||||||
Validator::validate_load(context, align, 2, ValueType::I32)?;
|
Validator::validate_load(context, align, 2, ValueType::I32)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::I32Load16U(offset));
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::I32Load16U(offset));
|
|
||||||
}
|
}
|
||||||
I64Load8S(align, offset) => {
|
I64Load8S(align, offset) => {
|
||||||
Validator::validate_load(context, align, 1, ValueType::I64)?;
|
Validator::validate_load(context, align, 1, ValueType::I64)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::I64Load8S(offset));
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::I64Load8S(offset));
|
|
||||||
}
|
}
|
||||||
I64Load8U(align, offset) => {
|
I64Load8U(align, offset) => {
|
||||||
Validator::validate_load(context, align, 1, ValueType::I64)?;
|
Validator::validate_load(context, align, 1, ValueType::I64)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::I64Load8U(offset));
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::I64Load8U(offset));
|
|
||||||
}
|
}
|
||||||
I64Load16S(align, offset) => {
|
I64Load16S(align, offset) => {
|
||||||
Validator::validate_load(context, align, 2, ValueType::I64)?;
|
Validator::validate_load(context, align, 2, ValueType::I64)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::I64Load16S(offset));
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::I64Load16S(offset));
|
|
||||||
}
|
}
|
||||||
I64Load16U(align, offset) => {
|
I64Load16U(align, offset) => {
|
||||||
Validator::validate_load(context, align, 2, ValueType::I64)?;
|
Validator::validate_load(context, align, 2, ValueType::I64)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::I64Load16U(offset));
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::I64Load16U(offset));
|
|
||||||
}
|
}
|
||||||
I64Load32S(align, offset) => {
|
I64Load32S(align, offset) => {
|
||||||
Validator::validate_load(context, align, 4, ValueType::I64)?;
|
Validator::validate_load(context, align, 4, ValueType::I64)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::I64Load32S(offset));
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::I64Load32S(offset));
|
|
||||||
}
|
}
|
||||||
I64Load32U(align, offset) => {
|
I64Load32U(align, offset) => {
|
||||||
Validator::validate_load(context, align, 4, ValueType::I64)?;
|
Validator::validate_load(context, align, 4, ValueType::I64)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::I64Load32U(offset));
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::I64Load32U(offset));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
I32Store(align, offset) => {
|
I32Store(align, offset) => {
|
||||||
Validator::validate_store(context, align, 4, ValueType::I32)?;
|
Validator::validate_store(context, align, 4, ValueType::I32)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::I32Store(offset));
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::I32Store(offset));
|
|
||||||
}
|
}
|
||||||
I64Store(align, offset) => {
|
I64Store(align, offset) => {
|
||||||
Validator::validate_store(context, align, 8, ValueType::I64)?;
|
Validator::validate_store(context, align, 8, ValueType::I64)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::I64Store(offset));
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::I64Store(offset));
|
|
||||||
}
|
}
|
||||||
F32Store(align, offset) => {
|
F32Store(align, offset) => {
|
||||||
Validator::validate_store(context, align, 4, ValueType::F32)?;
|
Validator::validate_store(context, align, 4, ValueType::F32)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::F32Store(offset));
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::F32Store(offset));
|
|
||||||
}
|
}
|
||||||
F64Store(align, offset) => {
|
F64Store(align, offset) => {
|
||||||
Validator::validate_store(context, align, 8, ValueType::F64)?;
|
Validator::validate_store(context, align, 8, ValueType::F64)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::F64Store(offset));
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::F64Store(offset));
|
|
||||||
}
|
}
|
||||||
I32Store8(align, offset) => {
|
I32Store8(align, offset) => {
|
||||||
Validator::validate_store(context, align, 1, ValueType::I32)?;
|
Validator::validate_store(context, align, 1, ValueType::I32)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::I32Store8(offset));
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::I32Store8(offset));
|
|
||||||
}
|
}
|
||||||
I32Store16(align, offset) => {
|
I32Store16(align, offset) => {
|
||||||
Validator::validate_store(context, align, 2, ValueType::I32)?;
|
Validator::validate_store(context, align, 2, ValueType::I32)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::I32Store16(offset));
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::I32Store16(offset));
|
|
||||||
}
|
}
|
||||||
I64Store8(align, offset) => {
|
I64Store8(align, offset) => {
|
||||||
Validator::validate_store(context, align, 1, ValueType::I64)?;
|
Validator::validate_store(context, align, 1, ValueType::I64)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::I64Store8(offset));
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::I64Store8(offset));
|
|
||||||
}
|
}
|
||||||
I64Store16(align, offset) => {
|
I64Store16(align, offset) => {
|
||||||
Validator::validate_store(context, align, 2, ValueType::I64)?;
|
Validator::validate_store(context, align, 2, ValueType::I64)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::I64Store16(offset));
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::I64Store16(offset));
|
|
||||||
}
|
}
|
||||||
I64Store32(align, offset) => {
|
I64Store32(align, offset) => {
|
||||||
Validator::validate_store(context, align, 4, ValueType::I64)?;
|
Validator::validate_store(context, align, 4, ValueType::I64)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::I64Store32(offset));
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::I64Store32(offset));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentMemory(_) => {
|
CurrentMemory(_) => {
|
||||||
|
@ -1125,27 +1044,19 @@ impl FunctionReader {
|
||||||
|
|
||||||
I32ReinterpretF32 => {
|
I32ReinterpretF32 => {
|
||||||
Validator::validate_cvtop(context, ValueType::F32, ValueType::I32)?;
|
Validator::validate_cvtop(context, ValueType::F32, ValueType::I32)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::I32ReinterpretF32);
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::I32ReinterpretF32);
|
|
||||||
}
|
}
|
||||||
I64ReinterpretF64 => {
|
I64ReinterpretF64 => {
|
||||||
Validator::validate_cvtop(context, ValueType::F64, ValueType::I64)?;
|
Validator::validate_cvtop(context, ValueType::F64, ValueType::I64)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::I64ReinterpretF64);
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::I64ReinterpretF64);
|
|
||||||
}
|
}
|
||||||
F32ReinterpretI32 => {
|
F32ReinterpretI32 => {
|
||||||
Validator::validate_cvtop(context, ValueType::I32, ValueType::F32)?;
|
Validator::validate_cvtop(context, ValueType::I32, ValueType::F32)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::F32ReinterpretI32);
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::F32ReinterpretI32);
|
|
||||||
}
|
}
|
||||||
F64ReinterpretI64 => {
|
F64ReinterpretI64 => {
|
||||||
Validator::validate_cvtop(context, ValueType::I64, ValueType::F64)?;
|
Validator::validate_cvtop(context, ValueType::I64, ValueType::F64)?;
|
||||||
context
|
context.sink.emit(isa::InstructionInternal::F64ReinterpretI64);
|
||||||
.sink
|
|
||||||
.emit(isa::InstructionInternal::F64ReinterpretI64);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1157,72 +1068,33 @@ impl FunctionReader {
|
||||||
struct Validator;
|
struct Validator;
|
||||||
|
|
||||||
impl Validator {
|
impl Validator {
|
||||||
fn validate_const(
|
fn validate_const(context: &mut FunctionValidationContext, value_type: ValueType) -> Result<(), Error> {
|
||||||
context: &mut FunctionValidationContext,
|
|
||||||
value_type: ValueType,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
push_value(&mut context.value_stack, value_type.into())?;
|
push_value(&mut context.value_stack, value_type.into())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_unop(
|
fn validate_unop(context: &mut FunctionValidationContext, value_type: ValueType) -> Result<(), Error> {
|
||||||
context: &mut FunctionValidationContext,
|
pop_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
|
||||||
value_type: ValueType,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
pop_value(
|
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
value_type.into(),
|
|
||||||
)?;
|
|
||||||
push_value(&mut context.value_stack, value_type.into())?;
|
push_value(&mut context.value_stack, value_type.into())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_binop(
|
fn validate_binop(context: &mut FunctionValidationContext, value_type: ValueType) -> Result<(), Error> {
|
||||||
context: &mut FunctionValidationContext,
|
pop_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
|
||||||
value_type: ValueType,
|
pop_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
|
||||||
) -> Result<(), Error> {
|
|
||||||
pop_value(
|
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
value_type.into(),
|
|
||||||
)?;
|
|
||||||
pop_value(
|
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
value_type.into(),
|
|
||||||
)?;
|
|
||||||
push_value(&mut context.value_stack, value_type.into())?;
|
push_value(&mut context.value_stack, value_type.into())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_testop(
|
fn validate_testop(context: &mut FunctionValidationContext, value_type: ValueType) -> Result<(), Error> {
|
||||||
context: &mut FunctionValidationContext,
|
pop_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
|
||||||
value_type: ValueType,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
pop_value(
|
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
value_type.into(),
|
|
||||||
)?;
|
|
||||||
push_value(&mut context.value_stack, ValueType::I32.into())?;
|
push_value(&mut context.value_stack, ValueType::I32.into())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_relop(
|
fn validate_relop(context: &mut FunctionValidationContext, value_type: ValueType) -> Result<(), Error> {
|
||||||
context: &mut FunctionValidationContext,
|
pop_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
|
||||||
value_type: ValueType,
|
pop_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
|
||||||
) -> Result<(), Error> {
|
|
||||||
pop_value(
|
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
value_type.into(),
|
|
||||||
)?;
|
|
||||||
pop_value(
|
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
value_type.into(),
|
|
||||||
)?;
|
|
||||||
push_value(&mut context.value_stack, ValueType::I32.into())?;
|
push_value(&mut context.value_stack, ValueType::I32.into())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1232,59 +1104,33 @@ impl Validator {
|
||||||
value_type1: ValueType,
|
value_type1: ValueType,
|
||||||
value_type2: ValueType,
|
value_type2: ValueType,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
pop_value(
|
pop_value(&mut context.value_stack, &context.frame_stack, value_type1.into())?;
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
value_type1.into(),
|
|
||||||
)?;
|
|
||||||
push_value(&mut context.value_stack, value_type2.into())?;
|
push_value(&mut context.value_stack, value_type2.into())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_drop(context: &mut FunctionValidationContext) -> Result<(), Error> {
|
fn validate_drop(context: &mut FunctionValidationContext) -> Result<(), Error> {
|
||||||
pop_value(
|
pop_value(&mut context.value_stack, &context.frame_stack, StackValueType::Any)?;
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
StackValueType::Any,
|
|
||||||
)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_select(context: &mut FunctionValidationContext) -> Result<(), Error> {
|
fn validate_select(context: &mut FunctionValidationContext) -> Result<(), Error> {
|
||||||
pop_value(
|
pop_value(&mut context.value_stack, &context.frame_stack, ValueType::I32.into())?;
|
||||||
&mut context.value_stack,
|
let select_type = pop_value(&mut context.value_stack, &context.frame_stack, StackValueType::Any)?;
|
||||||
&context.frame_stack,
|
|
||||||
ValueType::I32.into(),
|
|
||||||
)?;
|
|
||||||
let select_type = pop_value(
|
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
StackValueType::Any,
|
|
||||||
)?;
|
|
||||||
pop_value(&mut context.value_stack, &context.frame_stack, select_type)?;
|
pop_value(&mut context.value_stack, &context.frame_stack, select_type)?;
|
||||||
push_value(&mut context.value_stack, select_type)?;
|
push_value(&mut context.value_stack, select_type)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_get_local(
|
fn validate_get_local(context: &mut FunctionValidationContext, index: u32) -> Result<(), Error> {
|
||||||
context: &mut FunctionValidationContext,
|
|
||||||
index: u32,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let local_type = require_local(&context.locals, index)?;
|
let local_type = require_local(&context.locals, index)?;
|
||||||
push_value(&mut context.value_stack, local_type.into())?;
|
push_value(&mut context.value_stack, local_type.into())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_set_local(
|
fn validate_set_local(context: &mut FunctionValidationContext, index: u32) -> Result<(), Error> {
|
||||||
context: &mut FunctionValidationContext,
|
|
||||||
index: u32,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let local_type = require_local(&context.locals, index)?;
|
let local_type = require_local(&context.locals, index)?;
|
||||||
let value_type = pop_value(
|
let value_type = pop_value(&mut context.value_stack, &context.frame_stack, StackValueType::Any)?;
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
StackValueType::Any,
|
|
||||||
)?;
|
|
||||||
if StackValueType::from(local_type) != value_type {
|
if StackValueType::from(local_type) != value_type {
|
||||||
return Err(Error(format!(
|
return Err(Error(format!(
|
||||||
"Trying to update local {} of type {:?} with value of type {:?}",
|
"Trying to update local {} of type {:?} with value of type {:?}",
|
||||||
|
@ -1294,23 +1140,13 @@ impl Validator {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_tee_local(
|
fn validate_tee_local(context: &mut FunctionValidationContext, index: u32) -> Result<(), Error> {
|
||||||
context: &mut FunctionValidationContext,
|
|
||||||
index: u32,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let local_type = require_local(&context.locals, index)?;
|
let local_type = require_local(&context.locals, index)?;
|
||||||
tee_value(
|
tee_value(&mut context.value_stack, &context.frame_stack, local_type.into())?;
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
local_type.into(),
|
|
||||||
)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_get_global(
|
fn validate_get_global(context: &mut FunctionValidationContext, index: u32) -> Result<(), Error> {
|
||||||
context: &mut FunctionValidationContext,
|
|
||||||
index: u32,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let global_type: StackValueType = {
|
let global_type: StackValueType = {
|
||||||
let global = context.module.require_global(index, None)?;
|
let global = context.module.require_global(index, None)?;
|
||||||
global.content_type().into()
|
global.content_type().into()
|
||||||
|
@ -1319,19 +1155,12 @@ impl Validator {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_set_global(
|
fn validate_set_global(context: &mut FunctionValidationContext, index: u32) -> Result<(), Error> {
|
||||||
context: &mut FunctionValidationContext,
|
|
||||||
index: u32,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let global_type: StackValueType = {
|
let global_type: StackValueType = {
|
||||||
let global = context.module.require_global(index, Some(true))?;
|
let global = context.module.require_global(index, Some(true))?;
|
||||||
global.content_type().into()
|
global.content_type().into()
|
||||||
};
|
};
|
||||||
let value_type = pop_value(
|
let value_type = pop_value(&mut context.value_stack, &context.frame_stack, StackValueType::Any)?;
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
StackValueType::Any,
|
|
||||||
)?;
|
|
||||||
if global_type != value_type {
|
if global_type != value_type {
|
||||||
return Err(Error(format!(
|
return Err(Error(format!(
|
||||||
"Trying to update global {} of type {:?} with value of type {:?}",
|
"Trying to update global {} of type {:?} with value of type {:?}",
|
||||||
|
@ -1354,11 +1183,7 @@ impl Validator {
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
pop_value(
|
pop_value(&mut context.value_stack, &context.frame_stack, ValueType::I32.into())?;
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
ValueType::I32.into(),
|
|
||||||
)?;
|
|
||||||
context.module.require_memory(DEFAULT_MEMORY_INDEX)?;
|
context.module.require_memory(DEFAULT_MEMORY_INDEX)?;
|
||||||
push_value(&mut context.value_stack, value_type.into())?;
|
push_value(&mut context.value_stack, value_type.into())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1378,16 +1203,8 @@ impl Validator {
|
||||||
}
|
}
|
||||||
|
|
||||||
context.module.require_memory(DEFAULT_MEMORY_INDEX)?;
|
context.module.require_memory(DEFAULT_MEMORY_INDEX)?;
|
||||||
pop_value(
|
pop_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
|
||||||
&mut context.value_stack,
|
pop_value(&mut context.value_stack, &context.frame_stack, ValueType::I32.into())?;
|
||||||
&context.frame_stack,
|
|
||||||
value_type.into(),
|
|
||||||
)?;
|
|
||||||
pop_value(
|
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
ValueType::I32.into(),
|
|
||||||
)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1398,22 +1215,14 @@ impl Validator {
|
||||||
};
|
};
|
||||||
if !frame_type.is_loop() {
|
if !frame_type.is_loop() {
|
||||||
if let BlockType::Value(value_type) = frame_block_type {
|
if let BlockType::Value(value_type) = frame_block_type {
|
||||||
tee_value(
|
tee_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
value_type.into(),
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_br_if(context: &mut FunctionValidationContext, depth: u32) -> Result<(), Error> {
|
fn validate_br_if(context: &mut FunctionValidationContext, depth: u32) -> Result<(), Error> {
|
||||||
pop_value(
|
pop_value(&mut context.value_stack, &context.frame_stack, ValueType::I32.into())?;
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
ValueType::I32.into(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let (frame_type, frame_block_type) = {
|
let (frame_type, frame_block_type) = {
|
||||||
let frame = require_label(depth, &context.frame_stack)?;
|
let frame = require_label(depth, &context.frame_stack)?;
|
||||||
|
@ -1421,21 +1230,13 @@ impl Validator {
|
||||||
};
|
};
|
||||||
if !frame_type.is_loop() {
|
if !frame_type.is_loop() {
|
||||||
if let BlockType::Value(value_type) = frame_block_type {
|
if let BlockType::Value(value_type) = frame_block_type {
|
||||||
tee_value(
|
tee_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
value_type.into(),
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_br_table(
|
fn validate_br_table(context: &mut FunctionValidationContext, table: &[u32], default: u32) -> Result<(), Error> {
|
||||||
context: &mut FunctionValidationContext,
|
|
||||||
table: &[u32],
|
|
||||||
default: u32,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let required_block_type: BlockType = {
|
let required_block_type: BlockType = {
|
||||||
let default_block = require_label(default, &context.frame_stack)?;
|
let default_block = require_label(default, &context.frame_stack)?;
|
||||||
let required_block_type = if !default_block.frame_type.is_loop() {
|
let required_block_type = if !default_block.frame_type.is_loop() {
|
||||||
|
@ -1461,17 +1262,9 @@ impl Validator {
|
||||||
required_block_type
|
required_block_type
|
||||||
};
|
};
|
||||||
|
|
||||||
pop_value(
|
pop_value(&mut context.value_stack, &context.frame_stack, ValueType::I32.into())?;
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
ValueType::I32.into(),
|
|
||||||
)?;
|
|
||||||
if let BlockType::Value(value_type) = required_block_type {
|
if let BlockType::Value(value_type) = required_block_type {
|
||||||
tee_value(
|
tee_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
value_type.into(),
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1480,11 +1273,7 @@ impl Validator {
|
||||||
fn validate_call(context: &mut FunctionValidationContext, idx: u32) -> Result<(), Error> {
|
fn validate_call(context: &mut FunctionValidationContext, idx: u32) -> Result<(), Error> {
|
||||||
let (argument_types, return_type) = context.module.require_function(idx)?;
|
let (argument_types, return_type) = context.module.require_function(idx)?;
|
||||||
for argument_type in argument_types.iter().rev() {
|
for argument_type in argument_types.iter().rev() {
|
||||||
pop_value(
|
pop_value(&mut context.value_stack, &context.frame_stack, (*argument_type).into())?;
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
(*argument_type).into(),
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
if let BlockType::Value(value_type) = return_type {
|
if let BlockType::Value(value_type) = return_type {
|
||||||
push_value(&mut context.value_stack, value_type.into())?;
|
push_value(&mut context.value_stack, value_type.into())?;
|
||||||
|
@ -1492,10 +1281,7 @@ impl Validator {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_call_indirect(
|
fn validate_call_indirect(context: &mut FunctionValidationContext, idx: u32) -> Result<(), Error> {
|
||||||
context: &mut FunctionValidationContext,
|
|
||||||
idx: u32,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
{
|
{
|
||||||
let table = context.module.require_table(DEFAULT_TABLE_INDEX)?;
|
let table = context.module.require_table(DEFAULT_TABLE_INDEX)?;
|
||||||
if table.elem_type() != TableElementType::AnyFunc {
|
if table.elem_type() != TableElementType::AnyFunc {
|
||||||
|
@ -1507,18 +1293,10 @@ impl Validator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pop_value(
|
pop_value(&mut context.value_stack, &context.frame_stack, ValueType::I32.into())?;
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
ValueType::I32.into(),
|
|
||||||
)?;
|
|
||||||
let (argument_types, return_type) = context.module.require_function_type(idx)?;
|
let (argument_types, return_type) = context.module.require_function_type(idx)?;
|
||||||
for argument_type in argument_types.iter().rev() {
|
for argument_type in argument_types.iter().rev() {
|
||||||
pop_value(
|
pop_value(&mut context.value_stack, &context.frame_stack, (*argument_type).into())?;
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
(*argument_type).into(),
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
if let BlockType::Value(value_type) = return_type {
|
if let BlockType::Value(value_type) = return_type {
|
||||||
push_value(&mut context.value_stack, value_type.into())?;
|
push_value(&mut context.value_stack, value_type.into())?;
|
||||||
|
@ -1534,11 +1312,7 @@ impl Validator {
|
||||||
|
|
||||||
fn validate_grow_memory(context: &mut FunctionValidationContext) -> Result<(), Error> {
|
fn validate_grow_memory(context: &mut FunctionValidationContext) -> Result<(), Error> {
|
||||||
context.module.require_memory(DEFAULT_MEMORY_INDEX)?;
|
context.module.require_memory(DEFAULT_MEMORY_INDEX)?;
|
||||||
pop_value(
|
pop_value(&mut context.value_stack, &context.frame_stack, ValueType::I32.into())?;
|
||||||
&mut context.value_stack,
|
|
||||||
&context.frame_stack,
|
|
||||||
ValueType::I32.into(),
|
|
||||||
)?;
|
|
||||||
push_value(&mut context.value_stack, ValueType::I32.into())?;
|
push_value(&mut context.value_stack, ValueType::I32.into())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1610,10 +1384,7 @@ fn make_top_frame_polymorphic(
|
||||||
frame.polymorphic_stack = true;
|
frame.polymorphic_stack = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_value(
|
fn push_value(value_stack: &mut StackWithLimit<StackValueType>, value_type: StackValueType) -> Result<(), Error> {
|
||||||
value_stack: &mut StackWithLimit<StackValueType>,
|
|
||||||
value_type: StackValueType,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
Ok(value_stack.push(value_type.into())?)
|
Ok(value_stack.push(value_type.into())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1631,19 +1402,16 @@ fn pop_value(
|
||||||
let actual_value = if stack_is_empty && is_stack_polymorphic {
|
let actual_value = if stack_is_empty && is_stack_polymorphic {
|
||||||
StackValueType::Any
|
StackValueType::Any
|
||||||
} else {
|
} else {
|
||||||
let value_stack_min = frame_stack
|
let value_stack_min = frame_stack.top().expect("at least 1 topmost block").value_stack_len;
|
||||||
.top()
|
|
||||||
.expect("at least 1 topmost block")
|
|
||||||
.value_stack_len;
|
|
||||||
if value_stack.len() <= value_stack_min {
|
if value_stack.len() <= value_stack_min {
|
||||||
return Err(Error("Trying to access parent frame stack values.".into()));
|
return Err(Error("Trying to access parent frame stack values.".into()));
|
||||||
}
|
}
|
||||||
value_stack.pop().ok_or_else(|| Error("non-empty stack expected".into()))?
|
value_stack
|
||||||
|
.pop()
|
||||||
|
.ok_or_else(|| Error("non-empty stack expected".into()))?
|
||||||
};
|
};
|
||||||
match actual_value {
|
match actual_value {
|
||||||
StackValueType::Specific(stack_value_type) if stack_value_type == value_type => {
|
StackValueType::Specific(stack_value_type) if stack_value_type == value_type => Ok(actual_value),
|
||||||
Ok(actual_value)
|
|
||||||
}
|
|
||||||
StackValueType::Any => Ok(actual_value),
|
StackValueType::Any => Ok(actual_value),
|
||||||
stack_value_type @ _ => Err(Error(format!(
|
stack_value_type @ _ => Err(Error(format!(
|
||||||
"Expected value of type {:?} on top of stack. Got {:?}",
|
"Expected value of type {:?} on top of stack. Got {:?}",
|
||||||
|
@ -1693,11 +1461,7 @@ fn pop_label(
|
||||||
match block_type {
|
match block_type {
|
||||||
BlockType::NoResult => (),
|
BlockType::NoResult => (),
|
||||||
BlockType::Value(required_value_type) => {
|
BlockType::Value(required_value_type) => {
|
||||||
let _ = pop_value(
|
let _ = pop_value(value_stack, frame_stack, StackValueType::Specific(required_value_type))?;
|
||||||
value_stack,
|
|
||||||
frame_stack,
|
|
||||||
StackValueType::Specific(required_value_type),
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1721,13 +1485,10 @@ fn top_label(frame_stack: &StackWithLimit<BlockFrame>) -> &BlockFrame {
|
||||||
.expect("this function can't be called with empty frame stack")
|
.expect("this function can't be called with empty frame stack")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn require_label(
|
fn require_label(depth: u32, frame_stack: &StackWithLimit<BlockFrame>) -> Result<&BlockFrame, Error> {
|
||||||
depth: u32,
|
frame_stack
|
||||||
frame_stack: &StackWithLimit<BlockFrame>,
|
|
||||||
) -> Result<&BlockFrame, Error> {
|
|
||||||
Ok(frame_stack
|
|
||||||
.get_relative_to_top(depth as usize)
|
.get_relative_to_top(depth as usize)
|
||||||
.ok_or_else(|| Error("non-empty stack expected".into()))?)
|
.ok_or_else(|| Error("non-empty stack expected".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn require_target(
|
fn require_target(
|
||||||
|
@ -1736,8 +1497,7 @@ fn require_target(
|
||||||
frame_stack: &StackWithLimit<BlockFrame>,
|
frame_stack: &StackWithLimit<BlockFrame>,
|
||||||
) -> Target {
|
) -> Target {
|
||||||
let is_stack_polymorphic = top_label(frame_stack).polymorphic_stack;
|
let is_stack_polymorphic = top_label(frame_stack).polymorphic_stack;
|
||||||
let frame =
|
let frame = require_label(depth, frame_stack).expect("require_target called with a bogus depth");
|
||||||
require_label(depth, frame_stack).expect("require_target called with a bogus depth");
|
|
||||||
|
|
||||||
// Find out how many values we need to keep (copy to the new stack location after the drop).
|
// Find out how many values we need to keep (copy to the new stack location after the drop).
|
||||||
let keep: isa::Keep = match (frame.frame_type, frame.block_type) {
|
let keep: isa::Keep = match (frame.frame_type, frame.block_type) {
|
||||||
|
@ -1801,11 +1561,7 @@ fn require_local(locals: &Locals, idx: u32) -> Result<ValueType, Error> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See stack layout definition in mod isa.
|
/// See stack layout definition in mod isa.
|
||||||
fn relative_local_depth(
|
fn relative_local_depth(idx: u32, locals: &Locals, value_stack: &StackWithLimit<StackValueType>) -> Result<u32, Error> {
|
||||||
idx: u32,
|
|
||||||
locals: &Locals,
|
|
||||||
value_stack: &StackWithLimit<StackValueType>,
|
|
||||||
) -> Result<u32, Error> {
|
|
||||||
let value_stack_height = value_stack.len() as u32;
|
let value_stack_height = value_stack.len() as u32;
|
||||||
let locals_and_params_count = locals.count();
|
let locals_and_params_count = locals.count();
|
||||||
|
|
||||||
|
@ -1853,11 +1609,7 @@ impl Sink {
|
||||||
self.ins.current_pc()
|
self.ins.current_pc()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pc_or_placeholder<F: FnOnce() -> isa::Reloc>(
|
fn pc_or_placeholder<F: FnOnce() -> isa::Reloc>(&mut self, label: LabelId, reloc_creator: F) -> u32 {
|
||||||
&mut self,
|
|
||||||
label: LabelId,
|
|
||||||
reloc_creator: F,
|
|
||||||
) -> u32 {
|
|
||||||
match self.labels[label.0] {
|
match self.labels[label.0] {
|
||||||
(Label::Resolved(dst_pc), _) => dst_pc,
|
(Label::Resolved(dst_pc), _) => dst_pc,
|
||||||
(Label::NotResolved, ref mut unresolved) => {
|
(Label::NotResolved, ref mut unresolved) => {
|
||||||
|
@ -1885,8 +1637,7 @@ impl Sink {
|
||||||
let Target { label, drop_keep } = target;
|
let Target { label, drop_keep } = target;
|
||||||
let pc = self.cur_pc();
|
let pc = self.cur_pc();
|
||||||
let dst_pc = self.pc_or_placeholder(label, || isa::Reloc::Br { pc });
|
let dst_pc = self.pc_or_placeholder(label, || isa::Reloc::Br { pc });
|
||||||
self.ins
|
self.ins.push(isa::InstructionInternal::BrIfEqz(isa::Target {
|
||||||
.push(isa::InstructionInternal::BrIfEqz(isa::Target {
|
|
||||||
dst_pc,
|
dst_pc,
|
||||||
drop_keep: drop_keep.into(),
|
drop_keep: drop_keep.into(),
|
||||||
}));
|
}));
|
||||||
|
@ -1896,8 +1647,7 @@ impl Sink {
|
||||||
let Target { label, drop_keep } = target;
|
let Target { label, drop_keep } = target;
|
||||||
let pc = self.cur_pc();
|
let pc = self.cur_pc();
|
||||||
let dst_pc = self.pc_or_placeholder(label, || isa::Reloc::Br { pc });
|
let dst_pc = self.pc_or_placeholder(label, || isa::Reloc::Br { pc });
|
||||||
self.ins
|
self.ins.push(isa::InstructionInternal::BrIfNez(isa::Target {
|
||||||
.push(isa::InstructionInternal::BrIfNez(isa::Target {
|
|
||||||
dst_pc,
|
dst_pc,
|
||||||
drop_keep: drop_keep.into(),
|
drop_keep: drop_keep.into(),
|
||||||
}));
|
}));
|
||||||
|
@ -1912,12 +1662,9 @@ impl Sink {
|
||||||
count: targets.len() as u32 + 1,
|
count: targets.len() as u32 + 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
for (idx, &Target { label, drop_keep }) in
|
for (idx, &Target { label, drop_keep }) in targets.iter().chain(iter::once(&default)).enumerate() {
|
||||||
targets.iter().chain(iter::once(&default)).enumerate()
|
|
||||||
{
|
|
||||||
let dst_pc = self.pc_or_placeholder(label, || isa::Reloc::BrTable { pc, idx });
|
let dst_pc = self.pc_or_placeholder(label, || isa::Reloc::BrTable { pc, idx });
|
||||||
self.ins
|
self.ins.push(isa::InstructionInternal::BrTableTarget(isa::Target {
|
||||||
.push(isa::InstructionInternal::BrTableTarget(isa::Target {
|
|
||||||
dst_pc,
|
dst_pc,
|
||||||
drop_keep: drop_keep.into(),
|
drop_keep: drop_keep.into(),
|
||||||
}));
|
}));
|
||||||
|
@ -1958,9 +1705,7 @@ impl Sink {
|
||||||
// At this moment all labels should be resolved.
|
// At this moment all labels should be resolved.
|
||||||
assert!(
|
assert!(
|
||||||
{
|
{
|
||||||
self.labels
|
self.labels.iter().all(|(state, unresolved)| match (state, unresolved) {
|
||||||
.iter()
|
|
||||||
.all(|(state, unresolved)| match (state, unresolved) {
|
|
||||||
(Label::Resolved(_), unresolved) if unresolved.is_empty() => true,
|
(Label::Resolved(_), unresolved) if unresolved.is_empty() => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue