diff --git a/runtime/luajit.lua b/runtime/luajit.lua index 15f30c0..3334228 100644 --- a/runtime/luajit.lua +++ b/runtime/luajit.lua @@ -29,11 +29,17 @@ do end do + local eqz = {} + local eq = {} + local ne = {} local le = {} local lt = {} local ge = {} local gt = {} + module.eqz = eqz + module.eq = eq + module.ne = ne module.le = le module.lt = lt module.ge = ge @@ -47,6 +53,10 @@ do end end + function eqz.i32(lhs) return to_boolean(lhs == 0) end + function eqz.i64(lhs) return to_boolean(lhs == 0) end + function eq.i32(lhs, rhs) return to_boolean(lhs == rhs) end + function eq.i64(lhs, rhs) return to_boolean(lhs == rhs) end function ge.u32(lhs, rhs) return to_boolean(u32(lhs) >= u32(rhs)) end function ge.u64(lhs, rhs) return to_boolean(u64(lhs) >= u64(rhs)) end function gt.u32(lhs, rhs) return to_boolean(u32(lhs) > u32(rhs)) end @@ -55,6 +65,8 @@ do function le.u64(lhs, rhs) return to_boolean(u64(lhs) <= u64(rhs)) end function lt.u32(lhs, rhs) return to_boolean(u32(lhs) < u32(rhs)) end function lt.u64(lhs, rhs) return to_boolean(u64(lhs) < u64(rhs)) end + function ne.i32(lhs, rhs) return to_boolean(lhs ~= rhs) end + function ne.i64(lhs, rhs) return to_boolean(lhs ~= rhs) end end do diff --git a/runtime/luau.lua b/runtime/luau.lua index b354d37..40d5388 100644 --- a/runtime/luau.lua +++ b/runtime/luau.lua @@ -15,11 +15,17 @@ do end do + local eqz = {} + local eq = {} + local ne = {} local le = {} local lt = {} local ge = {} local gt = {} + module.eqz = eqz + module.eq = eq + module.ne = ne module.le = le module.lt = lt module.ge = ge @@ -37,6 +43,10 @@ do return x end + function eqz.i32(lhs) return lhs == 0 and 1 or 0 end + function eqz.i64(lhs) return lhs == 0 and 1 or 0 end + function eq.i32(lhs, rhs) return lhs == rhs and 1 or 0 end + function eq.i64(lhs, rhs) return lhs == rhs and 1 or 0 end function ge.u32(lhs, rhs) return unsign_i32(lhs) >= unsign_i32(rhs) and 1 or 0 end function ge.u64(lhs, rhs) return unsign_i64(lhs) >= unsign_i64(rhs) and 1 or 0 end function gt.u32(lhs, rhs) return unsign_i32(lhs) > unsign_i32(rhs) and 1 or 0 end @@ -45,6 +55,8 @@ do function le.u64(lhs, rhs) return unsign_i64(lhs) <= unsign_i64(rhs) and 1 or 0 end function lt.u32(lhs, rhs) return unsign_i32(lhs) < unsign_i32(rhs) and 1 or 0 end function lt.u64(lhs, rhs) return unsign_i64(lhs) < unsign_i64(rhs) and 1 or 0 end + function ne.i32(lhs, rhs) return lhs ~= rhs and 1 or 0 end + function ne.i64(lhs, rhs) return lhs ~= rhs and 1 or 0 end end do diff --git a/src/backend/ast/data.rs b/src/backend/ast/data.rs new file mode 100644 index 0000000..bee024e --- /dev/null +++ b/src/backend/ast/data.rs @@ -0,0 +1,415 @@ +use std::ops::Range; + +use parity_wasm::elements::BrTableData; + +use crate::backend::visitor::data::Visitor; + +use super::operation::{BinOp, Load, Store, UnOp}; + +#[derive(Clone)] +pub struct Select { + pub cond: Box, + pub a: Box, + pub b: Box, +} + +impl Select { + fn accept(&self, visitor: &mut V) { + visitor.visit_select(self); + + self.cond.accept(visitor); + self.a.accept(visitor); + self.b.accept(visitor); + } +} + +#[derive(Clone)] +pub struct GetLocal { + pub var: u32, +} + +impl GetLocal { + fn accept(&self, visitor: &mut V) { + visitor.visit_get_local(self); + } +} + +#[derive(Clone)] +pub struct GetGlobal { + pub var: u32, +} + +impl GetGlobal { + fn accept(&self, visitor: &mut V) { + visitor.visit_get_global(self); + } +} + +#[derive(Clone)] +pub struct AnyLoad { + pub op: Load, + pub offset: u32, + pub pointer: Box, +} + +impl AnyLoad { + fn accept(&self, visitor: &mut V) { + visitor.visit_any_load(self); + + self.pointer.accept(visitor); + } +} + +#[derive(Clone)] +pub struct MemorySize { + pub memory: u8, +} + +impl MemorySize { + fn accept(&self, visitor: &mut V) { + visitor.visit_memory_size(self); + } +} + +#[derive(Clone)] +pub struct MemoryGrow { + pub memory: u8, + pub value: Box, +} + +impl MemoryGrow { + fn accept(&self, visitor: &mut V) { + visitor.visit_memory_grow(self); + + self.value.accept(visitor); + } +} + +#[derive(Clone, Copy)] +pub enum Value { + I32(i32), + I64(i64), + F32(f32), + F64(f64), +} + +impl Value { + fn accept(&self, visitor: &mut V) { + visitor.visit_value(self); + } +} + +#[derive(Clone)] +pub struct AnyUnOp { + pub op: UnOp, + pub rhs: Box, +} + +impl AnyUnOp { + fn accept(&self, visitor: &mut V) { + visitor.visit_any_unop(self); + + self.rhs.accept(visitor); + } +} + +#[derive(Clone)] +pub struct AnyBinOp { + pub op: BinOp, + pub lhs: Box, + pub rhs: Box, +} + +impl AnyBinOp { + fn accept(&self, visitor: &mut V) { + visitor.visit_any_binop(self); + + self.lhs.accept(visitor); + self.rhs.accept(visitor); + } +} + +#[derive(Clone)] +pub enum Expression { + Recall(usize), + Select(Select), + GetLocal(GetLocal), + GetGlobal(GetGlobal), + AnyLoad(AnyLoad), + MemorySize(MemorySize), + MemoryGrow(MemoryGrow), + Value(Value), + AnyUnOp(AnyUnOp), + AnyBinOp(AnyBinOp), +} + +impl Expression { + fn accept(&self, visitor: &mut V) { + visitor.visit_expression(self); + + match self { + Expression::Recall(v) => visitor.visit_recall(*v), + Expression::Select(v) => v.accept(visitor), + Expression::GetLocal(v) => v.accept(visitor), + Expression::GetGlobal(v) => v.accept(visitor), + Expression::AnyLoad(v) => v.accept(visitor), + Expression::MemorySize(v) => v.accept(visitor), + Expression::MemoryGrow(v) => v.accept(visitor), + Expression::Value(v) => v.accept(visitor), + Expression::AnyUnOp(v) => v.accept(visitor), + Expression::AnyBinOp(v) => v.accept(visitor), + } + } + + pub fn is_recalling(&self, wanted: usize) -> bool { + match *self { + Expression::Recall(v) => v == wanted, + _ => false, + } + } +} + +pub struct Memorize { + pub var: usize, + pub value: Expression, +} + +impl Memorize { + fn accept(&self, visitor: &mut V) { + visitor.visit_memorize(self); + + self.value.accept(visitor); + } +} + +pub struct Forward { + pub body: Vec, +} + +impl Forward { + fn accept(&self, visitor: &mut V) { + visitor.visit_forward(self); + + for v in &self.body { + v.accept(visitor); + } + } +} + +pub struct Backward { + pub body: Vec, +} + +impl Backward { + fn accept(&self, visitor: &mut V) { + visitor.visit_backward(self); + + for v in &self.body { + v.accept(visitor); + } + } +} + +pub struct If { + pub cond: Expression, + pub body: Vec, + pub other: Option>, +} + +impl If { + fn accept(&self, visitor: &mut V) { + visitor.visit_if(self); + + self.cond.accept(visitor); + + for v in &self.body { + v.accept(visitor); + } + + if let Some(v) = &self.other { + for v in v { + v.accept(visitor); + } + } + } +} + +pub struct Br { + pub target: u32, +} + +impl Br { + fn accept(&self, visitor: &mut V) { + visitor.visit_br(self); + } +} + +pub struct BrIf { + pub cond: Expression, + pub target: u32, +} + +impl BrIf { + fn accept(&self, visitor: &mut V) { + visitor.visit_br_if(self); + + self.cond.accept(visitor); + } +} + +pub struct BrTable { + pub cond: Expression, + pub data: BrTableData, +} + +impl BrTable { + fn accept(&self, visitor: &mut V) { + visitor.visit_br_table(self); + + self.cond.accept(visitor); + } +} + +pub struct Return { + pub list: Vec, +} + +impl Return { + fn accept(&self, visitor: &mut V) { + visitor.visit_return(self); + + for v in &self.list { + v.accept(visitor); + } + } +} + +pub struct Call { + pub func: u32, + pub result: Range, + pub param_list: Vec, +} + +impl Call { + fn accept(&self, visitor: &mut V) { + visitor.visit_call(self); + + for v in &self.param_list { + v.accept(visitor); + } + } +} + +pub struct CallIndirect { + pub table: u8, + pub index: Expression, + pub result: Range, + pub param_list: Vec, +} + +impl CallIndirect { + fn accept(&self, visitor: &mut V) { + visitor.visit_call_indirect(self); + + self.index.accept(visitor); + + for v in &self.param_list { + v.accept(visitor); + } + } +} + +pub struct SetLocal { + pub var: u32, + pub value: Expression, +} + +impl SetLocal { + fn accept(&self, visitor: &mut V) { + visitor.visit_set_local(self); + + self.value.accept(visitor); + } +} + +pub struct SetGlobal { + pub var: u32, + pub value: Expression, +} + +impl SetGlobal { + fn accept(&self, visitor: &mut V) { + visitor.visit_set_global(self); + + self.value.accept(visitor); + } +} + +pub struct AnyStore { + pub op: Store, + pub offset: u32, + pub pointer: Expression, + pub value: Expression, +} + +impl AnyStore { + fn accept(&self, visitor: &mut V) { + visitor.visit_any_store(self); + + self.pointer.accept(visitor); + self.value.accept(visitor); + } +} + +pub enum Statement { + Unreachable, + Memorize(Memorize), + Forward(Forward), + Backward(Backward), + If(If), + Br(Br), + BrIf(BrIf), + BrTable(BrTable), + Return(Return), + Call(Call), + CallIndirect(CallIndirect), + SetLocal(SetLocal), + SetGlobal(SetGlobal), + AnyStore(AnyStore), +} + +impl Statement { + fn accept(&self, visitor: &mut V) { + match self { + Statement::Unreachable => visitor.visit_unreachable(), + Statement::Memorize(v) => v.accept(visitor), + Statement::Forward(v) => v.accept(visitor), + Statement::Backward(v) => v.accept(visitor), + Statement::If(v) => v.accept(visitor), + Statement::Br(v) => v.accept(visitor), + Statement::BrIf(v) => v.accept(visitor), + Statement::BrTable(v) => v.accept(visitor), + Statement::Return(v) => v.accept(visitor), + Statement::Call(v) => v.accept(visitor), + Statement::CallIndirect(v) => v.accept(visitor), + Statement::SetLocal(v) => v.accept(visitor), + Statement::SetGlobal(v) => v.accept(visitor), + Statement::AnyStore(v) => v.accept(visitor), + } + } +} + +pub struct Function { + pub num_param: u32, + pub num_local: u32, + pub num_stack: u32, + pub body: Vec, +} + +impl Function { + pub fn accept(&self, visitor: &mut V) { + for v in &self.body { + v.accept(visitor); + } + } +} diff --git a/src/backend/ast/mod.rs b/src/backend/ast/mod.rs new file mode 100644 index 0000000..7b61030 --- /dev/null +++ b/src/backend/ast/mod.rs @@ -0,0 +1,3 @@ +pub mod data; +mod operation; +pub mod transformer; diff --git a/src/backend/helper/operation.rs b/src/backend/ast/operation.rs similarity index 69% rename from src/backend/helper/operation.rs rename to src/backend/ast/operation.rs index 30f86eb..3561e3b 100644 --- a/src/backend/helper/operation.rs +++ b/src/backend/ast/operation.rs @@ -2,13 +2,8 @@ use std::convert::TryFrom; use parity_wasm::elements::Instruction; -type Name = (&'static str, &'static str); - -pub trait Named { - fn as_name(&self) -> Name; -} - #[allow(non_camel_case_types)] +#[derive(Clone, Copy)] pub enum Load { I32, I64, @@ -26,23 +21,23 @@ pub enum Load { I64_U32, } -impl Named for Load { - fn as_name(&self) -> Name { +impl Load { + pub fn as_name(self) -> &'static str { match self { - Self::I32 => ("load", "i32"), - Self::I64 => ("load", "i64"), - Self::F32 => ("load", "f32"), - Self::F64 => ("load", "f64"), - Self::I32_I8 => ("load", "i32_i8"), - Self::I32_U8 => ("load", "i32_u8"), - Self::I32_I16 => ("load", "i32_i16"), - Self::I32_U16 => ("load", "i32_u16"), - Self::I64_I8 => ("load", "i64_i8"), - Self::I64_U8 => ("load", "i64_u8"), - Self::I64_I16 => ("load", "i64_i16"), - Self::I64_U16 => ("load", "i64_u16"), - Self::I64_I32 => ("load", "i64_i32"), - Self::I64_U32 => ("load", "i64_u32"), + Self::I32 => "i32", + Self::I64 => "i64", + Self::F32 => "f32", + Self::F64 => "f64", + Self::I32_I8 => "i32_i8", + Self::I32_U8 => "i32_u8", + Self::I32_I16 => "i32_i16", + Self::I32_U16 => "i32_u16", + Self::I64_I8 => "i64_i8", + Self::I64_U8 => "i64_u8", + Self::I64_I16 => "i64_i16", + Self::I64_U16 => "i64_u16", + Self::I64_I32 => "i64_i32", + Self::I64_U32 => "i64_u32", } } } @@ -74,6 +69,7 @@ impl TryFrom<&Instruction> for Load { } #[allow(non_camel_case_types)] +#[derive(Clone, Copy)] pub enum Store { I32, I64, @@ -86,18 +82,18 @@ pub enum Store { I64_N32, } -impl Named for Store { - fn as_name(&self) -> Name { +impl Store { + pub fn as_name(self) -> &'static str { match self { - Self::I32 => ("store", "i32"), - Self::I64 => ("store", "i64"), - Self::F32 => ("store", "f32"), - Self::F64 => ("store", "f64"), - Self::I32_N8 => ("store", "i32_n8"), - Self::I32_N16 => ("store", "i32_n16"), - Self::I64_N8 => ("store", "i64_n8"), - Self::I64_N16 => ("store", "i64_n16"), - Self::I64_N32 => ("store", "i64_n32"), + Self::I32 => "i32", + Self::I64 => "i64", + Self::F32 => "f32", + Self::F64 => "f64", + Self::I32_N8 => "i32_n8", + Self::I32_N16 => "i32_n16", + Self::I64_N8 => "i64_n8", + Self::I64_N16 => "i64_n16", + Self::I64_N32 => "i64_n32", } } } @@ -124,7 +120,10 @@ impl TryFrom<&Instruction> for Store { } #[allow(non_camel_case_types)] +#[derive(Clone, Copy)] pub enum UnOp { + Eqz_I32, + Eqz_I64, Clz_I32, Ctz_I32, Popcnt_I32, @@ -132,6 +131,7 @@ pub enum UnOp { Ctz_I64, Popcnt_I64, Abs_FN, + Neg_FN, Ceil_FN, Floor_FN, Trunc_FN, @@ -165,9 +165,20 @@ pub enum UnOp { Reinterpret_F64_I64, } -impl Named for UnOp { - fn as_name(&self) -> Name { +impl UnOp { + pub fn as_operator(self) -> Option<&'static str> { + let op = match self { + Self::Neg_FN => "-", + _ => return None, + }; + + Some(op) + } + + pub fn as_name(self) -> (&'static str, &'static str) { match self { + Self::Eqz_I32 => ("eqz", "i32"), + Self::Eqz_I64 => ("eqz", "i64"), Self::Clz_I32 => ("clz", "i32"), Self::Ctz_I32 => ("ctz", "i32"), Self::Popcnt_I32 => ("popcnt", "i32"), @@ -175,10 +186,11 @@ impl Named for UnOp { Self::Ctz_I64 => ("ctz", "i64"), Self::Popcnt_I64 => ("popcnt", "i64"), Self::Abs_FN => ("math", "abs"), + Self::Neg_FN => ("neg", "num"), Self::Ceil_FN => ("math", "ceil"), Self::Floor_FN => ("math", "floor"), - Self::Trunc_FN => ("trunc", "f"), - Self::Nearest_FN => ("nearest", "f"), + Self::Trunc_FN => ("trunc", "num"), + Self::Nearest_FN => ("nearest", "num"), Self::Sqrt_FN => ("math", "sqrt"), Self::Copysign_FN => ("math", "sign"), Self::Wrap_I32_I64 => ("wrap", "i64_i32"), @@ -215,6 +227,8 @@ impl TryFrom<&Instruction> for UnOp { fn try_from(inst: &Instruction) -> Result { let result = match inst { + Instruction::I32Eqz => Self::Eqz_I32, + Instruction::I64Eqz => Self::Eqz_I64, Instruction::I32Clz => Self::Clz_I32, Instruction::I32Ctz => Self::Ctz_I32, Instruction::I32Popcnt => Self::Popcnt_I32, @@ -222,6 +236,7 @@ impl TryFrom<&Instruction> for UnOp { Instruction::I64Ctz => Self::Ctz_I64, Instruction::I64Popcnt => Self::Popcnt_I64, Instruction::F32Abs | Instruction::F64Abs => Self::Abs_FN, + Instruction::F32Neg | Instruction::F64Neg => Self::Neg_FN, Instruction::F32Ceil | Instruction::F64Ceil => Self::Ceil_FN, Instruction::F32Floor | Instruction::F64Floor => Self::Floor_FN, Instruction::F32Trunc | Instruction::F64Trunc => Self::Trunc_FN, @@ -261,15 +276,31 @@ impl TryFrom<&Instruction> for UnOp { } #[allow(non_camel_case_types)] +#[derive(Clone, Copy)] pub enum BinOp { + Eq_I32, + Ne_I32, + LtS_I32, LtU_I32, + GtS_I32, GtU_I32, + LeS_I32, LeU_I32, + GeS_I32, GeU_I32, + Eq_I64, + Ne_I64, + LtS_I64, LtU_I64, + GtS_I64, GtU_I64, + LeS_I64, LeU_I64, + GeS_I64, GeU_I64, + Add_I32, + Sub_I32, + Mul_I32, DivS_I32, DivU_I32, RemS_I32, @@ -282,6 +313,9 @@ pub enum BinOp { ShrU_I32, Rotl_I32, Rotr_I32, + Add_I64, + Sub_I64, + Mul_I64, DivS_I64, DivU_I64, RemS_I64, @@ -294,21 +328,59 @@ pub enum BinOp { ShrU_I64, Rotl_I64, Rotr_I64, + Eq_FN, + Ne_FN, + Lt_FN, + Gt_FN, + Le_FN, + Ge_FN, + Add_FN, + Sub_FN, + Mul_FN, + Div_FN, Min_FN, Max_FN, } -impl Named for BinOp { - fn as_name(&self) -> Name { +impl BinOp { + pub fn as_operator(self) -> Option<&'static str> { + let op = match self { + Self::Add_I32 | Self::Add_I64 | Self::Add_FN => "+", + Self::Sub_I32 | Self::Sub_I64 | Self::Sub_FN => "-", + Self::Mul_I32 | Self::Mul_I64 | Self::Mul_FN => "*", + Self::Div_FN => "/", + Self::RemS_I32 | Self::RemU_I32 | Self::RemS_I64 | Self::RemU_I64 => "%", + _ => return None, + }; + + Some(op) + } + + pub fn as_name(self) -> (&'static str, &'static str) { match self { + Self::Eq_I32 => ("eq", "i32"), + Self::Ne_I32 => ("ne", "i32"), + Self::LtS_I32 => ("lt", "i32"), Self::LtU_I32 => ("lt", "u32"), + Self::GtS_I32 => ("gt", "i32"), Self::GtU_I32 => ("gt", "u32"), + Self::LeS_I32 => ("le", "i32"), Self::LeU_I32 => ("le", "u32"), + Self::GeS_I32 => ("ge", "i32"), Self::GeU_I32 => ("ge", "u32"), + Self::Eq_I64 => ("eq", "i64"), + Self::Ne_I64 => ("ne", "i64"), + Self::LtS_I64 => ("lt", "i64"), Self::LtU_I64 => ("lt", "u64"), + Self::GtS_I64 => ("gt", "i64"), Self::GtU_I64 => ("gt", "u64"), + Self::LeS_I64 => ("le", "i64"), Self::LeU_I64 => ("le", "u64"), + Self::GeS_I64 => ("ge", "i64"), Self::GeU_I64 => ("ge", "u64"), + Self::Add_I32 => ("add", "i32"), + Self::Sub_I32 => ("sub", "i32"), + Self::Mul_I32 => ("mul", "i32"), Self::DivS_I32 => ("div", "i32"), Self::DivU_I32 => ("div", "u32"), Self::RemS_I32 => ("rem", "i32"), @@ -321,6 +393,9 @@ impl Named for BinOp { Self::ShrU_I32 => ("shr", "u32"), Self::Rotl_I32 => ("rotl", "i32"), Self::Rotr_I32 => ("rotr", "i32"), + Self::Add_I64 => ("add", "i64"), + Self::Sub_I64 => ("sub", "i64"), + Self::Mul_I64 => ("mul", "i64"), Self::DivS_I64 => ("div", "i64"), Self::DivU_I64 => ("div", "u64"), Self::RemS_I64 => ("rem", "i64"), @@ -333,6 +408,16 @@ impl Named for BinOp { Self::ShrU_I64 => ("shr", "u64"), Self::Rotl_I64 => ("rotl", "i64"), Self::Rotr_I64 => ("rotr", "i64"), + Self::Eq_FN => ("eq", "num"), + Self::Ne_FN => ("ne", "num"), + Self::Lt_FN => ("lt", "num"), + Self::Gt_FN => ("gt", "num"), + Self::Le_FN => ("le", "num"), + Self::Ge_FN => ("ge", "num"), + Self::Add_FN => ("add", "num"), + Self::Sub_FN => ("sub", "num"), + Self::Mul_FN => ("mul", "num"), + Self::Div_FN => ("div", "num"), Self::Min_FN => ("math", "min"), Self::Max_FN => ("math", "max"), } @@ -344,14 +429,29 @@ impl TryFrom<&Instruction> for BinOp { fn try_from(inst: &Instruction) -> Result { let result = match inst { + Instruction::I32Eq => Self::Eq_I32, + Instruction::I32Ne => Self::Ne_I32, + Instruction::I32LtS => Self::LtS_I32, Instruction::I32LtU => Self::LtU_I32, + Instruction::I32GtS => Self::GtS_I32, Instruction::I32GtU => Self::GtU_I32, + Instruction::I32LeS => Self::LeS_I32, Instruction::I32LeU => Self::LeU_I32, + Instruction::I32GeS => Self::GeS_I32, Instruction::I32GeU => Self::GeU_I32, + Instruction::I64Eq => Self::Eq_I64, + Instruction::I64Ne => Self::Ne_I64, + Instruction::I64LtS => Self::LtS_I64, Instruction::I64LtU => Self::LtU_I64, + Instruction::I64GtS => Self::GtS_I64, Instruction::I64GtU => Self::GtU_I64, + Instruction::I64LeS => Self::LeS_I64, Instruction::I64LeU => Self::LeU_I64, + Instruction::I64GeS => Self::GeS_I64, Instruction::I64GeU => Self::GeU_I64, + Instruction::I32Add => Self::Add_I32, + Instruction::I32Sub => Self::Sub_I32, + Instruction::I32Mul => Self::Mul_I32, Instruction::I32DivS => Self::DivS_I32, Instruction::I32DivU => Self::DivU_I32, Instruction::I32RemS => Self::RemS_I32, @@ -364,6 +464,9 @@ impl TryFrom<&Instruction> for BinOp { Instruction::I32ShrU => Self::ShrU_I32, Instruction::I32Rotl => Self::Rotl_I32, Instruction::I32Rotr => Self::Rotr_I32, + Instruction::I64Add => Self::Add_I64, + Instruction::I64Sub => Self::Sub_I64, + Instruction::I64Mul => Self::Mul_I64, Instruction::I64DivS => Self::DivS_I64, Instruction::I64DivU => Self::DivU_I64, Instruction::I64RemS => Self::RemS_I64, @@ -376,6 +479,16 @@ impl TryFrom<&Instruction> for BinOp { Instruction::I64ShrU => Self::ShrU_I64, Instruction::I64Rotl => Self::Rotl_I64, Instruction::I64Rotr => Self::Rotr_I64, + Instruction::F32Eq | Instruction::F64Eq => Self::Eq_FN, + Instruction::F32Ne | Instruction::F64Ne => Self::Ne_FN, + Instruction::F32Lt | Instruction::F64Lt => Self::Lt_FN, + Instruction::F32Gt | Instruction::F64Gt => Self::Gt_FN, + Instruction::F32Le | Instruction::F64Le => Self::Le_FN, + Instruction::F32Ge | Instruction::F64Ge => Self::Ge_FN, + Instruction::F32Add | Instruction::F64Add => Self::Add_FN, + Instruction::F32Sub | Instruction::F64Sub => Self::Sub_FN, + Instruction::F32Mul | Instruction::F64Mul => Self::Mul_FN, + Instruction::F32Div | Instruction::F64Div => Self::Div_FN, Instruction::F32Min | Instruction::F64Min => Self::Min_FN, Instruction::F32Max | Instruction::F64Max => Self::Max_FN, _ => { diff --git a/src/backend/ast/transformer.rs b/src/backend/ast/transformer.rs new file mode 100644 index 0000000..968ce9a --- /dev/null +++ b/src/backend/ast/transformer.rs @@ -0,0 +1,405 @@ +use parity_wasm::elements::{Instruction, Local, Module}; + +use crate::backend::translator::arity::{Arity, List as ArityList}; + +use super::{ + data::Memorize, + operation::{BinOp, UnOp}, + { + data::{ + AnyBinOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, CallIndirect, + Expression, Forward, Function, GetGlobal, GetLocal, If, MemoryGrow, MemorySize, Return, + Select, SetGlobal, SetLocal, Statement, Value, + }, + operation::{Load, Store}, + }, +}; + +pub struct Transformer<'a> { + // target state + wasm: &'a Module, + arity: &'a ArityList, + name: usize, + + // translation state + sleeping: Vec>, + living: Vec, + last_stack: usize, +} + +fn is_now_else(inst: &[Instruction]) -> bool { + inst.get(0) == Some(&Instruction::Else) +} + +fn local_sum(list: &[Local]) -> u32 { + list.iter().map(Local::count).sum() +} + +impl<'a> Transformer<'a> { + pub fn new(wasm: &'a Module, arity: &'a ArityList, name: usize) -> Transformer<'a> { + Transformer { + wasm, + arity, + name, + sleeping: Vec::new(), + living: Vec::new(), + last_stack: 0, + } + } + + pub fn consume(mut self) -> Function { + debug_assert!(self.name != usize::MAX, "Not an indexed value"); + + let func = &self.wasm.code_section().unwrap().bodies()[self.name]; + let body = self.new_stored_body(&mut func.code().elements()); + + Function { + num_param: self.arity.in_arity[self.name].num_param, + num_local: local_sum(func.locals()), + num_stack: u32::try_from(self.last_stack).unwrap(), + body, + } + } + + fn gen_push_recall(&mut self, num: u32) { + let len = self.living.len(); + + (len..len + num as usize) + .map(Expression::Recall) + .for_each(|v| self.living.push(v)); + } + + // If any expressions are still pending at the start of + // statement, we leak them into variables. + // Since expressions do not have set ordering rules, this is + // safe and condenses code. + fn gen_leak_pending(&mut self, stat: &mut Vec) { + self.last_stack = self.last_stack.max(self.living.len()); + + for (i, v) in self + .living + .iter_mut() + .enumerate() + .filter(|v| !v.1.is_recalling(v.0)) + { + let new = Expression::Recall(i); + let mem = Memorize { + var: i, + value: std::mem::replace(v, new), + }; + + stat.push(Statement::Memorize(mem)); + } + } + + // Pending expressions are put to sleep before entering + // a control structure so that they are not lost. + fn save_pending(&mut self) { + self.sleeping.push(self.living.clone()); + } + + fn load_pending(&mut self) { + let mut old = self.sleeping.pop().unwrap(); + + if self.living.len() > old.len() { + let rem = self.living.drain(old.len()..); + + old.extend(rem); + } + + self.living = old; + } + + fn gen_return(&mut self, stat: &mut Vec) { + let num = self.arity.in_arity[self.name].num_result as usize; + let list = self.living.split_off(self.living.len() - num); + + self.gen_leak_pending(stat); + stat.push(Statement::Return(Return { list })); + } + + fn gen_call(&mut self, func: u32, stat: &mut Vec) { + let arity = self.arity.arity_of(func as usize); + + let param_list = self + .living + .split_off(self.living.len() - arity.num_param as usize); + + let len = u32::try_from(self.living.len()).unwrap(); + let result = len..len + arity.num_result; + + self.gen_push_recall(arity.num_result); + self.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 types = self.wasm.type_section().unwrap().types(); + let arity = Arity::from_index(types, typ); + + let index = self.living.pop().unwrap(); + let param_list = self + .living + .split_off(self.living.len() - arity.num_param as usize); + + let len = u32::try_from(self.living.len()).unwrap(); + let result = len..len + arity.num_result; + + self.gen_push_recall(arity.num_result); + self.gen_leak_pending(stat); + stat.push(Statement::CallIndirect(CallIndirect { + table, + index, + result, + param_list, + })); + } + + fn push_load(&mut self, op: Load, offset: u32) { + let pointer = Box::new(self.living.pop().unwrap()); + + self.living.push(Expression::AnyLoad(AnyLoad { + op, + offset, + pointer, + })); + } + + fn gen_store(&mut self, op: Store, offset: u32, stat: &mut Vec) { + let value = self.living.pop().unwrap(); + let pointer = self.living.pop().unwrap(); + + self.gen_leak_pending(stat); + stat.push(Statement::AnyStore(AnyStore { + op, + offset, + pointer, + value, + })); + } + + fn push_constant(&mut self, value: Value) { + self.living.push(Expression::Value(value)); + } + + fn push_un_op(&mut self, op: UnOp) { + let rhs = Box::new(self.living.pop().unwrap()); + + self.living.push(Expression::AnyUnOp(AnyUnOp { op, rhs })); + } + + fn push_bin_op(&mut self, op: BinOp) { + let rhs = Box::new(self.living.pop().unwrap()); + let lhs = Box::new(self.living.pop().unwrap()); + + self.living + .push(Expression::AnyBinOp(AnyBinOp { op, lhs, rhs })); + } + + fn new_body(&mut self, list: &mut &[Instruction]) -> Vec { + use Instruction as Inst; + + let mut stat = Vec::new(); + + while let Some(inst) = list.get(0) { + *list = &list[1..]; + + if let Ok(op) = UnOp::try_from(inst) { + self.push_un_op(op); + + continue; + } else if let Ok(op) = BinOp::try_from(inst) { + self.push_bin_op(op); + + continue; + } + + match inst { + Inst::Nop => {} + Inst::Unreachable => { + self.gen_leak_pending(&mut stat); + stat.push(Statement::Unreachable); + } + Inst::Block(_) => { + self.gen_leak_pending(&mut stat); + + let data = self.new_forward(list); + + stat.push(Statement::Forward(data)); + } + Inst::Loop(_) => { + self.gen_leak_pending(&mut stat); + + let data = self.new_backward(list); + + stat.push(Statement::Backward(data)); + } + Inst::If(_) => { + let cond = self.living.pop().unwrap(); + + self.gen_leak_pending(&mut stat); + + let data = self.new_if(cond, list); + + stat.push(Statement::If(data)); + } + Inst::Else => { + self.gen_leak_pending(&mut stat); + + break; + } + Inst::End => { + if list.is_empty() && !self.living.is_empty() { + self.gen_return(&mut stat); + } else { + self.gen_leak_pending(&mut stat); + } + + break; + } + Inst::Br(i) => { + self.gen_leak_pending(&mut stat); + + stat.push(Statement::Br(Br { target: *i })); + } + Inst::BrIf(i) => { + let cond = self.living.pop().unwrap(); + + self.gen_leak_pending(&mut stat); + stat.push(Statement::BrIf(BrIf { cond, target: *i })); + } + Inst::BrTable(t) => { + let cond = self.living.pop().unwrap(); + + self.gen_leak_pending(&mut stat); + stat.push(Statement::BrTable(BrTable { + cond, + data: *t.clone(), + })); + } + Inst::Return => { + self.gen_return(&mut stat); + } + Inst::Call(i) => { + self.gen_call(*i, &mut stat); + } + Inst::CallIndirect(i, t) => { + self.gen_call_indirect(*i, *t, &mut stat); + } + Inst::Drop => { + self.living.pop().unwrap(); + } + Inst::Select => { + let cond = Box::new(self.living.pop().unwrap()); + let b = Box::new(self.living.pop().unwrap()); + let a = Box::new(self.living.pop().unwrap()); + + self.living.push(Expression::Select(Select { cond, a, b })); + } + Inst::GetLocal(i) => { + self.living.push(Expression::GetLocal(GetLocal { var: *i })); + } + Inst::SetLocal(i) => { + let value = self.living.pop().unwrap(); + + self.gen_leak_pending(&mut stat); + stat.push(Statement::SetLocal(SetLocal { var: *i, value })); + } + Inst::TeeLocal(i) => { + self.gen_leak_pending(&mut stat); + + let value = self.living.last().unwrap().clone(); + + stat.push(Statement::SetLocal(SetLocal { var: *i, value })); + } + Inst::GetGlobal(i) => { + self.living + .push(Expression::GetGlobal(GetGlobal { var: *i })); + } + Inst::SetGlobal(i) => { + let value = self.living.pop().unwrap(); + + 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::CurrentMemory(i) => { + self.living + .push(Expression::MemorySize(MemorySize { memory: *i })); + } + Inst::GrowMemory(i) => { + let value = Box::new(self.living.pop().unwrap()); + + // `MemoryGrow` is an expression *but* it has side effects + self.gen_leak_pending(&mut stat); + self.living + .push(Expression::MemoryGrow(MemoryGrow { memory: *i, value })); + } + 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))), + _ => unreachable!(), + } + } + + stat + } + + fn new_stored_body(&mut self, list: &mut &[Instruction]) -> Vec { + self.save_pending(); + + let body = self.new_body(list); + + self.load_pending(); + + body + } + + fn new_if(&mut self, cond: Expression, list: &mut &[Instruction]) -> If { + let body = self.new_stored_body(list); + let other = is_now_else(list).then(|| { + *list = &list[1..]; + self.new_stored_body(list) + }); + + If { cond, body, other } + } + + fn new_backward(&mut self, list: &mut &[Instruction]) -> Backward { + Backward { + body: self.new_stored_body(list), + } + } + + fn new_forward(&mut self, list: &mut &[Instruction]) -> Forward { + Forward { + body: self.new_stored_body(list), + } + } +} diff --git a/src/backend/edition/data.rs b/src/backend/edition/data.rs index 88762c9..51b5cee 100644 --- a/src/backend/edition/data.rs +++ b/src/backend/edition/data.rs @@ -1,6 +1,7 @@ -use std::{fmt::Display, io::Result}; - -use crate::backend::helper::writer::Writer; +use std::{ + fmt::Display, + io::{Result, Write}, +}; use super::{luajit::LuaJIT, luau::Luau}; @@ -28,15 +29,15 @@ where pub trait Edition { fn runtime(&self) -> &'static str; - fn start_block(&self, w: Writer) -> Result<()>; - fn start_loop(&self, level: usize, w: Writer) -> Result<()>; - fn start_if(&self, cond: &str, w: Writer) -> Result<()>; - fn end_block(&self, level: usize, w: Writer) -> Result<()>; - fn end_loop(&self, w: Writer) -> Result<()>; - fn end_if(&self, level: usize, w: Writer) -> Result<()>; + fn start_block(&self, w: &mut dyn Write) -> Result<()>; + fn start_loop(&self, level: usize, w: &mut dyn Write) -> Result<()>; + fn start_if(&self, cond: &str, w: &mut dyn Write) -> Result<()>; + fn end_block(&self, level: usize, w: &mut dyn Write) -> Result<()>; + fn end_loop(&self, w: &mut dyn Write) -> Result<()>; + fn end_if(&self, level: usize, w: &mut dyn Write) -> Result<()>; - fn br_target(&self, level: usize, in_loop: bool, w: Writer) -> Result<()>; - fn br_to_level(&self, level: usize, up: usize, is_loop: bool, w: Writer) -> Result<()>; + fn br_target(&self, level: usize, in_loop: bool, w: &mut dyn Write) -> Result<()>; + fn br_to_level(&self, level: usize, up: usize, is_loop: bool, w: &mut dyn Write) -> Result<()>; fn i64(&self, i: i64) -> Infix; } diff --git a/src/backend/edition/luajit.rs b/src/backend/edition/luajit.rs index 4e52983..36e0016 100644 --- a/src/backend/edition/luajit.rs +++ b/src/backend/edition/luajit.rs @@ -1,6 +1,4 @@ -use std::io::Result; - -use crate::backend::helper::writer::Writer; +use std::io::{Result, Write}; use super::data::{Edition, Infix}; @@ -11,38 +9,44 @@ impl Edition for LuaJIT { "'luajit'" } - fn start_block(&self, w: Writer) -> Result<()> { + fn start_block(&self, w: &mut dyn Write) -> Result<()> { write!(w, "do ") } - fn start_loop(&self, level: usize, w: Writer) -> Result<()> { + fn start_loop(&self, level: usize, w: &mut dyn Write) -> Result<()> { write!(w, "do ")?; write!(w, "::continue_at_{}::", level) } - fn start_if(&self, cond: &str, w: Writer) -> Result<()> { + fn start_if(&self, cond: &str, w: &mut dyn Write) -> Result<()> { write!(w, "if {} ~= 0 then ", cond) } - fn end_block(&self, level: usize, w: Writer) -> Result<()> { + fn end_block(&self, level: usize, w: &mut dyn Write) -> Result<()> { write!(w, "::continue_at_{}::", level)?; write!(w, "end ") } - fn end_loop(&self, w: Writer) -> Result<()> { + fn end_loop(&self, w: &mut dyn Write) -> Result<()> { write!(w, "end ") } - fn end_if(&self, level: usize, w: Writer) -> Result<()> { + fn end_if(&self, level: usize, w: &mut dyn Write) -> Result<()> { write!(w, "::continue_at_{}::", level)?; write!(w, "end ") } - fn br_target(&self, _level: usize, _in_loop: bool, _w: Writer) -> Result<()> { + fn br_target(&self, _level: usize, _in_loop: bool, _w: &mut dyn Write) -> Result<()> { Ok(()) } - fn br_to_level(&self, level: usize, up: usize, _is_loop: bool, w: Writer) -> Result<()> { + fn br_to_level( + &self, + level: usize, + up: usize, + _is_loop: bool, + w: &mut dyn Write, + ) -> Result<()> { write!(w, "goto continue_at_{} ", level - up) } diff --git a/src/backend/edition/luau.rs b/src/backend/edition/luau.rs index 1a5f338..00b4adc 100644 --- a/src/backend/edition/luau.rs +++ b/src/backend/edition/luau.rs @@ -1,6 +1,4 @@ -use std::io::Result; - -use crate::backend::helper::writer::Writer; +use std::io::{Result, Write}; use super::data::{Edition, Infix}; @@ -11,36 +9,36 @@ impl Edition for Luau { "script.Runtime" } - fn start_block(&self, w: Writer) -> Result<()> { + fn start_block(&self, w: &mut dyn Write) -> Result<()> { write!(w, "while true do ") } - fn start_loop(&self, _level: usize, w: Writer) -> Result<()> { + fn start_loop(&self, _level: usize, w: &mut dyn Write) -> Result<()> { write!(w, "while true do ") } - fn start_if(&self, cond: &str, w: Writer) -> Result<()> { + fn start_if(&self, cond: &str, w: &mut dyn Write) -> Result<()> { write!(w, "while true do ")?; write!(w, "if {} ~= 0 then ", cond) } - fn end_block(&self, _level: usize, w: Writer) -> Result<()> { + fn end_block(&self, _level: usize, w: &mut dyn Write) -> Result<()> { write!(w, "break ")?; write!(w, "end ") } - fn end_loop(&self, w: Writer) -> Result<()> { + fn end_loop(&self, w: &mut dyn Write) -> Result<()> { write!(w, "break ")?; write!(w, "end ") } - fn end_if(&self, _level: usize, w: Writer) -> Result<()> { + fn end_if(&self, _level: usize, w: &mut dyn Write) -> Result<()> { write!(w, "end ")?; write!(w, "break ")?; write!(w, "end ") } - fn br_target(&self, level: usize, in_loop: bool, w: Writer) -> Result<()> { + fn br_target(&self, level: usize, in_loop: bool, w: &mut dyn Write) -> Result<()> { write!(w, "if desired then ")?; write!(w, "if desired == {} then ", level)?; write!(w, "desired = nil ")?; @@ -54,7 +52,7 @@ impl Edition for Luau { write!(w, "end ") } - fn br_to_level(&self, level: usize, up: usize, is_loop: bool, w: Writer) -> Result<()> { + fn br_to_level(&self, level: usize, up: usize, is_loop: bool, w: &mut dyn Write) -> Result<()> { write!(w, "do ")?; if up == 0 { diff --git a/src/backend/helper/mod.rs b/src/backend/helper/mod.rs deleted file mode 100644 index f9760fb..0000000 --- a/src/backend/helper/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod operation; -pub mod register; -pub mod writer; diff --git a/src/backend/helper/register.rs b/src/backend/helper/register.rs deleted file mode 100755 index 3fc33e3..0000000 --- a/src/backend/helper/register.rs +++ /dev/null @@ -1,41 +0,0 @@ -pub struct Register { - pub last: u32, - pub inner: u32, - saved: Vec, -} - -impl Register { - pub fn new() -> Self { - Self { - last: 0, - inner: 0, - saved: vec![0], - } - } - - fn extend(&mut self) { - self.last = self.last.max(self.inner); - } - - pub fn save(&mut self) { - self.saved.push(self.inner); - } - - pub fn load(&mut self) { - self.inner = self.saved.pop().unwrap(); - } - - pub fn push(&mut self, n: u32) -> u32 { - let prev = self.inner; - - self.inner = self.inner.checked_add(n).unwrap(); - self.extend(); - - prev - } - - pub fn pop(&mut self, n: u32) -> u32 { - self.inner = self.inner.checked_sub(n).unwrap(); - self.inner - } -} diff --git a/src/backend/helper/writer.rs b/src/backend/helper/writer.rs deleted file mode 100644 index 86e16b4..0000000 --- a/src/backend/helper/writer.rs +++ /dev/null @@ -1,17 +0,0 @@ -use std::io::{Result, Write}; - -pub type Writer<'a> = &'a mut dyn Write; - -pub fn ordered_iter(prefix: &'static str, end: u32) -> impl Iterator { - (1..=end).map(move |i| format!("{}_{}", prefix, i)) -} - -pub fn write_ordered(prefix: &'static str, end: u32, w: Writer) -> Result<()> { - let mut iter = ordered_iter(prefix, end); - - if let Some(s) = iter.next() { - write!(w, "{}", s)?; - } - - iter.try_for_each(|s| write!(w, ", {}", s)) -} diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 5725e11..3bb5960 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -1,4 +1,4 @@ +mod ast; pub mod edition; -pub mod helper; pub mod translator; -pub mod visitor; +mod visitor; diff --git a/src/backend/translator/arity.rs b/src/backend/translator/arity.rs new file mode 100755 index 0000000..b93e335 --- /dev/null +++ b/src/backend/translator/arity.rs @@ -0,0 +1,81 @@ +use std::convert::TryInto; + +use parity_wasm::elements::{External, FunctionType, ImportEntry, Module, Type}; + +pub struct Arity { + pub num_param: u32, + pub num_result: u32, +} + +impl Arity { + fn from_type(typ: &FunctionType) -> Self { + let num_param = typ.params().len().try_into().unwrap(); + let num_result = typ.results().len().try_into().unwrap(); + + Self { + num_param, + num_result, + } + } + + pub fn from_index(types: &[Type], index: u32) -> Self { + let Type::Function(typ) = &types[index as usize]; + + Self::from_type(typ) + } +} + +pub struct List { + pub ex_arity: Vec, + pub in_arity: Vec, +} + +impl List { + pub fn new(parent: &Module) -> Self { + Self { + ex_arity: Self::new_arity_ex_list(parent), + in_arity: Self::new_arity_in_list(parent), + } + } + + pub fn arity_of(&self, index: usize) -> &Arity { + let offset = self.ex_arity.len(); + + self.ex_arity + .get(index) + .or_else(|| self.in_arity.get(index - offset)) + .unwrap() + } + + fn new_arity_ext(types: &[Type], import: &ImportEntry) -> Option { + if let External::Function(i) = import.external() { + Some(Arity::from_index(types, *i)) + } else { + None + } + } + + fn new_arity_in_list(wasm: &Module) -> Vec { + let (types, funcs) = match (wasm.type_section(), wasm.function_section()) { + (Some(t), Some(f)) => (t.types(), f.entries()), + _ => return Vec::new(), + }; + + funcs + .iter() + .map(|i| Arity::from_index(types, i.type_ref())) + .collect() + } + + fn new_arity_ex_list(wasm: &Module) -> Vec { + let (types, imports) = match (wasm.type_section(), wasm.import_section()) { + (Some(t), Some(i)) => (t.types(), i.entries()), + _ => return Vec::new(), + }; + + imports + .iter() + .filter_map(|i| Self::new_arity_ext(types, i)) + .collect() + } +} diff --git a/src/backend/translator/data.rs b/src/backend/translator/data.rs new file mode 100644 index 0000000..c01759f --- /dev/null +++ b/src/backend/translator/data.rs @@ -0,0 +1,279 @@ +use std::io::{Result, Write}; + +use parity_wasm::elements::{ + External, ImportCountType, Instruction, Internal, Module as WasmModule, ResizableLimits, +}; + +use crate::backend::{ast::transformer::Transformer, edition::data::Edition}; + +use super::{arity::List as ArityList, writer::Data}; + +fn aux_internal_index(internal: Internal) -> u32 { + match internal { + Internal::Function(v) | Internal::Table(v) | Internal::Memory(v) | Internal::Global(v) => v, + } +} + +fn gen_table_init(limit: &ResizableLimits, w: &mut dyn Write) -> Result<()> { + write!(w, "{{ min = {}", limit.initial())?; + + if let Some(max) = limit.maximum() { + write!(w, ", max = {}", max)?; + } + + write!(w, ", data = {{}} }}") +} + +fn gen_memory_init(limit: &ResizableLimits, w: &mut dyn Write) -> Result<()> { + write!(w, "rt.memory.new({}, ", limit.initial())?; + + if let Some(max) = limit.maximum() { + write!(w, "{}", max)?; + } else { + write!(w, "nil")?; + } + + write!(w, ")") +} + +fn gen_nil_array(name: &str, len: usize, w: &mut dyn Write) -> Result<()> { + if len == 0 { + return Ok(()); + } + + write!(w, "local {} = {{[0] = {}}}", name, "nil, ".repeat(len)) +} + +pub fn gen_expression(code: &[Instruction], w: &mut dyn Write) -> Result<()> { + assert!(code.len() == 2); + + let inst = code.first().unwrap(); + + match *inst { + Instruction::I32Const(v) => write!(w, "{} ", v), + Instruction::I64Const(v) => write!(w, "{} ", v), + Instruction::F32Const(v) => write!(w, "{} ", f32::from_bits(v)), + Instruction::F64Const(v) => write!(w, "{} ", f64::from_bits(v)), + Instruction::GetGlobal(i) => write!(w, "GLOBAL_LIST[{}].value ", i), + _ => unreachable!(), + } +} + +pub struct Module<'a> { + wasm: &'a WasmModule, + arity: ArityList, +} + +impl<'a> Module<'a> { + pub fn new(wasm: &'a WasmModule) -> Self { + let arity = ArityList::new(wasm); + + Self { wasm, arity } + } + + fn gen_import_of(&self, w: &mut dyn Write, lower: &str, cond: T) -> Result<()> + where + T: Fn(&External) -> bool, + { + let import = match self.wasm.import_section() { + Some(v) => v.entries(), + None => return Ok(()), + }; + let upper = lower.to_uppercase(); + + for (i, v) in import.iter().filter(|v| cond(v.external())).enumerate() { + let field = v.field(); + let module = v.module(); + + write!(w, "{}[{}] = wasm.{}.{}.{} ", upper, i, module, lower, field)?; + } + + Ok(()) + } + + fn gen_export_of(&self, w: &mut dyn Write, lower: &str, cond: T) -> Result<()> + where + T: Fn(&Internal) -> bool, + { + let export = match self.wasm.export_section() { + Some(v) => v.entries(), + None => return Ok(()), + }; + let upper = lower.to_uppercase(); + + write!(w, "{} = {{", lower)?; + + for v in export.iter().filter(|v| cond(v.internal())) { + let field = v.field(); + let index = aux_internal_index(*v.internal()); + + write!(w, "{} = {}[{}],", field, upper, index)?; + } + + write!(w, "}},") + } + + fn gen_import_list(&self, w: &mut dyn Write) -> Result<()> { + self.gen_import_of(w, "func_list", |v| matches!(v, External::Function(_)))?; + self.gen_import_of(w, "table_list", |v| matches!(v, External::Table(_)))?; + self.gen_import_of(w, "memory_list", |v| matches!(v, External::Memory(_)))?; + self.gen_import_of(w, "global_list", |v| matches!(v, External::Global(_))) + } + + fn gen_export_list(&self, w: &mut dyn Write) -> Result<()> { + self.gen_export_of(w, "func_list", |v| matches!(v, Internal::Function(_)))?; + self.gen_export_of(w, "table_list", |v| matches!(v, Internal::Table(_)))?; + self.gen_export_of(w, "memory_list", |v| matches!(v, Internal::Memory(_)))?; + self.gen_export_of(w, "global_list", |v| matches!(v, Internal::Global(_))) + } + + fn gen_table_list(&self, w: &mut dyn Write) -> Result<()> { + let table = match self.wasm.table_section() { + Some(v) => v.entries(), + None => return Ok(()), + }; + let offset = self.wasm.import_count(ImportCountType::Table); + + for (i, v) in table.iter().enumerate() { + let index = i + offset; + + write!(w, "TABLE_LIST[{}] =", index)?; + gen_table_init(v.limits(), w)?; + } + + Ok(()) + } + + fn gen_memory_list(&self, w: &mut dyn Write) -> Result<()> { + let memory = match self.wasm.memory_section() { + Some(v) => v.entries(), + None => return Ok(()), + }; + let offset = self.wasm.import_count(ImportCountType::Memory); + + for (i, v) in memory.iter().enumerate() { + let index = i + offset; + + write!(w, "MEMORY_LIST[{}] =", index)?; + gen_memory_init(v.limits(), w)?; + } + + Ok(()) + } + + fn gen_global_list(&self, w: &mut dyn Write) -> Result<()> { + let global = match self.wasm.global_section() { + Some(v) => v, + None => return Ok(()), + }; + let offset = self.wasm.import_count(ImportCountType::Global); + + for (i, v) in global.entries().iter().enumerate() { + let index = i + offset; + + write!(w, "GLOBAL_LIST[{}] = {{ value =", index)?; + + gen_expression(v.init_expr().code(), w)?; + + write!(w, "}}")?; + } + + Ok(()) + } + + fn gen_element_list(&self, w: &mut dyn Write) -> Result<()> { + let element = match self.wasm.elements_section() { + Some(v) => v.entries(), + None => return Ok(()), + }; + + for v in element { + write!(w, "do ")?; + write!(w, "local target = TABLE_LIST[{}].data ", v.index())?; + write!(w, "local offset =")?; + + gen_expression(v.offset().as_ref().unwrap().code(), w)?; + + for (i, f) in v.members().iter().enumerate() { + write!(w, "target[offset + {}] = FUNC_LIST[{}]", i, f)?; + } + + write!(w, "end ")?; + } + + Ok(()) + } + + fn gen_data_list(&self, w: &mut dyn Write) -> Result<()> { + let data = match self.wasm.data_section() { + Some(v) => v.entries(), + None => return Ok(()), + }; + + for v in data { + write!(w, "do ")?; + write!(w, "local target = MEMORY_LIST[{}]", v.index())?; + write!(w, "local offset =")?; + + gen_expression(v.offset().as_ref().unwrap().code(), w)?; + + write!(w, "local data = \"")?; + + v.value() + .iter() + .try_for_each(|v| write!(w, "\\x{:02X}", v))?; + + write!(w, "\"")?; + + write!(w, "rt.memory.init(target, offset, data)")?; + + write!(w, "end ")?; + } + + Ok(()) + } + + fn gen_start_point(&self, w: &mut dyn Write) -> Result<()> { + write!(w, "local function run_init_code()")?; + self.gen_table_list(w)?; + self.gen_memory_list(w)?; + self.gen_global_list(w)?; + self.gen_element_list(w)?; + self.gen_data_list(w)?; + write!(w, "end ")?; + + write!(w, "return function(wasm)")?; + self.gen_import_list(w)?; + write!(w, "run_init_code()")?; + + if let Some(start) = self.wasm.start_section() { + write!(w, "FUNC_LIST[{}]()", start)?; + } + + write!(w, "return {{")?; + self.gen_export_list(w)?; + write!(w, "}} end ") + } + + pub fn translate(&self, ed: &dyn Edition, w: &mut dyn Write) -> Result<()> { + write!(w, "local rt = require({})", ed.runtime())?; + + gen_nil_array("FUNC_LIST", self.wasm.functions_space(), w)?; + gen_nil_array("TABLE_LIST", self.wasm.table_space(), w)?; + gen_nil_array("MEMORY_LIST", self.wasm.memory_space(), w)?; + gen_nil_array("GLOBAL_LIST", self.wasm.globals_space(), w)?; + + let offset = self.arity.ex_arity.len(); + + for i in 0..self.arity.in_arity.len() { + let func = Transformer::new(self.wasm, &self.arity, i).consume(); + let data = &mut Data::new(func.num_param, ed); + + write!(w, "FUNC_LIST[{}] =", i + offset)?; + + func.output(data, w)?; + } + + self.gen_start_point(w) + } +} diff --git a/src/backend/translator/level_1.rs b/src/backend/translator/level_1.rs deleted file mode 100644 index 2315203..0000000 --- a/src/backend/translator/level_1.rs +++ /dev/null @@ -1,483 +0,0 @@ -use std::{fmt::Display, io::Result, ops::Range}; - -use parity_wasm::elements::{BrTableData, Instruction}; - -use crate::{ - backend::{ - edition::data::Edition, - helper::{register::Register, writer::Writer}, - }, - data::{Arity, Code, Module}, -}; - -pub fn list_to_range(list: &[u32]) -> Vec<(Range, u32)> { - let mut result = Vec::new(); - let mut index = 0; - - while index < list.len() { - let start = index; - - loop { - index += 1; - - // if end of list or next value is not equal, break - if index == list.len() || list[index - 1] != list[index] { - break; - } - } - - result.push((start..index, list[start])); - } - - result -} - -#[derive(PartialEq)] -pub enum Label { - Block, - If, - Loop, -} - -pub struct Body<'a> { - spec: &'a dyn Edition, - label_list: Vec