Refactor wasm-ast to use wasmparser

This commit is contained in:
Rerumu 2022-06-24 16:55:38 -04:00
parent 6338e29ebb
commit 9f8cf3814b
6 changed files with 596 additions and 426 deletions

View File

@ -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"]

View File

@ -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);
} }
} }

View File

@ -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
View 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)
}
}
}
}

View File

@ -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
} }

View File

@ -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!(),
}; };