Refactor wasm-ast
to use wasmparser
This commit is contained in:
parent
6338e29ebb
commit
9f8cf3814b
@ -3,6 +3,5 @@ name = "wasm-ast"
|
|||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies.parity-wasm]
|
[dependencies]
|
||||||
git = "https://github.com/paritytech/parity-wasm.git"
|
wasmparser = "0.86.0"
|
||||||
features = ["multi_value", "sign_ext"]
|
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
use parity_wasm::elements::{
|
use wasmparser::{BlockType, FunctionBody, MemoryImmediate, Operator};
|
||||||
BlockType, External, Func, FuncBody, FunctionSection, FunctionType, ImportEntry, ImportSection,
|
|
||||||
Instruction, Module, Type, TypeSection,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
module::TypeInfo,
|
||||||
node::{
|
node::{
|
||||||
Backward, BinOp, BinOpType, Br, BrIf, BrTable, Call, CallIndirect, CmpOp, CmpOpType,
|
Backward, BinOp, BinOpType, Br, BrIf, BrTable, Call, CallIndirect, CmpOp, CmpOpType,
|
||||||
Expression, Forward, FuncData, GetGlobal, GetLocal, If, LoadAt, LoadType, MemoryGrow,
|
Expression, Forward, FuncData, GetGlobal, GetLocal, If, LoadAt, LoadType, MemoryGrow,
|
||||||
@ -23,116 +21,6 @@ macro_rules! leak_on {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Arity {
|
|
||||||
num_param: usize,
|
|
||||||
num_result: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Arity {
|
|
||||||
fn from_type(typ: &FunctionType) -> Self {
|
|
||||||
Self {
|
|
||||||
num_param: typ.params().len(),
|
|
||||||
num_result: typ.results().len(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct TypeInfo<'a> {
|
|
||||||
data: &'a [Type],
|
|
||||||
func_ex: Vec<usize>,
|
|
||||||
func_in: Vec<usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> TypeInfo<'a> {
|
|
||||||
#[must_use]
|
|
||||||
pub fn from_module(parent: &'a Module) -> Self {
|
|
||||||
let data = parent
|
|
||||||
.type_section()
|
|
||||||
.map_or([].as_ref(), TypeSection::types);
|
|
||||||
|
|
||||||
let func_ex = Self::new_ex_list(parent);
|
|
||||||
let func_in = Self::new_in_list(parent);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
data,
|
|
||||||
func_ex,
|
|
||||||
func_in,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn len_in(&self) -> usize {
|
|
||||||
self.func_in.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn len_ex(&self) -> usize {
|
|
||||||
self.func_ex.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn arity_of(&self, index: usize) -> Arity {
|
|
||||||
let Type::Function(typ) = &self.data[index];
|
|
||||||
|
|
||||||
Arity::from_type(typ)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rel_arity_of(&self, index: usize) -> Arity {
|
|
||||||
let adjusted = self
|
|
||||||
.func_ex
|
|
||||||
.iter()
|
|
||||||
.chain(self.func_in.iter())
|
|
||||||
.nth(index)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
self.arity_of(*adjusted)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn block_arity_of(&self, typ: BlockType) -> Arity {
|
|
||||||
match typ {
|
|
||||||
BlockType::NoResult => Arity {
|
|
||||||
num_param: 0,
|
|
||||||
num_result: 0,
|
|
||||||
},
|
|
||||||
BlockType::Value(_) => Arity {
|
|
||||||
num_param: 0,
|
|
||||||
num_result: 1,
|
|
||||||
},
|
|
||||||
BlockType::TypeIndex(i) => {
|
|
||||||
let id = i.try_into().unwrap();
|
|
||||||
|
|
||||||
self.arity_of(id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn func_of_import(import: &ImportEntry) -> Option<usize> {
|
|
||||||
if let &External::Function(i) = import.external() {
|
|
||||||
Some(i.try_into().unwrap())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_ex_list(wasm: &Module) -> Vec<usize> {
|
|
||||||
let list = wasm
|
|
||||||
.import_section()
|
|
||||||
.map_or([].as_ref(), ImportSection::entries);
|
|
||||||
|
|
||||||
list.iter().filter_map(Self::func_of_import).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_in_list(wasm: &Module) -> Vec<usize> {
|
|
||||||
let list = wasm
|
|
||||||
.function_section()
|
|
||||||
.map_or([].as_ref(), FunctionSection::entries);
|
|
||||||
|
|
||||||
list.iter()
|
|
||||||
.map(Func::type_ref)
|
|
||||||
.map(|v| v.try_into().unwrap())
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
enum BlockVariant {
|
enum BlockVariant {
|
||||||
Forward,
|
Forward,
|
||||||
@ -144,7 +32,7 @@ enum BlockVariant {
|
|||||||
enum BlockData {
|
enum BlockData {
|
||||||
Forward { num_result: usize },
|
Forward { num_result: usize },
|
||||||
Backward { num_param: usize },
|
Backward { num_param: usize },
|
||||||
If { num_result: usize, typ: BlockType },
|
If { num_result: usize, ty: BlockType },
|
||||||
Else { num_result: usize },
|
Else { num_result: usize },
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,9 +70,13 @@ impl StatList {
|
|||||||
leak_on!(leak_global_write, Global);
|
leak_on!(leak_global_write, Global);
|
||||||
leak_on!(leak_memory_write, Memory);
|
leak_on!(leak_memory_write, Memory);
|
||||||
|
|
||||||
fn push_load(&mut self, load_type: LoadType, offset: u32) {
|
fn push_load(&mut self, load_type: LoadType, memarg: MemoryImmediate) {
|
||||||
|
let memory = memarg.memory.try_into().unwrap();
|
||||||
|
let offset = memarg.offset.try_into().unwrap();
|
||||||
|
|
||||||
let data = Expression::LoadAt(LoadAt {
|
let data = Expression::LoadAt(LoadAt {
|
||||||
load_type,
|
load_type,
|
||||||
|
memory,
|
||||||
offset,
|
offset,
|
||||||
pointer: self.stack.pop().into(),
|
pointer: self.stack.pop().into(),
|
||||||
});
|
});
|
||||||
@ -192,15 +84,19 @@ impl StatList {
|
|||||||
self.stack.push_with_single(data);
|
self.stack.push_with_single(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_store(&mut self, store_type: StoreType, offset: u32) {
|
fn add_store(&mut self, store_type: StoreType, memarg: MemoryImmediate) {
|
||||||
|
let memory = memarg.memory.try_into().unwrap();
|
||||||
|
let offset = memarg.offset.try_into().unwrap();
|
||||||
|
|
||||||
let data = Statement::StoreAt(StoreAt {
|
let data = Statement::StoreAt(StoreAt {
|
||||||
store_type,
|
store_type,
|
||||||
|
memory,
|
||||||
offset,
|
offset,
|
||||||
value: self.stack.pop(),
|
value: self.stack.pop(),
|
||||||
pointer: self.stack.pop(),
|
pointer: self.stack.pop(),
|
||||||
});
|
});
|
||||||
|
|
||||||
self.leak_memory_write(0);
|
self.leak_memory_write(memory);
|
||||||
self.code.push(data);
|
self.code.push(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,15 +148,15 @@ impl StatList {
|
|||||||
|
|
||||||
// Eqz is the only unary comparison so it's "emulated"
|
// Eqz is the only unary comparison so it's "emulated"
|
||||||
// using a constant operand
|
// using a constant operand
|
||||||
fn try_add_equal_zero(&mut self, inst: &Instruction) -> bool {
|
fn try_add_equal_zero(&mut self, op: &Operator) -> bool {
|
||||||
match inst {
|
match op {
|
||||||
Instruction::I32Eqz => {
|
Operator::I32Eqz => {
|
||||||
self.push_constant(0_i32);
|
self.push_constant(0_i32);
|
||||||
self.push_cmp_op(CmpOpType::Eq_I32);
|
self.push_cmp_op(CmpOpType::Eq_I32);
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
Instruction::I64Eqz => {
|
Operator::I64Eqz => {
|
||||||
self.push_constant(0_i64);
|
self.push_constant(0_i64);
|
||||||
self.push_cmp_op(CmpOpType::Eq_I64);
|
self.push_cmp_op(CmpOpType::Eq_I64);
|
||||||
|
|
||||||
@ -271,21 +167,21 @@ impl StatList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try to generate a simple operation
|
// Try to generate a simple operation
|
||||||
fn try_add_operation(&mut self, inst: &Instruction) -> bool {
|
fn try_add_operation(&mut self, op: &Operator) -> bool {
|
||||||
if let Ok(op) = UnOpType::try_from(inst) {
|
if let Ok(op_type) = UnOpType::try_from(op) {
|
||||||
self.push_un_op(op);
|
self.push_un_op(op_type);
|
||||||
|
|
||||||
true
|
true
|
||||||
} else if let Ok(op) = BinOpType::try_from(inst) {
|
} else if let Ok(op_type) = BinOpType::try_from(op) {
|
||||||
self.push_bin_op(op);
|
self.push_bin_op(op_type);
|
||||||
|
|
||||||
true
|
true
|
||||||
} else if let Ok(op) = CmpOpType::try_from(inst) {
|
} else if let Ok(op_type) = CmpOpType::try_from(op) {
|
||||||
self.push_cmp_op(op);
|
self.push_cmp_op(op_type);
|
||||||
|
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
self.try_add_equal_zero(inst)
|
self.try_add_equal_zero(op)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,7 +209,7 @@ impl From<StatList> for Backward {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Builder<'a> {
|
pub struct Factory<'a> {
|
||||||
type_info: &'a TypeInfo<'a>,
|
type_info: &'a TypeInfo<'a>,
|
||||||
|
|
||||||
pending: Vec<StatList>,
|
pending: Vec<StatList>,
|
||||||
@ -322,7 +218,7 @@ pub struct Builder<'a> {
|
|||||||
nested_unreachable: usize,
|
nested_unreachable: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Builder<'a> {
|
impl<'a> Factory<'a> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_type_info(type_info: &'a TypeInfo<'a>) -> Self {
|
pub fn from_type_info(type_info: &'a TypeInfo<'a>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -334,7 +230,7 @@ impl<'a> Builder<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn build_anonymous(&mut self, list: &[Instruction]) -> FuncData {
|
pub fn create_anonymous(&mut self, list: &[Operator]) -> FuncData {
|
||||||
let data = self.build_stat_list(list, 1);
|
let data = self.build_stat_list(list, 1);
|
||||||
|
|
||||||
FuncData {
|
FuncData {
|
||||||
@ -346,26 +242,28 @@ impl<'a> Builder<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the function is malformed.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn build_indexed(&mut self, index: usize, func: &FuncBody) -> FuncData {
|
pub fn create_indexed(&mut self, index: usize, func: &FunctionBody) -> FuncData {
|
||||||
let arity = &self.type_info.rel_arity_of(self.type_info.len_ex() + index);
|
let code: Result<Vec<_>, _> = func.get_operators_reader().unwrap().into_iter().collect();
|
||||||
let data = self.build_stat_list(func.code().elements(), arity.num_result);
|
let local: Result<Vec<_>, _> = func.get_locals_reader().unwrap().into_iter().collect();
|
||||||
|
|
||||||
|
let (num_param, num_result) = self.type_info.by_func_index(index);
|
||||||
|
let data = self.build_stat_list(&code.unwrap(), num_result);
|
||||||
|
|
||||||
FuncData {
|
FuncData {
|
||||||
local_data: func.locals().to_vec(),
|
local_data: local.unwrap(),
|
||||||
num_result: arity.num_result,
|
num_result,
|
||||||
num_param: arity.num_param,
|
num_param,
|
||||||
num_stack: data.stack.capacity,
|
num_stack: data.stack.capacity,
|
||||||
code: data.into(),
|
code: data.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_block(&mut self, typ: BlockType, variant: BlockVariant) {
|
fn start_block(&mut self, ty: BlockType, variant: BlockVariant) {
|
||||||
let Arity {
|
let (num_param, num_result) = self.type_info.by_block_type(ty);
|
||||||
num_param,
|
|
||||||
num_result,
|
|
||||||
} = self.type_info.block_arity_of(typ);
|
|
||||||
|
|
||||||
let mut old = std::mem::take(&mut self.target);
|
let mut old = std::mem::take(&mut self.target);
|
||||||
|
|
||||||
old.leak_all();
|
old.leak_all();
|
||||||
@ -373,7 +271,7 @@ impl<'a> Builder<'a> {
|
|||||||
self.target.block_data = match variant {
|
self.target.block_data = match variant {
|
||||||
BlockVariant::Forward => BlockData::Forward { num_result },
|
BlockVariant::Forward => BlockData::Forward { num_result },
|
||||||
BlockVariant::Backward => BlockData::Backward { num_param },
|
BlockVariant::Backward => BlockData::Backward { num_param },
|
||||||
BlockVariant::If => BlockData::If { num_result, typ },
|
BlockVariant::If => BlockData::If { num_result, ty },
|
||||||
BlockVariant::Else => {
|
BlockVariant::Else => {
|
||||||
old.stack.pop_len(num_result).for_each(drop);
|
old.stack.pop_len(num_result).for_each(drop);
|
||||||
old.stack.push_temporary(num_param);
|
old.stack.push_temporary(num_param);
|
||||||
@ -390,15 +288,14 @@ impl<'a> Builder<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn start_else(&mut self) {
|
fn start_else(&mut self) {
|
||||||
let typ = if let BlockData::If { typ, .. } = self.target.block_data {
|
let ty = match self.target.block_data {
|
||||||
typ
|
BlockData::If { ty, .. } => ty,
|
||||||
} else {
|
_ => unreachable!(),
|
||||||
unreachable!()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
self.target.leak_all();
|
self.target.leak_all();
|
||||||
self.end_block();
|
self.end_block();
|
||||||
self.start_block(typ, BlockVariant::Else);
|
self.start_block(ty, BlockVariant::Else);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end_block(&mut self) {
|
fn end_block(&mut self) {
|
||||||
@ -455,12 +352,12 @@ impl<'a> Builder<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn add_call(&mut self, function: usize) {
|
fn add_call(&mut self, function: usize) {
|
||||||
let arity = self.type_info.rel_arity_of(function);
|
let (num_param, num_result) = self.type_info.by_func_index(function);
|
||||||
let param_list = self.target.stack.pop_len(arity.num_param).collect();
|
let param_list = self.target.stack.pop_len(num_param).collect();
|
||||||
|
|
||||||
self.target.leak_pre_call();
|
self.target.leak_pre_call();
|
||||||
|
|
||||||
let result = self.target.stack.push_temporary(arity.num_result);
|
let result = self.target.stack.push_temporary(num_result);
|
||||||
|
|
||||||
let data = Statement::Call(Call {
|
let data = Statement::Call(Call {
|
||||||
function,
|
function,
|
||||||
@ -471,14 +368,14 @@ impl<'a> Builder<'a> {
|
|||||||
self.target.code.push(data);
|
self.target.code.push(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_call_indirect(&mut self, typ: usize, table: usize) {
|
fn add_call_indirect(&mut self, ty: usize, table: usize) {
|
||||||
let arity = self.type_info.arity_of(typ);
|
let (num_param, num_result) = self.type_info.by_type_index(ty);
|
||||||
let index = self.target.stack.pop();
|
let index = self.target.stack.pop();
|
||||||
let param_list = self.target.stack.pop_len(arity.num_param).collect();
|
let param_list = self.target.stack.pop_len(num_param).collect();
|
||||||
|
|
||||||
self.target.leak_pre_call();
|
self.target.leak_pre_call();
|
||||||
|
|
||||||
let result = self.target.stack.push_temporary(arity.num_result);
|
let result = self.target.stack.push_temporary(num_result);
|
||||||
|
|
||||||
let data = Statement::CallIndirect(CallIndirect {
|
let data = Statement::CallIndirect(CallIndirect {
|
||||||
table,
|
table,
|
||||||
@ -491,22 +388,22 @@ impl<'a> Builder<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cold]
|
#[cold]
|
||||||
fn drop_unreachable(&mut self, inst: &Instruction) {
|
fn drop_unreachable(&mut self, op: &Operator) {
|
||||||
match inst {
|
match op {
|
||||||
Instruction::Block(_) | Instruction::Loop(_) | Instruction::If(_) => {
|
Operator::Block { .. } | Operator::Loop { .. } | Operator::If { .. } => {
|
||||||
self.nested_unreachable += 1;
|
self.nested_unreachable += 1;
|
||||||
}
|
}
|
||||||
Instruction::Else if self.nested_unreachable == 1 => {
|
Operator::Else if self.nested_unreachable == 1 => {
|
||||||
self.nested_unreachable -= 1;
|
self.nested_unreachable -= 1;
|
||||||
|
|
||||||
self.start_else();
|
self.start_else();
|
||||||
}
|
}
|
||||||
Instruction::End if self.nested_unreachable == 1 => {
|
Operator::End if self.nested_unreachable == 1 => {
|
||||||
self.nested_unreachable -= 1;
|
self.nested_unreachable -= 1;
|
||||||
|
|
||||||
self.end_block();
|
self.end_block();
|
||||||
}
|
}
|
||||||
Instruction::End => {
|
Operator::End => {
|
||||||
self.nested_unreachable -= 1;
|
self.nested_unreachable -= 1;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -514,65 +411,63 @@ impl<'a> Builder<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
fn add_instruction(&mut self, inst: &Instruction) {
|
fn add_instruction(&mut self, op: &Operator) {
|
||||||
use Instruction as Inst;
|
if self.target.try_add_operation(op) {
|
||||||
|
|
||||||
if self.target.try_add_operation(inst) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
match *inst {
|
match *op {
|
||||||
Inst::Unreachable => {
|
Operator::Unreachable => {
|
||||||
self.nested_unreachable += 1;
|
self.nested_unreachable += 1;
|
||||||
|
|
||||||
self.target.set_terminator(Terminator::Unreachable);
|
self.target.set_terminator(Terminator::Unreachable);
|
||||||
}
|
}
|
||||||
Inst::Nop => {}
|
Operator::Nop => {}
|
||||||
Inst::Block(typ) => {
|
Operator::Block { ty } => {
|
||||||
self.start_block(typ, BlockVariant::Forward);
|
self.start_block(ty, BlockVariant::Forward);
|
||||||
}
|
}
|
||||||
Inst::Loop(typ) => {
|
Operator::Loop { ty } => {
|
||||||
self.start_block(typ, BlockVariant::Backward);
|
self.start_block(ty, BlockVariant::Backward);
|
||||||
}
|
}
|
||||||
Inst::If(typ) => {
|
Operator::If { ty } => {
|
||||||
let cond = self.target.stack.pop();
|
let cond = self.target.stack.pop();
|
||||||
|
|
||||||
self.start_block(typ, BlockVariant::If);
|
self.start_block(ty, BlockVariant::If);
|
||||||
self.pending.last_mut().unwrap().stack.push(cond);
|
self.pending.last_mut().unwrap().stack.push(cond);
|
||||||
}
|
}
|
||||||
Inst::Else => {
|
Operator::Else => {
|
||||||
self.start_else();
|
self.start_else();
|
||||||
}
|
}
|
||||||
Inst::End => {
|
Operator::End => {
|
||||||
self.target.leak_all();
|
self.target.leak_all();
|
||||||
self.end_block();
|
self.end_block();
|
||||||
}
|
}
|
||||||
Inst::Br(v) => {
|
Operator::Br { relative_depth } => {
|
||||||
let target = v.try_into().unwrap();
|
let target = relative_depth.try_into().unwrap();
|
||||||
let term = Terminator::Br(self.get_br_terminator(target));
|
let term = Terminator::Br(self.get_br_terminator(target));
|
||||||
|
|
||||||
self.target.set_terminator(term);
|
self.target.set_terminator(term);
|
||||||
self.nested_unreachable += 1;
|
self.nested_unreachable += 1;
|
||||||
}
|
}
|
||||||
Inst::BrIf(v) => {
|
Operator::BrIf { relative_depth } => {
|
||||||
|
let target = relative_depth.try_into().unwrap();
|
||||||
let data = Statement::BrIf(BrIf {
|
let data = Statement::BrIf(BrIf {
|
||||||
condition: self.target.stack.pop(),
|
condition: self.target.stack.pop(),
|
||||||
target: self.get_br_terminator(v.try_into().unwrap()),
|
target: self.get_br_terminator(target),
|
||||||
});
|
});
|
||||||
|
|
||||||
self.target.leak_all();
|
self.target.leak_all();
|
||||||
self.target.code.push(data);
|
self.target.code.push(data);
|
||||||
}
|
}
|
||||||
Inst::BrTable(ref v) => {
|
Operator::BrTable { ref table } => {
|
||||||
let condition = self.target.stack.pop();
|
let condition = self.target.stack.pop();
|
||||||
let data = v
|
let data = table
|
||||||
.table
|
.targets()
|
||||||
.iter()
|
.map(Result::unwrap)
|
||||||
.copied()
|
|
||||||
.map(|v| self.get_br_terminator(v.try_into().unwrap()))
|
.map(|v| self.get_br_terminator(v.try_into().unwrap()))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let default = self.get_br_terminator(v.default.try_into().unwrap());
|
let default = self.get_br_terminator(table.default().try_into().unwrap());
|
||||||
|
|
||||||
let term = Terminator::BrTable(BrTable {
|
let term = Terminator::BrTable(BrTable {
|
||||||
condition,
|
condition,
|
||||||
@ -583,23 +478,29 @@ impl<'a> Builder<'a> {
|
|||||||
self.target.set_terminator(term);
|
self.target.set_terminator(term);
|
||||||
self.nested_unreachable += 1;
|
self.nested_unreachable += 1;
|
||||||
}
|
}
|
||||||
Inst::Return => {
|
Operator::Return => {
|
||||||
let target = self.pending.len();
|
let target = self.pending.len();
|
||||||
let term = Terminator::Br(self.get_br_terminator(target));
|
let term = Terminator::Br(self.get_br_terminator(target));
|
||||||
|
|
||||||
self.target.set_terminator(term);
|
self.target.set_terminator(term);
|
||||||
self.nested_unreachable += 1;
|
self.nested_unreachable += 1;
|
||||||
}
|
}
|
||||||
Inst::Call(i) => {
|
Operator::Call { function_index } => {
|
||||||
self.add_call(i.try_into().unwrap());
|
let index = function_index.try_into().unwrap();
|
||||||
|
|
||||||
|
self.add_call(index);
|
||||||
}
|
}
|
||||||
Inst::CallIndirect(i, t) => {
|
Operator::CallIndirect {
|
||||||
self.add_call_indirect(i.try_into().unwrap(), t.into());
|
index, table_byte, ..
|
||||||
|
} => {
|
||||||
|
let index = index.try_into().unwrap();
|
||||||
|
|
||||||
|
self.add_call_indirect(index, table_byte.into());
|
||||||
}
|
}
|
||||||
Inst::Drop => {
|
Operator::Drop => {
|
||||||
self.target.stack.pop();
|
self.target.stack.pop();
|
||||||
}
|
}
|
||||||
Inst::Select => {
|
Operator::Select => {
|
||||||
let mut condition = self.target.stack.pop_with_read();
|
let mut condition = self.target.stack.pop_with_read();
|
||||||
let on_false = self.target.stack.pop_with_read();
|
let on_false = self.target.stack.pop_with_read();
|
||||||
let on_true = self.target.stack.pop_with_read();
|
let on_true = self.target.stack.pop_with_read();
|
||||||
@ -615,14 +516,14 @@ impl<'a> Builder<'a> {
|
|||||||
|
|
||||||
self.target.stack.push_with_read(data, condition.1);
|
self.target.stack.push_with_read(data, condition.1);
|
||||||
}
|
}
|
||||||
Inst::GetLocal(i) => {
|
Operator::LocalGet { local_index } => {
|
||||||
let var = i.try_into().unwrap();
|
let var = local_index.try_into().unwrap();
|
||||||
let data = Expression::GetLocal(GetLocal { var });
|
let data = Expression::GetLocal(GetLocal { var });
|
||||||
|
|
||||||
self.target.stack.push_with_single(data);
|
self.target.stack.push_with_single(data);
|
||||||
}
|
}
|
||||||
Inst::SetLocal(i) => {
|
Operator::LocalSet { local_index } => {
|
||||||
let var = i.try_into().unwrap();
|
let var = local_index.try_into().unwrap();
|
||||||
let data = Statement::SetLocal(SetLocal {
|
let data = Statement::SetLocal(SetLocal {
|
||||||
var,
|
var,
|
||||||
value: self.target.stack.pop(),
|
value: self.target.stack.pop(),
|
||||||
@ -631,8 +532,8 @@ impl<'a> Builder<'a> {
|
|||||||
self.target.leak_local_write(var);
|
self.target.leak_local_write(var);
|
||||||
self.target.code.push(data);
|
self.target.code.push(data);
|
||||||
}
|
}
|
||||||
Inst::TeeLocal(i) => {
|
Operator::LocalTee { local_index } => {
|
||||||
let var = i.try_into().unwrap();
|
let var = local_index.try_into().unwrap();
|
||||||
let get = Expression::GetLocal(GetLocal { var });
|
let get = Expression::GetLocal(GetLocal { var });
|
||||||
let set = Statement::SetLocal(SetLocal {
|
let set = Statement::SetLocal(SetLocal {
|
||||||
var,
|
var,
|
||||||
@ -643,14 +544,14 @@ impl<'a> Builder<'a> {
|
|||||||
self.target.stack.push_with_single(get);
|
self.target.stack.push_with_single(get);
|
||||||
self.target.code.push(set);
|
self.target.code.push(set);
|
||||||
}
|
}
|
||||||
Inst::GetGlobal(i) => {
|
Operator::GlobalGet { global_index } => {
|
||||||
let var = i.try_into().unwrap();
|
let var = global_index.try_into().unwrap();
|
||||||
let data = Expression::GetGlobal(GetGlobal { var });
|
let data = Expression::GetGlobal(GetGlobal { var });
|
||||||
|
|
||||||
self.target.stack.push_with_single(data);
|
self.target.stack.push_with_single(data);
|
||||||
}
|
}
|
||||||
Inst::SetGlobal(i) => {
|
Operator::GlobalSet { global_index } => {
|
||||||
let var = i.try_into().unwrap();
|
let var = global_index.try_into().unwrap();
|
||||||
let data = Statement::SetGlobal(SetGlobal {
|
let data = Statement::SetGlobal(SetGlobal {
|
||||||
var,
|
var,
|
||||||
value: self.target.stack.pop(),
|
value: self.target.stack.pop(),
|
||||||
@ -659,39 +560,39 @@ impl<'a> Builder<'a> {
|
|||||||
self.target.leak_global_write(var);
|
self.target.leak_global_write(var);
|
||||||
self.target.code.push(data);
|
self.target.code.push(data);
|
||||||
}
|
}
|
||||||
Inst::I32Load(_, o) => self.target.push_load(LoadType::I32, o),
|
Operator::I32Load { memarg } => self.target.push_load(LoadType::I32, memarg),
|
||||||
Inst::I64Load(_, o) => self.target.push_load(LoadType::I64, o),
|
Operator::I64Load { memarg } => self.target.push_load(LoadType::I64, memarg),
|
||||||
Inst::F32Load(_, o) => self.target.push_load(LoadType::F32, o),
|
Operator::F32Load { memarg } => self.target.push_load(LoadType::F32, memarg),
|
||||||
Inst::F64Load(_, o) => self.target.push_load(LoadType::F64, o),
|
Operator::F64Load { memarg } => self.target.push_load(LoadType::F64, memarg),
|
||||||
Inst::I32Load8S(_, o) => self.target.push_load(LoadType::I32_I8, o),
|
Operator::I32Load8S { memarg } => self.target.push_load(LoadType::I32_I8, memarg),
|
||||||
Inst::I32Load8U(_, o) => self.target.push_load(LoadType::I32_U8, o),
|
Operator::I32Load8U { memarg } => self.target.push_load(LoadType::I32_U8, memarg),
|
||||||
Inst::I32Load16S(_, o) => self.target.push_load(LoadType::I32_I16, o),
|
Operator::I32Load16S { memarg } => self.target.push_load(LoadType::I32_I16, memarg),
|
||||||
Inst::I32Load16U(_, o) => self.target.push_load(LoadType::I32_U16, o),
|
Operator::I32Load16U { memarg } => self.target.push_load(LoadType::I32_U16, memarg),
|
||||||
Inst::I64Load8S(_, o) => self.target.push_load(LoadType::I64_I8, o),
|
Operator::I64Load8S { memarg } => self.target.push_load(LoadType::I64_I8, memarg),
|
||||||
Inst::I64Load8U(_, o) => self.target.push_load(LoadType::I64_U8, o),
|
Operator::I64Load8U { memarg } => self.target.push_load(LoadType::I64_U8, memarg),
|
||||||
Inst::I64Load16S(_, o) => self.target.push_load(LoadType::I64_I16, o),
|
Operator::I64Load16S { memarg } => self.target.push_load(LoadType::I64_I16, memarg),
|
||||||
Inst::I64Load16U(_, o) => self.target.push_load(LoadType::I64_U16, o),
|
Operator::I64Load16U { memarg } => self.target.push_load(LoadType::I64_U16, memarg),
|
||||||
Inst::I64Load32S(_, o) => self.target.push_load(LoadType::I64_I32, o),
|
Operator::I64Load32S { memarg } => self.target.push_load(LoadType::I64_I32, memarg),
|
||||||
Inst::I64Load32U(_, o) => self.target.push_load(LoadType::I64_U32, o),
|
Operator::I64Load32U { memarg } => self.target.push_load(LoadType::I64_U32, memarg),
|
||||||
Inst::I32Store(_, o) => self.target.add_store(StoreType::I32, o),
|
Operator::I32Store { memarg } => self.target.add_store(StoreType::I32, memarg),
|
||||||
Inst::I64Store(_, o) => self.target.add_store(StoreType::I64, o),
|
Operator::I64Store { memarg } => self.target.add_store(StoreType::I64, memarg),
|
||||||
Inst::F32Store(_, o) => self.target.add_store(StoreType::F32, o),
|
Operator::F32Store { memarg } => self.target.add_store(StoreType::F32, memarg),
|
||||||
Inst::F64Store(_, o) => self.target.add_store(StoreType::F64, o),
|
Operator::F64Store { memarg } => self.target.add_store(StoreType::F64, memarg),
|
||||||
Inst::I32Store8(_, o) => self.target.add_store(StoreType::I32_N8, o),
|
Operator::I32Store8 { memarg } => self.target.add_store(StoreType::I32_N8, memarg),
|
||||||
Inst::I32Store16(_, o) => self.target.add_store(StoreType::I32_N16, o),
|
Operator::I32Store16 { memarg } => self.target.add_store(StoreType::I32_N16, memarg),
|
||||||
Inst::I64Store8(_, o) => self.target.add_store(StoreType::I64_N8, o),
|
Operator::I64Store8 { memarg } => self.target.add_store(StoreType::I64_N8, memarg),
|
||||||
Inst::I64Store16(_, o) => self.target.add_store(StoreType::I64_N16, o),
|
Operator::I64Store16 { memarg } => self.target.add_store(StoreType::I64_N16, memarg),
|
||||||
Inst::I64Store32(_, o) => self.target.add_store(StoreType::I64_N32, o),
|
Operator::I64Store32 { memarg } => self.target.add_store(StoreType::I64_N32, memarg),
|
||||||
Inst::CurrentMemory(i) => {
|
Operator::MemorySize { mem, .. } => {
|
||||||
let memory = i.try_into().unwrap();
|
let memory = mem.try_into().unwrap();
|
||||||
let data = Expression::MemorySize(MemorySize { memory });
|
let data = Expression::MemorySize(MemorySize { memory });
|
||||||
|
|
||||||
self.target.stack.push(data);
|
self.target.stack.push(data);
|
||||||
}
|
}
|
||||||
Inst::GrowMemory(i) => {
|
Operator::MemoryGrow { mem, .. } => {
|
||||||
let size = self.target.stack.pop().into();
|
let size = self.target.stack.pop().into();
|
||||||
let result = self.target.stack.push_temporary(1).start;
|
let result = self.target.stack.push_temporary(1).start;
|
||||||
let memory = i.try_into().unwrap();
|
let memory = mem.try_into().unwrap();
|
||||||
|
|
||||||
let data = Statement::MemoryGrow(MemoryGrow {
|
let data = Statement::MemoryGrow(MemoryGrow {
|
||||||
memory,
|
memory,
|
||||||
@ -702,24 +603,23 @@ impl<'a> Builder<'a> {
|
|||||||
self.target.leak_memory_write(memory);
|
self.target.leak_memory_write(memory);
|
||||||
self.target.code.push(data);
|
self.target.code.push(data);
|
||||||
}
|
}
|
||||||
Inst::I32Const(v) => self.target.push_constant(v),
|
Operator::I32Const { value } => self.target.push_constant(value),
|
||||||
Inst::I64Const(v) => self.target.push_constant(v),
|
Operator::I64Const { value } => self.target.push_constant(value),
|
||||||
Inst::F32Const(v) => self.target.push_constant(v),
|
Operator::F32Const { value } => self.target.push_constant(value.bits()),
|
||||||
Inst::F64Const(v) => self.target.push_constant(v),
|
Operator::F64Const { value } => self.target.push_constant(value.bits()),
|
||||||
Inst::SignExt(_) => todo!(),
|
_ => unimplemented!(),
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_stat_list(&mut self, list: &[Instruction], num_result: usize) -> StatList {
|
fn build_stat_list(&mut self, list: &[Operator], num_result: usize) -> StatList {
|
||||||
self.target.block_data = BlockData::Forward { num_result };
|
self.target.block_data = BlockData::Forward { num_result };
|
||||||
self.nested_unreachable = 0;
|
self.nested_unreachable = 0;
|
||||||
|
|
||||||
for inst in list.iter().take(list.len() - 1) {
|
for op in list.iter().take(list.len() - 1) {
|
||||||
if self.nested_unreachable == 0 {
|
if self.nested_unreachable == 0 {
|
||||||
self.add_instruction(inst);
|
self.add_instruction(op);
|
||||||
} else {
|
} else {
|
||||||
self.drop_unreachable(inst);
|
self.drop_unreachable(op);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,6 @@
|
|||||||
pub mod builder;
|
pub mod factory;
|
||||||
|
pub mod module;
|
||||||
pub mod node;
|
pub mod node;
|
||||||
mod stack;
|
|
||||||
pub mod visit;
|
pub mod visit;
|
||||||
|
|
||||||
|
mod stack;
|
||||||
|
270
wasm-ast/src/module.rs
Normal file
270
wasm-ast/src/module.rs
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use wasmparser::{
|
||||||
|
BlockType, Data, Element, Export, ExternalKind, FunctionBody, Global, Import, MemoryType, Name,
|
||||||
|
NameSectionReader, Parser, Payload, TableType, Type, TypeRef,
|
||||||
|
};
|
||||||
|
|
||||||
|
macro_rules! to_section {
|
||||||
|
($data:ident) => {{
|
||||||
|
let read: Result<_, _> = $data.into_iter().collect();
|
||||||
|
|
||||||
|
read.unwrap()
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub enum External {
|
||||||
|
Func,
|
||||||
|
Table,
|
||||||
|
Memory,
|
||||||
|
Global,
|
||||||
|
Tag,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TypeRef> for External {
|
||||||
|
fn from(value: TypeRef) -> Self {
|
||||||
|
match value {
|
||||||
|
TypeRef::Func(_) => External::Func,
|
||||||
|
TypeRef::Table(_) => External::Table,
|
||||||
|
TypeRef::Memory(_) => External::Memory,
|
||||||
|
TypeRef::Global(_) => External::Global,
|
||||||
|
TypeRef::Tag(_) => External::Tag,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ExternalKind> for External {
|
||||||
|
fn from(value: ExternalKind) -> Self {
|
||||||
|
match value {
|
||||||
|
ExternalKind::Func => External::Func,
|
||||||
|
ExternalKind::Table => External::Table,
|
||||||
|
ExternalKind::Memory => External::Memory,
|
||||||
|
ExternalKind::Global => External::Global,
|
||||||
|
ExternalKind::Tag => External::Tag,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Module<'a> {
|
||||||
|
type_section: Vec<Type>,
|
||||||
|
import_section: Vec<Import<'a>>,
|
||||||
|
func_section: Vec<u32>,
|
||||||
|
table_section: Vec<TableType>,
|
||||||
|
memory_section: Vec<MemoryType>,
|
||||||
|
global_section: Vec<Global<'a>>,
|
||||||
|
export_section: Vec<Export<'a>>,
|
||||||
|
element_section: Vec<Element<'a>>,
|
||||||
|
data_section: Vec<Data<'a>>,
|
||||||
|
code_section: Vec<FunctionBody<'a>>,
|
||||||
|
|
||||||
|
name_section: HashMap<u32, &'a str>,
|
||||||
|
|
||||||
|
start_section: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Module<'a> {
|
||||||
|
#[must_use]
|
||||||
|
pub fn from_data(data: &'a [u8]) -> Self {
|
||||||
|
let mut temp = Module {
|
||||||
|
type_section: Vec::new(),
|
||||||
|
import_section: Vec::new(),
|
||||||
|
func_section: Vec::new(),
|
||||||
|
table_section: Vec::new(),
|
||||||
|
memory_section: Vec::new(),
|
||||||
|
global_section: Vec::new(),
|
||||||
|
export_section: Vec::new(),
|
||||||
|
element_section: Vec::new(),
|
||||||
|
data_section: Vec::new(),
|
||||||
|
code_section: Vec::new(),
|
||||||
|
name_section: HashMap::new(),
|
||||||
|
start_section: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
temp.load_data(data);
|
||||||
|
temp
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_data(&mut self, data: &'a [u8]) {
|
||||||
|
for payload in Parser::new(0).parse_all(data).flatten() {
|
||||||
|
match payload {
|
||||||
|
Payload::TypeSection(v) => self.type_section = to_section!(v),
|
||||||
|
Payload::ImportSection(v) => self.import_section = to_section!(v),
|
||||||
|
Payload::FunctionSection(v) => self.func_section = to_section!(v),
|
||||||
|
Payload::TableSection(v) => self.table_section = to_section!(v),
|
||||||
|
Payload::MemorySection(v) => self.memory_section = to_section!(v),
|
||||||
|
Payload::GlobalSection(v) => self.global_section = to_section!(v),
|
||||||
|
Payload::ExportSection(v) => self.export_section = to_section!(v),
|
||||||
|
Payload::ElementSection(v) => self.element_section = to_section!(v),
|
||||||
|
Payload::DataSection(v) => self.data_section = to_section!(v),
|
||||||
|
Payload::CodeSectionEntry(v) => {
|
||||||
|
self.code_section.push(v);
|
||||||
|
}
|
||||||
|
Payload::StartSection { func, .. } => {
|
||||||
|
self.start_section = Some(func);
|
||||||
|
}
|
||||||
|
Payload::CustomSection(v) if v.name() == "name" => {
|
||||||
|
for name in NameSectionReader::new(v.data(), v.data_offset()).unwrap() {
|
||||||
|
if let Name::Function(map) = name.unwrap() {
|
||||||
|
let mut iter = map.get_map().unwrap();
|
||||||
|
|
||||||
|
while let Ok(elem) = iter.read() {
|
||||||
|
self.name_section.insert(elem.index, elem.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn import_count(&self, ext: External) -> usize {
|
||||||
|
let predicate = |v: &&Import| External::from(v.ty) == ext;
|
||||||
|
|
||||||
|
self.import_section.iter().filter(predicate).count()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn function_space(&self) -> usize {
|
||||||
|
self.import_count(External::Func) + self.func_section.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn table_space(&self) -> usize {
|
||||||
|
self.import_count(External::Table) + self.table_section.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn memory_space(&self) -> usize {
|
||||||
|
self.import_count(External::Memory) + self.memory_section.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn global_space(&self) -> usize {
|
||||||
|
self.import_count(External::Global) + self.global_section.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn type_section(&self) -> &[Type] {
|
||||||
|
&self.type_section
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn import_section(&self) -> &[Import] {
|
||||||
|
&self.import_section
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn func_section(&self) -> &[u32] {
|
||||||
|
&self.func_section
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn table_section(&self) -> &[TableType] {
|
||||||
|
&self.table_section
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn memory_section(&self) -> &[MemoryType] {
|
||||||
|
&self.memory_section
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn global_section(&self) -> &[Global] {
|
||||||
|
&self.global_section
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn export_section(&self) -> &[Export] {
|
||||||
|
&self.export_section
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn element_section(&self) -> &[Element] {
|
||||||
|
&self.element_section
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn data_section(&self) -> &[Data] {
|
||||||
|
&self.data_section
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn code_section(&self) -> &[FunctionBody] {
|
||||||
|
&self.code_section
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn name_section(&self) -> &HashMap<u32, &'a str> {
|
||||||
|
&self.name_section
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn start_section(&self) -> Option<u32> {
|
||||||
|
self.start_section
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TypeInfo<'a> {
|
||||||
|
type_list: &'a [Type],
|
||||||
|
func_list: Vec<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TypeInfo<'a> {
|
||||||
|
#[must_use]
|
||||||
|
pub fn from_module(wasm: &'a Module) -> Self {
|
||||||
|
let mut temp = Self {
|
||||||
|
type_list: &wasm.type_section,
|
||||||
|
func_list: Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
temp.load_import_list(&wasm.import_section);
|
||||||
|
temp.load_func_list(&wasm.func_section);
|
||||||
|
temp
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_import_list(&mut self, list: &[Import]) {
|
||||||
|
let iter = list
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.filter_map(|v| match v.ty {
|
||||||
|
TypeRef::Func(v) => Some(v),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|v| usize::try_from(v).unwrap());
|
||||||
|
|
||||||
|
self.func_list.extend(iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_func_list(&mut self, list: &[u32]) {
|
||||||
|
let iter = list.iter().copied().map(|v| usize::try_from(v).unwrap());
|
||||||
|
|
||||||
|
self.func_list.extend(iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn by_type_index(&self, index: usize) -> (usize, usize) {
|
||||||
|
let Type::Func(ty) = &self.type_list[index];
|
||||||
|
|
||||||
|
(ty.params.len(), ty.returns.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn by_func_index(&self, index: usize) -> (usize, usize) {
|
||||||
|
let adjusted = self.func_list[index];
|
||||||
|
|
||||||
|
self.by_type_index(adjusted)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn by_block_type(&self, ty: BlockType) -> (usize, usize) {
|
||||||
|
match ty {
|
||||||
|
BlockType::Empty => (0, 0),
|
||||||
|
BlockType::Type(_) => (0, 1),
|
||||||
|
BlockType::FuncType(i) => {
|
||||||
|
let id = i.try_into().unwrap();
|
||||||
|
|
||||||
|
self.by_type_index(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use parity_wasm::elements::{Instruction, Local, SignExtInstruction};
|
use wasmparser::{Operator, ValType};
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
@ -43,27 +43,25 @@ impl LoadType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&Instruction> for LoadType {
|
impl TryFrom<&Operator<'_>> for LoadType {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
fn try_from(inst: &Instruction) -> Result<Self, Self::Error> {
|
fn try_from(inst: &Operator) -> Result<Self, Self::Error> {
|
||||||
use Instruction as Inst;
|
|
||||||
|
|
||||||
let result = match inst {
|
let result = match inst {
|
||||||
Inst::I32Load(_, _) => Self::I32,
|
Operator::I32Load { .. } => Self::I32,
|
||||||
Inst::I64Load(_, _) => Self::I64,
|
Operator::I64Load { .. } => Self::I64,
|
||||||
Inst::F32Load(_, _) => Self::F32,
|
Operator::F32Load { .. } => Self::F32,
|
||||||
Inst::F64Load(_, _) => Self::F64,
|
Operator::F64Load { .. } => Self::F64,
|
||||||
Inst::I32Load8S(_, _) => Self::I32_I8,
|
Operator::I32Load8S { .. } => Self::I32_I8,
|
||||||
Inst::I32Load8U(_, _) => Self::I32_U8,
|
Operator::I32Load8U { .. } => Self::I32_U8,
|
||||||
Inst::I32Load16S(_, _) => Self::I32_I16,
|
Operator::I32Load16S { .. } => Self::I32_I16,
|
||||||
Inst::I32Load16U(_, _) => Self::I32_U16,
|
Operator::I32Load16U { .. } => Self::I32_U16,
|
||||||
Inst::I64Load8S(_, _) => Self::I64_I8,
|
Operator::I64Load8S { .. } => Self::I64_I8,
|
||||||
Inst::I64Load8U(_, _) => Self::I64_U8,
|
Operator::I64Load8U { .. } => Self::I64_U8,
|
||||||
Inst::I64Load16S(_, _) => Self::I64_I16,
|
Operator::I64Load16S { .. } => Self::I64_I16,
|
||||||
Inst::I64Load16U(_, _) => Self::I64_U16,
|
Operator::I64Load16U { .. } => Self::I64_U16,
|
||||||
Inst::I64Load32S(_, _) => Self::I64_I32,
|
Operator::I64Load32S { .. } => Self::I64_I32,
|
||||||
Inst::I64Load32U(_, _) => Self::I64_U32,
|
Operator::I64Load32U { .. } => Self::I64_U32,
|
||||||
_ => return Err(()),
|
_ => return Err(()),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -102,22 +100,20 @@ impl StoreType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&Instruction> for StoreType {
|
impl TryFrom<&Operator<'_>> for StoreType {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
fn try_from(inst: &Instruction) -> Result<Self, Self::Error> {
|
fn try_from(inst: &Operator) -> Result<Self, Self::Error> {
|
||||||
use Instruction as Inst;
|
|
||||||
|
|
||||||
let result = match inst {
|
let result = match inst {
|
||||||
Inst::I32Store(_, _) => Self::I32,
|
Operator::I32Store { .. } => Self::I32,
|
||||||
Inst::I64Store(_, _) => Self::I64,
|
Operator::I64Store { .. } => Self::I64,
|
||||||
Inst::F32Store(_, _) => Self::F32,
|
Operator::F32Store { .. } => Self::F32,
|
||||||
Inst::F64Store(_, _) => Self::F64,
|
Operator::F64Store { .. } => Self::F64,
|
||||||
Inst::I32Store8(_, _) => Self::I32_N8,
|
Operator::I32Store8 { .. } => Self::I32_N8,
|
||||||
Inst::I32Store16(_, _) => Self::I32_N16,
|
Operator::I32Store16 { .. } => Self::I32_N16,
|
||||||
Inst::I64Store8(_, _) => Self::I64_N8,
|
Operator::I64Store8 { .. } => Self::I64_N8,
|
||||||
Inst::I64Store16(_, _) => Self::I64_N16,
|
Operator::I64Store16 { .. } => Self::I64_N16,
|
||||||
Inst::I64Store32(_, _) => Self::I64_N32,
|
Operator::I64Store32 { .. } => Self::I64_N32,
|
||||||
_ => return Err(()),
|
_ => return Err(()),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -224,58 +220,53 @@ impl UnOpType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&Instruction> for UnOpType {
|
impl TryFrom<&Operator<'_>> for UnOpType {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
fn try_from(inst: &Instruction) -> Result<Self, Self::Error> {
|
fn try_from(inst: &Operator) -> Result<Self, Self::Error> {
|
||||||
use Instruction as Inst;
|
|
||||||
|
|
||||||
let result = match inst {
|
let result = match inst {
|
||||||
Inst::SignExt(ext) => match ext {
|
Operator::I32Clz => Self::Clz_I32,
|
||||||
SignExtInstruction::I32Extend8S => Self::Extend_I32_I8,
|
Operator::I32Ctz => Self::Ctz_I32,
|
||||||
SignExtInstruction::I32Extend16S => Self::Extend_I32_I16,
|
Operator::I32Popcnt => Self::Popcnt_I32,
|
||||||
SignExtInstruction::I64Extend8S => Self::Extend_I64_I8,
|
Operator::I64Clz => Self::Clz_I64,
|
||||||
SignExtInstruction::I64Extend16S => Self::Extend_I64_I16,
|
Operator::I64Ctz => Self::Ctz_I64,
|
||||||
SignExtInstruction::I64Extend32S => Self::Extend_I64_I32,
|
Operator::I64Popcnt => Self::Popcnt_I64,
|
||||||
},
|
Operator::F32Abs | Operator::F64Abs => Self::Abs_FN,
|
||||||
Inst::I32Clz => Self::Clz_I32,
|
Operator::F32Neg | Operator::F64Neg => Self::Neg_FN,
|
||||||
Inst::I32Ctz => Self::Ctz_I32,
|
Operator::F32Ceil | Operator::F64Ceil => Self::Ceil_FN,
|
||||||
Inst::I32Popcnt => Self::Popcnt_I32,
|
Operator::F32Floor | Operator::F64Floor => Self::Floor_FN,
|
||||||
Inst::I64Clz => Self::Clz_I64,
|
Operator::F32Trunc | Operator::F64Trunc => Self::Trunc_FN,
|
||||||
Inst::I64Ctz => Self::Ctz_I64,
|
Operator::F32Nearest | Operator::F64Nearest => Self::Nearest_FN,
|
||||||
Inst::I64Popcnt => Self::Popcnt_I64,
|
Operator::F32Sqrt | Operator::F64Sqrt => Self::Sqrt_FN,
|
||||||
Inst::F32Abs | Inst::F64Abs => Self::Abs_FN,
|
Operator::I32WrapI64 => Self::Wrap_I32_I64,
|
||||||
Inst::F32Neg | Inst::F64Neg => Self::Neg_FN,
|
Operator::I32TruncF32S => Self::Trunc_I32_F32,
|
||||||
Inst::F32Ceil | Inst::F64Ceil => Self::Ceil_FN,
|
Operator::I32TruncF32U => Self::Trunc_U32_F32,
|
||||||
Inst::F32Floor | Inst::F64Floor => Self::Floor_FN,
|
Operator::I32TruncF64S => Self::Trunc_I32_F64,
|
||||||
Inst::F32Trunc | Inst::F64Trunc => Self::Trunc_FN,
|
Operator::I32TruncF64U => Self::Trunc_U32_F64,
|
||||||
Inst::F32Nearest | Inst::F64Nearest => Self::Nearest_FN,
|
Operator::I32Extend8S => Self::Extend_I32_I8,
|
||||||
Inst::F32Sqrt | Inst::F64Sqrt => Self::Sqrt_FN,
|
Operator::I32Extend16S => Self::Extend_I32_I16,
|
||||||
Inst::I32WrapI64 => Self::Wrap_I32_I64,
|
Operator::I64Extend8S => Self::Extend_I64_I8,
|
||||||
Inst::I32TruncSF32 => Self::Trunc_I32_F32,
|
Operator::I64Extend16S => Self::Extend_I64_I16,
|
||||||
Inst::I32TruncUF32 => Self::Trunc_U32_F32,
|
Operator::I64Extend32S | Operator::I64ExtendI32S => Self::Extend_I64_I32,
|
||||||
Inst::I32TruncSF64 => Self::Trunc_I32_F64,
|
Operator::I64ExtendI32U => Self::Extend_U64_I32,
|
||||||
Inst::I32TruncUF64 => Self::Trunc_U32_F64,
|
Operator::I64TruncF32S => Self::Trunc_I64_F32,
|
||||||
Inst::I64ExtendSI32 => Self::Extend_I64_I32,
|
Operator::I64TruncF32U => Self::Trunc_U64_F32,
|
||||||
Inst::I64ExtendUI32 => Self::Extend_U64_I32,
|
Operator::I64TruncF64S => Self::Trunc_I64_F64,
|
||||||
Inst::I64TruncSF32 => Self::Trunc_I64_F32,
|
Operator::I64TruncF64U => Self::Trunc_U64_F64,
|
||||||
Inst::I64TruncUF32 => Self::Trunc_U64_F32,
|
Operator::F32ConvertI32S => Self::Convert_F32_I32,
|
||||||
Inst::I64TruncSF64 => Self::Trunc_I64_F64,
|
Operator::F32ConvertI32U => Self::Convert_F32_U32,
|
||||||
Inst::I64TruncUF64 => Self::Trunc_U64_F64,
|
Operator::F32ConvertI64S => Self::Convert_F32_I64,
|
||||||
Inst::F32ConvertSI32 => Self::Convert_F32_I32,
|
Operator::F32ConvertI64U => Self::Convert_F32_U64,
|
||||||
Inst::F32ConvertUI32 => Self::Convert_F32_U32,
|
Operator::F32DemoteF64 => Self::Demote_F32_F64,
|
||||||
Inst::F32ConvertSI64 => Self::Convert_F32_I64,
|
Operator::F64ConvertI32S => Self::Convert_F64_I32,
|
||||||
Inst::F32ConvertUI64 => Self::Convert_F32_U64,
|
Operator::F64ConvertI32U => Self::Convert_F64_U32,
|
||||||
Inst::F32DemoteF64 => Self::Demote_F32_F64,
|
Operator::F64ConvertI64S => Self::Convert_F64_I64,
|
||||||
Inst::F64ConvertSI32 => Self::Convert_F64_I32,
|
Operator::F64ConvertI64U => Self::Convert_F64_U64,
|
||||||
Inst::F64ConvertUI32 => Self::Convert_F64_U32,
|
Operator::F64PromoteF32 => Self::Promote_F64_F32,
|
||||||
Inst::F64ConvertSI64 => Self::Convert_F64_I64,
|
Operator::I32ReinterpretF32 => Self::Reinterpret_I32_F32,
|
||||||
Inst::F64ConvertUI64 => Self::Convert_F64_U64,
|
Operator::I64ReinterpretF64 => Self::Reinterpret_I64_F64,
|
||||||
Inst::F64PromoteF32 => Self::Promote_F64_F32,
|
Operator::F32ReinterpretI32 => Self::Reinterpret_F32_I32,
|
||||||
Inst::I32ReinterpretF32 => Self::Reinterpret_I32_F32,
|
Operator::F64ReinterpretI64 => Self::Reinterpret_F64_I64,
|
||||||
Inst::I64ReinterpretF64 => Self::Reinterpret_I64_F64,
|
|
||||||
Inst::F32ReinterpretI32 => Self::Reinterpret_F32_I32,
|
|
||||||
Inst::F64ReinterpretI64 => Self::Reinterpret_F64_I64,
|
|
||||||
_ => return Err(()),
|
_ => return Err(()),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -370,50 +361,48 @@ impl BinOpType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&Instruction> for BinOpType {
|
impl TryFrom<&Operator<'_>> for BinOpType {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
fn try_from(inst: &Instruction) -> Result<Self, Self::Error> {
|
fn try_from(inst: &Operator) -> Result<Self, Self::Error> {
|
||||||
use Instruction as Inst;
|
|
||||||
|
|
||||||
let result = match inst {
|
let result = match inst {
|
||||||
Inst::I32Add => Self::Add_I32,
|
Operator::I32Add => Self::Add_I32,
|
||||||
Inst::I32Sub => Self::Sub_I32,
|
Operator::I32Sub => Self::Sub_I32,
|
||||||
Inst::I32Mul => Self::Mul_I32,
|
Operator::I32Mul => Self::Mul_I32,
|
||||||
Inst::I32DivS => Self::DivS_I32,
|
Operator::I32DivS => Self::DivS_I32,
|
||||||
Inst::I32DivU => Self::DivU_I32,
|
Operator::I32DivU => Self::DivU_I32,
|
||||||
Inst::I32RemS => Self::RemS_I32,
|
Operator::I32RemS => Self::RemS_I32,
|
||||||
Inst::I32RemU => Self::RemU_I32,
|
Operator::I32RemU => Self::RemU_I32,
|
||||||
Inst::I32And => Self::And_I32,
|
Operator::I32And => Self::And_I32,
|
||||||
Inst::I32Or => Self::Or_I32,
|
Operator::I32Or => Self::Or_I32,
|
||||||
Inst::I32Xor => Self::Xor_I32,
|
Operator::I32Xor => Self::Xor_I32,
|
||||||
Inst::I32Shl => Self::Shl_I32,
|
Operator::I32Shl => Self::Shl_I32,
|
||||||
Inst::I32ShrS => Self::ShrS_I32,
|
Operator::I32ShrS => Self::ShrS_I32,
|
||||||
Inst::I32ShrU => Self::ShrU_I32,
|
Operator::I32ShrU => Self::ShrU_I32,
|
||||||
Inst::I32Rotl => Self::Rotl_I32,
|
Operator::I32Rotl => Self::Rotl_I32,
|
||||||
Inst::I32Rotr => Self::Rotr_I32,
|
Operator::I32Rotr => Self::Rotr_I32,
|
||||||
Inst::I64Add => Self::Add_I64,
|
Operator::I64Add => Self::Add_I64,
|
||||||
Inst::I64Sub => Self::Sub_I64,
|
Operator::I64Sub => Self::Sub_I64,
|
||||||
Inst::I64Mul => Self::Mul_I64,
|
Operator::I64Mul => Self::Mul_I64,
|
||||||
Inst::I64DivS => Self::DivS_I64,
|
Operator::I64DivS => Self::DivS_I64,
|
||||||
Inst::I64DivU => Self::DivU_I64,
|
Operator::I64DivU => Self::DivU_I64,
|
||||||
Inst::I64RemS => Self::RemS_I64,
|
Operator::I64RemS => Self::RemS_I64,
|
||||||
Inst::I64RemU => Self::RemU_I64,
|
Operator::I64RemU => Self::RemU_I64,
|
||||||
Inst::I64And => Self::And_I64,
|
Operator::I64And => Self::And_I64,
|
||||||
Inst::I64Or => Self::Or_I64,
|
Operator::I64Or => Self::Or_I64,
|
||||||
Inst::I64Xor => Self::Xor_I64,
|
Operator::I64Xor => Self::Xor_I64,
|
||||||
Inst::I64Shl => Self::Shl_I64,
|
Operator::I64Shl => Self::Shl_I64,
|
||||||
Inst::I64ShrS => Self::ShrS_I64,
|
Operator::I64ShrS => Self::ShrS_I64,
|
||||||
Inst::I64ShrU => Self::ShrU_I64,
|
Operator::I64ShrU => Self::ShrU_I64,
|
||||||
Inst::I64Rotl => Self::Rotl_I64,
|
Operator::I64Rotl => Self::Rotl_I64,
|
||||||
Inst::I64Rotr => Self::Rotr_I64,
|
Operator::I64Rotr => Self::Rotr_I64,
|
||||||
Inst::F32Add | Inst::F64Add => Self::Add_FN,
|
Operator::F32Add | Operator::F64Add => Self::Add_FN,
|
||||||
Inst::F32Sub | Inst::F64Sub => Self::Sub_FN,
|
Operator::F32Sub | Operator::F64Sub => Self::Sub_FN,
|
||||||
Inst::F32Mul | Inst::F64Mul => Self::Mul_FN,
|
Operator::F32Mul | Operator::F64Mul => Self::Mul_FN,
|
||||||
Inst::F32Div | Inst::F64Div => Self::Div_FN,
|
Operator::F32Div | Operator::F64Div => Self::Div_FN,
|
||||||
Inst::F32Min | Inst::F64Min => Self::Min_FN,
|
Operator::F32Min | Operator::F64Min => Self::Min_FN,
|
||||||
Inst::F32Max | Inst::F64Max => Self::Max_FN,
|
Operator::F32Max | Operator::F64Max => Self::Max_FN,
|
||||||
Inst::F32Copysign | Inst::F64Copysign => Self::Copysign_FN,
|
Operator::F32Copysign | Operator::F64Copysign => Self::Copysign_FN,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
@ -488,39 +477,37 @@ impl CmpOpType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&Instruction> for CmpOpType {
|
impl TryFrom<&Operator<'_>> for CmpOpType {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
fn try_from(inst: &Instruction) -> Result<Self, Self::Error> {
|
fn try_from(inst: &Operator) -> Result<Self, Self::Error> {
|
||||||
use Instruction as Inst;
|
|
||||||
|
|
||||||
let result = match inst {
|
let result = match inst {
|
||||||
Inst::I32Eq => Self::Eq_I32,
|
Operator::I32Eq => Self::Eq_I32,
|
||||||
Inst::I32Ne => Self::Ne_I32,
|
Operator::I32Ne => Self::Ne_I32,
|
||||||
Inst::I32LtS => Self::LtS_I32,
|
Operator::I32LtS => Self::LtS_I32,
|
||||||
Inst::I32LtU => Self::LtU_I32,
|
Operator::I32LtU => Self::LtU_I32,
|
||||||
Inst::I32GtS => Self::GtS_I32,
|
Operator::I32GtS => Self::GtS_I32,
|
||||||
Inst::I32GtU => Self::GtU_I32,
|
Operator::I32GtU => Self::GtU_I32,
|
||||||
Inst::I32LeS => Self::LeS_I32,
|
Operator::I32LeS => Self::LeS_I32,
|
||||||
Inst::I32LeU => Self::LeU_I32,
|
Operator::I32LeU => Self::LeU_I32,
|
||||||
Inst::I32GeS => Self::GeS_I32,
|
Operator::I32GeS => Self::GeS_I32,
|
||||||
Inst::I32GeU => Self::GeU_I32,
|
Operator::I32GeU => Self::GeU_I32,
|
||||||
Inst::I64Eq => Self::Eq_I64,
|
Operator::I64Eq => Self::Eq_I64,
|
||||||
Inst::I64Ne => Self::Ne_I64,
|
Operator::I64Ne => Self::Ne_I64,
|
||||||
Inst::I64LtS => Self::LtS_I64,
|
Operator::I64LtS => Self::LtS_I64,
|
||||||
Inst::I64LtU => Self::LtU_I64,
|
Operator::I64LtU => Self::LtU_I64,
|
||||||
Inst::I64GtS => Self::GtS_I64,
|
Operator::I64GtS => Self::GtS_I64,
|
||||||
Inst::I64GtU => Self::GtU_I64,
|
Operator::I64GtU => Self::GtU_I64,
|
||||||
Inst::I64LeS => Self::LeS_I64,
|
Operator::I64LeS => Self::LeS_I64,
|
||||||
Inst::I64LeU => Self::LeU_I64,
|
Operator::I64LeU => Self::LeU_I64,
|
||||||
Inst::I64GeS => Self::GeS_I64,
|
Operator::I64GeS => Self::GeS_I64,
|
||||||
Inst::I64GeU => Self::GeU_I64,
|
Operator::I64GeU => Self::GeU_I64,
|
||||||
Inst::F32Eq | Inst::F64Eq => Self::Eq_FN,
|
Operator::F32Eq | Operator::F64Eq => Self::Eq_FN,
|
||||||
Inst::F32Ne | Inst::F64Ne => Self::Ne_FN,
|
Operator::F32Ne | Operator::F64Ne => Self::Ne_FN,
|
||||||
Inst::F32Lt | Inst::F64Lt => Self::Lt_FN,
|
Operator::F32Lt | Operator::F64Lt => Self::Lt_FN,
|
||||||
Inst::F32Gt | Inst::F64Gt => Self::Gt_FN,
|
Operator::F32Gt | Operator::F64Gt => Self::Gt_FN,
|
||||||
Inst::F32Le | Inst::F64Le => Self::Le_FN,
|
Operator::F32Le | Operator::F64Le => Self::Le_FN,
|
||||||
Inst::F32Ge | Inst::F64Ge => Self::Ge_FN,
|
Operator::F32Ge | Operator::F64Ge => Self::Ge_FN,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
@ -588,6 +575,7 @@ impl GetGlobal {
|
|||||||
|
|
||||||
pub struct LoadAt {
|
pub struct LoadAt {
|
||||||
pub(crate) load_type: LoadType,
|
pub(crate) load_type: LoadType,
|
||||||
|
pub(crate) memory: usize,
|
||||||
pub(crate) offset: u32,
|
pub(crate) offset: u32,
|
||||||
pub(crate) pointer: Box<Expression>,
|
pub(crate) pointer: Box<Expression>,
|
||||||
}
|
}
|
||||||
@ -598,6 +586,11 @@ impl LoadAt {
|
|||||||
self.load_type
|
self.load_type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn memory(&self) -> usize {
|
||||||
|
self.memory
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn offset(&self) -> u32 {
|
pub fn offset(&self) -> u32 {
|
||||||
self.offset
|
self.offset
|
||||||
@ -620,29 +613,6 @@ impl MemorySize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MemoryGrow {
|
|
||||||
pub(crate) memory: usize,
|
|
||||||
pub(crate) result: usize,
|
|
||||||
pub(crate) size: Box<Expression>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MemoryGrow {
|
|
||||||
#[must_use]
|
|
||||||
pub fn memory(&self) -> usize {
|
|
||||||
self.memory
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn result(&self) -> usize {
|
|
||||||
self.result
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn size(&self) -> &Expression {
|
|
||||||
&self.size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
I32(i32),
|
I32(i32),
|
||||||
@ -1001,6 +971,7 @@ impl SetGlobal {
|
|||||||
|
|
||||||
pub struct StoreAt {
|
pub struct StoreAt {
|
||||||
pub(crate) store_type: StoreType,
|
pub(crate) store_type: StoreType,
|
||||||
|
pub(crate) memory: usize,
|
||||||
pub(crate) offset: u32,
|
pub(crate) offset: u32,
|
||||||
pub(crate) pointer: Expression,
|
pub(crate) pointer: Expression,
|
||||||
pub(crate) value: Expression,
|
pub(crate) value: Expression,
|
||||||
@ -1012,6 +983,11 @@ impl StoreAt {
|
|||||||
self.store_type
|
self.store_type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn memory(&self) -> usize {
|
||||||
|
self.memory
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn offset(&self) -> u32 {
|
pub fn offset(&self) -> u32 {
|
||||||
self.offset
|
self.offset
|
||||||
@ -1028,6 +1004,29 @@ impl StoreAt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct MemoryGrow {
|
||||||
|
pub(crate) memory: usize,
|
||||||
|
pub(crate) result: usize,
|
||||||
|
pub(crate) size: Box<Expression>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemoryGrow {
|
||||||
|
#[must_use]
|
||||||
|
pub fn memory(&self) -> usize {
|
||||||
|
self.memory
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn result(&self) -> usize {
|
||||||
|
self.result
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn size(&self) -> &Expression {
|
||||||
|
&self.size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub enum Statement {
|
pub enum Statement {
|
||||||
Forward(Forward),
|
Forward(Forward),
|
||||||
Backward(Backward),
|
Backward(Backward),
|
||||||
@ -1043,7 +1042,7 @@ pub enum Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct FuncData {
|
pub struct FuncData {
|
||||||
pub(crate) local_data: Vec<Local>,
|
pub(crate) local_data: Vec<(u32, ValType)>,
|
||||||
pub(crate) num_result: usize,
|
pub(crate) num_result: usize,
|
||||||
pub(crate) num_param: usize,
|
pub(crate) num_param: usize,
|
||||||
pub(crate) num_stack: usize,
|
pub(crate) num_stack: usize,
|
||||||
@ -1052,7 +1051,7 @@ pub struct FuncData {
|
|||||||
|
|
||||||
impl FuncData {
|
impl FuncData {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn local_data(&self) -> &[Local] {
|
pub fn local_data(&self) -> &[(u32, ValType)] {
|
||||||
&self.local_data
|
&self.local_data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ impl Stack {
|
|||||||
let elem = match data {
|
let elem = match data {
|
||||||
Expression::GetLocal(GetLocal { var }) => ReadType::Local(var),
|
Expression::GetLocal(GetLocal { var }) => ReadType::Local(var),
|
||||||
Expression::GetGlobal(GetGlobal { var }) => ReadType::Global(var),
|
Expression::GetGlobal(GetGlobal { var }) => ReadType::Global(var),
|
||||||
Expression::LoadAt(LoadAt { .. }) => ReadType::Memory(0),
|
Expression::LoadAt(LoadAt { memory, .. }) => ReadType::Memory(memory),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user