diff --git a/wasm-ast/Cargo.toml b/wasm-ast/Cargo.toml index d480ad3..8f5011b 100644 --- a/wasm-ast/Cargo.toml +++ b/wasm-ast/Cargo.toml @@ -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" diff --git a/wasm-ast/src/builder.rs b/wasm-ast/src/factory.rs similarity index 55% rename from wasm-ast/src/builder.rs rename to wasm-ast/src/factory.rs index 946e04b..778f84b 100644 --- a/wasm-ast/src/builder.rs +++ b/wasm-ast/src/factory.rs @@ -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, - func_in: Vec, -} - -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 { - if let &External::Function(i) = import.external() { - Some(i.try_into().unwrap()) - } else { - None - } - } - - fn new_ex_list(wasm: &Module) -> Vec { - 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 { - 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 for Backward { } } -pub struct Builder<'a> { +pub struct Factory<'a> { type_info: &'a TypeInfo<'a>, pending: Vec, @@ -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, _> = func.get_operators_reader().unwrap().into_iter().collect(); + let local: Result, _> = 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); } } diff --git a/wasm-ast/src/lib.rs b/wasm-ast/src/lib.rs index 3fe9dcc..c0d50ee 100644 --- a/wasm-ast/src/lib.rs +++ b/wasm-ast/src/lib.rs @@ -1,4 +1,6 @@ -pub mod builder; +pub mod factory; +pub mod module; pub mod node; -mod stack; pub mod visit; + +mod stack; diff --git a/wasm-ast/src/module.rs b/wasm-ast/src/module.rs new file mode 100644 index 0000000..0a7a6be --- /dev/null +++ b/wasm-ast/src/module.rs @@ -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 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 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, + import_section: Vec>, + func_section: Vec, + table_section: Vec, + memory_section: Vec, + global_section: Vec>, + export_section: Vec>, + element_section: Vec>, + data_section: Vec>, + code_section: Vec>, + + name_section: HashMap, + + start_section: Option, +} + +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 { + &self.name_section + } + + #[must_use] + pub fn start_section(&self) -> Option { + self.start_section + } +} + +pub struct TypeInfo<'a> { + type_list: &'a [Type], + func_list: Vec, +} + +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) + } + } + } +} diff --git a/wasm-ast/src/node.rs b/wasm-ast/src/node.rs index 5f95694..41b48db 100644 --- a/wasm-ast/src/node.rs +++ b/wasm-ast/src/node.rs @@ -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 { - use Instruction as Inst; - + fn try_from(inst: &Operator) -> Result { 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 { - use Instruction as Inst; - + fn try_from(inst: &Operator) -> Result { 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 { - use Instruction as Inst; - + fn try_from(inst: &Operator) -> Result { 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 { - use Instruction as Inst; - + fn try_from(inst: &Operator) -> Result { 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 { - use Instruction as Inst; - + fn try_from(inst: &Operator) -> Result { 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, } @@ -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, -} - -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, +} + +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, + 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 } diff --git a/wasm-ast/src/stack.rs b/wasm-ast/src/stack.rs index 8bedb40..d76b734 100644 --- a/wasm-ast/src/stack.rs +++ b/wasm-ast/src/stack.rs @@ -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!(), };