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"
edition = "2021"
[dependencies.parity-wasm]
git = "https://github.com/paritytech/parity-wasm.git"
features = ["multi_value", "sign_ext"]
[dependencies]
wasmparser = "0.86.0"

View File

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

View File

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

View File

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