diff --git a/wasm-ast/src/builder.rs b/wasm-ast/src/builder.rs index b76bb30..df058b8 100644 --- a/wasm-ast/src/builder.rs +++ b/wasm-ast/src/builder.rs @@ -99,103 +99,16 @@ impl Arities { } } -pub struct Builder<'a> { - // target state - wasm: &'a Module, - other: &'a Arities, - num_result: u32, - - // translation state - pending: Vec>, +#[derive(Default)] +struct Stacked { + pending_list: Vec>, stack: Vec, last_stack: usize, } -fn is_else_stat(inst: &Instruction) -> bool { - inst == &Instruction::Else -} - -fn is_dead_precursor(inst: &Instruction) -> bool { - matches!( - inst, - Instruction::Unreachable | Instruction::Br(_) | Instruction::Return - ) -} - -fn flat_local_list(local: Local) -> impl Iterator { - std::iter::repeat(local.value_type()).take(local.count().try_into().unwrap()) -} - -fn load_local_list(func: &FuncBody) -> Vec { - func.locals() - .iter() - .copied() - .flat_map(flat_local_list) - .collect() -} - -fn load_func_at(wasm: &Module, index: usize) -> &FuncBody { - &wasm.code_section().unwrap().bodies()[index] -} - -impl<'a> Builder<'a> { - #[must_use] - pub fn new(wasm: &'a Module, other: &'a Arities) -> Builder<'a> { - Builder { - wasm, - other, - num_result: 0, - pending: Vec::new(), - stack: Vec::new(), - last_stack: 0, - } - } - - #[must_use] - pub fn consume(mut self, index: usize) -> Function { - let func = load_func_at(self.wasm, index); - let arity = &self.other.in_arity[index]; - - let local_list = load_local_list(func); - let num_param = arity.num_param; - - self.num_result = arity.num_result; - - let body = self.new_forward(&mut func.code().elements()); - let num_stack = self.last_stack.try_into().unwrap(); - - Function { - local_list, - num_param, - num_stack, - body, - } - } - - fn get_type_of(&self, index: u32) -> Arity { - let types = self.wasm.type_section().unwrap().types(); - - Arity::from_index(types, index) - } - - fn push_recall(&mut self, num: u32) { - let len = self.stack.len(); - - for var in len..len + num as usize { - self.stack.push(Expression::Recall(Recall { var })); - } - } - - fn push_block_result(&mut self, typ: BlockType) { - let num = match typ { - BlockType::NoResult => { - return; - } - BlockType::Value(_) => 1, - BlockType::TypeIndex(i) => self.get_type_of(i).num_result, - }; - - self.push_recall(num); +impl Stacked { + fn new() -> Self { + Self::default() } // If any expressions are still pending at the start of @@ -226,63 +139,35 @@ impl<'a> Builder<'a> { fn save_pending(&mut self) { let cloned = self.stack.iter().map(Expression::clone_recall).collect(); - self.pending.push(cloned); + self.pending_list.push(cloned); } fn load_pending(&mut self) { - self.stack = self.pending.pop().unwrap(); + self.stack = self.pending_list.pop().unwrap(); } - fn gen_return(&mut self, stat: &mut Vec) { - let num = self.num_result as usize; - let list = self.stack.split_off(self.stack.len() - num); - - self.gen_leak_pending(stat); - stat.push(Statement::Return(Return { list })); + fn pop(&mut self) -> Expression { + self.stack.pop().unwrap() } - fn gen_call(&mut self, func: u32, stat: &mut Vec) { - let arity = self.other.arity_of(func as usize); - - let param_list = self - .stack - .split_off(self.stack.len() - arity.num_param as usize); - - let len = u32::try_from(self.stack.len()).unwrap(); - let result = len..len + arity.num_result; - - self.push_recall(arity.num_result); - self.gen_leak_pending(stat); - stat.push(Statement::Call(Call { - func, - result, - param_list, - })); + fn push(&mut self, value: Expression) { + self.stack.push(value); } - fn gen_call_indirect(&mut self, typ: u32, table: u8, stat: &mut Vec) { - let arity = self.get_type_of(typ); + fn push_constant(&mut self, value: Value) { + self.stack.push(Expression::Value(value)); + } - let index = self.stack.pop().unwrap(); - let param_list = self - .stack - .split_off(self.stack.len() - arity.num_param as usize); + fn push_recall(&mut self, num: u32) { + let len = self.stack.len(); - let len = u32::try_from(self.stack.len()).unwrap(); - let result = len..len + arity.num_result; - - self.push_recall(arity.num_result); - self.gen_leak_pending(stat); - stat.push(Statement::CallIndirect(CallIndirect { - table, - index, - result, - param_list, - })); + for var in len..len + num as usize { + self.stack.push(Expression::Recall(Recall { var })); + } } fn push_load(&mut self, op: Load, offset: u32) { - let pointer = Box::new(self.stack.pop().unwrap()); + let pointer = Box::new(self.pop()); self.stack.push(Expression::AnyLoad(AnyLoad { op, @@ -292,10 +177,11 @@ impl<'a> Builder<'a> { } fn gen_store(&mut self, op: Store, offset: u32, stat: &mut Vec) { - let value = self.stack.pop().unwrap(); - let pointer = self.stack.pop().unwrap(); + let value = self.pop(); + let pointer = self.pop(); self.gen_leak_pending(stat); + stat.push(Statement::AnyStore(AnyStore { op, offset, @@ -304,27 +190,23 @@ impl<'a> Builder<'a> { })); } - fn push_constant(&mut self, value: Value) { - self.stack.push(Expression::Value(value)); - } - fn push_un_op(&mut self, op: UnOp) { - let rhs = Box::new(self.stack.pop().unwrap()); + let rhs = Box::new(self.pop()); self.stack.push(Expression::AnyUnOp(AnyUnOp { op, rhs })); } fn push_bin_op(&mut self, op: BinOp) { - let rhs = Box::new(self.stack.pop().unwrap()); - let lhs = Box::new(self.stack.pop().unwrap()); + let rhs = Box::new(self.pop()); + let lhs = Box::new(self.pop()); self.stack .push(Expression::AnyBinOp(AnyBinOp { op, lhs, rhs })); } fn push_cmp_op(&mut self, op: CmpOp) { - let rhs = Box::new(self.stack.pop().unwrap()); - let lhs = Box::new(self.stack.pop().unwrap()); + let rhs = Box::new(self.pop()); + let lhs = Box::new(self.pop()); self.stack .push(Expression::AnyCmpOp(AnyCmpOp { op, lhs, rhs })); @@ -367,6 +249,142 @@ impl<'a> Builder<'a> { self.from_equal_zero(inst) } } +} + +pub struct Builder<'a> { + // target state + wasm: &'a Module, + other: &'a Arities, + num_result: u32, + + // translation state + data: Stacked, +} + +fn is_else_stat(inst: &Instruction) -> bool { + inst == &Instruction::Else +} + +fn is_dead_precursor(inst: &Instruction) -> bool { + matches!( + inst, + Instruction::Unreachable | Instruction::Br(_) | Instruction::Return + ) +} + +fn flat_local_list(local: Local) -> impl Iterator { + std::iter::repeat(local.value_type()).take(local.count().try_into().unwrap()) +} + +fn load_local_list(func: &FuncBody) -> Vec { + func.locals() + .iter() + .copied() + .flat_map(flat_local_list) + .collect() +} + +fn load_func_at(wasm: &Module, index: usize) -> &FuncBody { + &wasm.code_section().unwrap().bodies()[index] +} + +impl<'a> Builder<'a> { + #[must_use] + pub fn new(wasm: &'a Module, other: &'a Arities) -> Builder<'a> { + Builder { + wasm, + other, + num_result: 0, + data: Stacked::new(), + } + } + + #[must_use] + pub fn consume(mut self, index: usize) -> Function { + let func = load_func_at(self.wasm, index); + let arity = &self.other.in_arity[index]; + + let local_list = load_local_list(func); + let num_param = arity.num_param; + + self.num_result = arity.num_result; + + let body = self.new_forward(&mut func.code().elements()); + let num_stack = self.data.last_stack.try_into().unwrap(); + + Function { + local_list, + num_param, + num_stack, + body, + } + } + + fn get_type_of(&self, index: u32) -> Arity { + let types = self.wasm.type_section().unwrap().types(); + + Arity::from_index(types, index) + } + + fn push_block_result(&mut self, typ: BlockType) { + let num = match typ { + BlockType::NoResult => { + return; + } + BlockType::Value(_) => 1, + BlockType::TypeIndex(i) => self.get_type_of(i).num_result, + }; + + self.data.push_recall(num); + } + + fn gen_return(&mut self, stat: &mut Vec) { + let num = self.num_result as usize; + let list = self.data.stack.split_off(self.data.stack.len() - num); + + self.data.gen_leak_pending(stat); + + stat.push(Statement::Return(Return { list })); + } + + fn gen_call(&mut self, func: u32, stat: &mut Vec) { + let arity = self.other.arity_of(func as usize); + let len = self.data.stack.len(); + + let first = u32::try_from(len).unwrap(); + let result = first..first + arity.num_result; + let param_list = self.data.stack.split_off(len - arity.num_param as usize); + + self.data.push_recall(arity.num_result); + self.data.gen_leak_pending(stat); + + stat.push(Statement::Call(Call { + func, + result, + param_list, + })); + } + + fn gen_call_indirect(&mut self, typ: u32, table: u8, stat: &mut Vec) { + let arity = self.get_type_of(typ); + let len = self.data.stack.len(); + + let index = self.data.pop(); + let param_list = self.data.stack.split_off(len - arity.num_param as usize); + + let first = u32::try_from(len).unwrap(); + let result = first..first + arity.num_result; + + self.data.push_recall(arity.num_result); + self.data.gen_leak_pending(stat); + + stat.push(Statement::CallIndirect(CallIndirect { + table, + index, + result, + param_list, + })); + } fn drop_unreachable(list: &mut &[Instruction]) { use Instruction as Inst; @@ -405,14 +423,14 @@ impl<'a> Builder<'a> { let mut stat = Vec::new(); - self.save_pending(); + self.data.save_pending(); loop { let inst = &list[0]; *list = &list[1..]; - if self.from_operation(inst) { + if self.data.from_operation(inst) { continue; } @@ -422,7 +440,7 @@ impl<'a> Builder<'a> { stat.push(Statement::Unreachable); } Inst::Block(t) => { - self.gen_leak_pending(&mut stat); + self.data.gen_leak_pending(&mut stat); let data = self.new_forward(list); @@ -430,7 +448,7 @@ impl<'a> Builder<'a> { stat.push(Statement::Forward(data)); } Inst::Loop(t) => { - self.gen_leak_pending(&mut stat); + self.data.gen_leak_pending(&mut stat); let data = self.new_backward(list); @@ -438,9 +456,9 @@ impl<'a> Builder<'a> { stat.push(Statement::Backward(data)); } Inst::If(t) => { - let cond = self.stack.pop().unwrap(); + let cond = self.data.pop(); - self.gen_leak_pending(&mut stat); + self.data.gen_leak_pending(&mut stat); let data = self.new_if(cond, list); @@ -448,7 +466,7 @@ impl<'a> Builder<'a> { stat.push(Statement::If(data)); } Inst::Else => { - self.gen_leak_pending(&mut stat); + self.data.gen_leak_pending(&mut stat); break; } @@ -456,25 +474,25 @@ impl<'a> Builder<'a> { if list.is_empty() && self.num_result != 0 { self.gen_return(&mut stat); } else { - self.gen_leak_pending(&mut stat); + self.data.gen_leak_pending(&mut stat); } break; } Inst::Br(i) => { - self.gen_leak_pending(&mut stat); + self.data.gen_leak_pending(&mut stat); stat.push(Statement::Br(Br { target: *i })); } Inst::BrIf(i) => { - let cond = self.stack.pop().unwrap(); + let cond = self.data.pop(); - self.gen_leak_pending(&mut stat); + self.data.gen_leak_pending(&mut stat); stat.push(Statement::BrIf(BrIf { cond, target: *i })); } Inst::BrTable(t) => { - let cond = self.stack.pop().unwrap(); + let cond = self.data.pop(); - self.gen_leak_pending(&mut stat); + self.data.gen_leak_pending(&mut stat); stat.push(Statement::BrTable(BrTable { cond, data: *t.clone(), @@ -490,80 +508,80 @@ impl<'a> Builder<'a> { self.gen_call_indirect(*i, *t, &mut stat); } Inst::Drop => { - self.stack.pop().unwrap(); + self.data.pop(); } Inst::Select => { - let cond = Box::new(self.stack.pop().unwrap()); - let b = Box::new(self.stack.pop().unwrap()); - let a = Box::new(self.stack.pop().unwrap()); + let cond = Box::new(self.data.pop()); + let b = Box::new(self.data.pop()); + let a = Box::new(self.data.pop()); - self.stack.push(Expression::Select(Select { cond, a, b })); + self.data.push(Expression::Select(Select { cond, a, b })); } Inst::GetLocal(i) => { - self.stack.push(Expression::GetLocal(GetLocal { var: *i })); + self.data.push(Expression::GetLocal(GetLocal { var: *i })); } Inst::SetLocal(i) => { - let value = self.stack.pop().unwrap(); + let value = self.data.pop(); - self.gen_leak_pending(&mut stat); + self.data.gen_leak_pending(&mut stat); stat.push(Statement::SetLocal(SetLocal { var: *i, value })); } Inst::TeeLocal(i) => { - self.gen_leak_pending(&mut stat); + self.data.gen_leak_pending(&mut stat); - let value = self.stack.last().unwrap().clone_recall(); + let value = self.data.pop(); + self.data.push(value.clone_recall()); stat.push(Statement::SetLocal(SetLocal { var: *i, value })); } Inst::GetGlobal(i) => { - self.stack - .push(Expression::GetGlobal(GetGlobal { var: *i })); + self.data.push(Expression::GetGlobal(GetGlobal { var: *i })); } Inst::SetGlobal(i) => { - let value = self.stack.pop().unwrap(); + let value = self.data.pop(); stat.push(Statement::SetGlobal(SetGlobal { var: *i, value })); } - Inst::I32Load(_, o) => self.push_load(Load::I32, *o), - Inst::I64Load(_, o) => self.push_load(Load::I64, *o), - Inst::F32Load(_, o) => self.push_load(Load::F32, *o), - Inst::F64Load(_, o) => self.push_load(Load::F64, *o), - Inst::I32Load8S(_, o) => self.push_load(Load::I32_I8, *o), - Inst::I32Load8U(_, o) => self.push_load(Load::I32_U8, *o), - Inst::I32Load16S(_, o) => self.push_load(Load::I32_I16, *o), - Inst::I32Load16U(_, o) => self.push_load(Load::I32_U16, *o), - Inst::I64Load8S(_, o) => self.push_load(Load::I64_I8, *o), - Inst::I64Load8U(_, o) => self.push_load(Load::I64_U8, *o), - Inst::I64Load16S(_, o) => self.push_load(Load::I64_I16, *o), - Inst::I64Load16U(_, o) => self.push_load(Load::I64_U16, *o), - Inst::I64Load32S(_, o) => self.push_load(Load::I64_I32, *o), - Inst::I64Load32U(_, o) => self.push_load(Load::I64_U32, *o), - Inst::I32Store(_, o) => self.gen_store(Store::I32, *o, &mut stat), - Inst::I64Store(_, o) => self.gen_store(Store::I64, *o, &mut stat), - Inst::F32Store(_, o) => self.gen_store(Store::F32, *o, &mut stat), - Inst::F64Store(_, o) => self.gen_store(Store::F64, *o, &mut stat), - Inst::I32Store8(_, o) => self.gen_store(Store::I32_N8, *o, &mut stat), - Inst::I32Store16(_, o) => self.gen_store(Store::I32_N16, *o, &mut stat), - Inst::I64Store8(_, o) => self.gen_store(Store::I64_N8, *o, &mut stat), - Inst::I64Store16(_, o) => self.gen_store(Store::I64_N16, *o, &mut stat), - Inst::I64Store32(_, o) => self.gen_store(Store::I64_N32, *o, &mut stat), + Inst::I32Load(_, o) => self.data.push_load(Load::I32, *o), + Inst::I64Load(_, o) => self.data.push_load(Load::I64, *o), + Inst::F32Load(_, o) => self.data.push_load(Load::F32, *o), + Inst::F64Load(_, o) => self.data.push_load(Load::F64, *o), + Inst::I32Load8S(_, o) => self.data.push_load(Load::I32_I8, *o), + Inst::I32Load8U(_, o) => self.data.push_load(Load::I32_U8, *o), + Inst::I32Load16S(_, o) => self.data.push_load(Load::I32_I16, *o), + Inst::I32Load16U(_, o) => self.data.push_load(Load::I32_U16, *o), + Inst::I64Load8S(_, o) => self.data.push_load(Load::I64_I8, *o), + Inst::I64Load8U(_, o) => self.data.push_load(Load::I64_U8, *o), + Inst::I64Load16S(_, o) => self.data.push_load(Load::I64_I16, *o), + Inst::I64Load16U(_, o) => self.data.push_load(Load::I64_U16, *o), + Inst::I64Load32S(_, o) => self.data.push_load(Load::I64_I32, *o), + Inst::I64Load32U(_, o) => self.data.push_load(Load::I64_U32, *o), + Inst::I32Store(_, o) => self.data.gen_store(Store::I32, *o, &mut stat), + Inst::I64Store(_, o) => self.data.gen_store(Store::I64, *o, &mut stat), + Inst::F32Store(_, o) => self.data.gen_store(Store::F32, *o, &mut stat), + Inst::F64Store(_, o) => self.data.gen_store(Store::F64, *o, &mut stat), + Inst::I32Store8(_, o) => self.data.gen_store(Store::I32_N8, *o, &mut stat), + Inst::I32Store16(_, o) => self.data.gen_store(Store::I32_N16, *o, &mut stat), + Inst::I64Store8(_, o) => self.data.gen_store(Store::I64_N8, *o, &mut stat), + Inst::I64Store16(_, o) => self.data.gen_store(Store::I64_N16, *o, &mut stat), + Inst::I64Store32(_, o) => self.data.gen_store(Store::I64_N32, *o, &mut stat), Inst::CurrentMemory(i) => { - self.stack + self.data .push(Expression::MemorySize(MemorySize { memory: *i })); } Inst::GrowMemory(i) => { - let value = Box::new(self.stack.pop().unwrap()); + let value = Box::new(self.data.pop()); // `MemoryGrow` is an expression *but* it has side effects - self.stack + self.data .push(Expression::MemoryGrow(MemoryGrow { memory: *i, value })); - self.gen_leak_pending(&mut stat); + self.data.gen_leak_pending(&mut stat); } - Inst::I32Const(v) => self.push_constant(Value::I32(*v)), - Inst::I64Const(v) => self.push_constant(Value::I64(*v)), - Inst::F32Const(v) => self.push_constant(Value::F32(f32::from_bits(*v))), - Inst::F64Const(v) => self.push_constant(Value::F64(f64::from_bits(*v))), + Inst::I32Const(v) => self.data.push_constant(Value::I32(*v)), + Inst::I64Const(v) => self.data.push_constant(Value::I64(*v)), + Inst::F32Const(v) => self.data.push_constant(Value::F32(f32::from_bits(*v))), + Inst::F64Const(v) => self.data.push_constant(Value::F64(f64::from_bits(*v))), _ => unreachable!(), } @@ -574,7 +592,7 @@ impl<'a> Builder<'a> { } } - self.load_pending(); + self.data.load_pending(); stat }