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