From 96a27c9626d475f685048c97a425fd94b5249373 Mon Sep 17 00:00:00 2001 From: Rerumu Date: Tue, 30 Nov 2021 03:27:17 -0500 Subject: [PATCH] Refactor the codebase and organize files --- fuzz/fuzz_targets/full_translate.rs | 23 +- fuzz/fuzz_targets/just_transformer.rs | 9 +- fuzz/fuzz_targets/just_writer.rs | 22 +- .../{backend/visitor => analyzer}/localize.rs | 4 +- .../{backend/visitor => analyzer}/memory.rs | 4 +- wasm/src/{backend/visitor => analyzer}/mod.rs | 2 +- wasm/src/analyzer/visit.rs | 317 ++++++++ .../ast/transformer.rs => ast/builder.rs} | 142 +++- wasm/src/ast/mod.rs | 3 + wasm/src/ast/node.rs | 184 +++++ .../{backend/ast/operation.rs => ast/tag.rs} | 262 ++++--- wasm/src/backend/ast/data.rs | 413 ---------- wasm/src/backend/ast/mod.rs | 3 - wasm/src/backend/edition/data.rs | 51 -- wasm/src/backend/edition/luajit.rs | 56 -- wasm/src/backend/edition/luau.rs | 75 -- wasm/src/backend/mod.rs | 4 - wasm/src/backend/translator/arity.rs | 81 -- wasm/src/backend/translator/data.rs | 311 -------- wasm/src/backend/translator/mod.rs | 3 - wasm/src/backend/translator/writer.rs | 505 ------------ wasm/src/backend/visitor/data.rs | 59 -- wasm/src/lib.rs | 4 +- wasm/src/main.rs | 26 +- wasm/src/writer/luajit.rs | 724 +++++++++++++++++ wasm/src/writer/luau.rs | 727 ++++++++++++++++++ wasm/src/{backend/edition => writer}/mod.rs | 3 +- wasm/src/writer/shared.rs | 109 +++ wasm/src/writer/visit.rs | 15 + 29 files changed, 2370 insertions(+), 1771 deletions(-) rename wasm/src/{backend/visitor => analyzer}/localize.rs (88%) rename wasm/src/{backend/visitor => analyzer}/memory.rs (83%) rename wasm/src/{backend/visitor => analyzer}/mod.rs (70%) create mode 100644 wasm/src/analyzer/visit.rs rename wasm/src/{backend/ast/transformer.rs => ast/builder.rs} (80%) create mode 100644 wasm/src/ast/mod.rs create mode 100644 wasm/src/ast/node.rs rename wasm/src/{backend/ast/operation.rs => ast/tag.rs} (58%) delete mode 100644 wasm/src/backend/ast/data.rs delete mode 100644 wasm/src/backend/ast/mod.rs delete mode 100644 wasm/src/backend/edition/data.rs delete mode 100644 wasm/src/backend/edition/luajit.rs delete mode 100644 wasm/src/backend/edition/luau.rs delete mode 100644 wasm/src/backend/mod.rs delete mode 100755 wasm/src/backend/translator/arity.rs delete mode 100644 wasm/src/backend/translator/data.rs delete mode 100644 wasm/src/backend/translator/mod.rs delete mode 100644 wasm/src/backend/translator/writer.rs delete mode 100644 wasm/src/backend/visitor/data.rs create mode 100644 wasm/src/writer/luajit.rs create mode 100644 wasm/src/writer/luau.rs rename wasm/src/{backend/edition => writer}/mod.rs (52%) create mode 100644 wasm/src/writer/shared.rs create mode 100644 wasm/src/writer/visit.rs diff --git a/fuzz/fuzz_targets/full_translate.rs b/fuzz/fuzz_targets/full_translate.rs index 732e790..1c6e0a5 100644 --- a/fuzz/fuzz_targets/full_translate.rs +++ b/fuzz/fuzz_targets/full_translate.rs @@ -1,30 +1,19 @@ #![no_main] -use std::io::Result; +use wasm_smith::Module; -use parity_wasm::elements::Module as WasmModule; -use wasm_smith::Module as SmModule; - -use wasm::backend::{ - edition::{data::Edition, luajit::LuaJIT}, - translator::data::Module, -}; - -fn fuzz_translate(wasm: &WasmModule, ed: &dyn Edition) -> Result<()> { - let mut sink = std::io::sink(); - let module = Module::new(wasm); - - module.translate(ed, &mut sink) -} +use wasm::writer::{luajit::LuaJIT, visit::Transpiler}; // We are not interested in parity_wasm errors. // Only 1 edition should need to be tested too. -libfuzzer_sys::fuzz_target!(|module: SmModule| { +libfuzzer_sys::fuzz_target!(|module: Module| { let data = module.to_bytes(); let wasm = match parity_wasm::deserialize_buffer(&data) { Ok(v) => v, Err(_) => return, }; - fuzz_translate(&wasm, &LuaJIT).expect("LuaJIT should succeed"); + LuaJIT::new(&wasm) + .transpile(&mut std::io::sink()) + .expect("LuaJIT should succeed"); }); diff --git a/fuzz/fuzz_targets/just_transformer.rs b/fuzz/fuzz_targets/just_transformer.rs index b036ef1..438e55f 100644 --- a/fuzz/fuzz_targets/just_transformer.rs +++ b/fuzz/fuzz_targets/just_transformer.rs @@ -3,14 +3,11 @@ use parity_wasm::elements::Module as WasmModule; use wasm_smith::Module as SmModule; -use wasm::backend::{ast::transformer::Transformer, translator::arity::List}; +use wasm::writer::{luajit::LuaJIT, visit::Transpiler}; fn fuzz_transformer(wasm: &WasmModule) { - let arity = List::new(wasm); - - for i in 0..arity.in_arity.len() { - let _ = Transformer::new(wasm, &arity).consume(i); - } + let trans = LuaJIT::new(wasm); + let _func = trans.build_func_list(); } libfuzzer_sys::fuzz_target!(|module: SmModule| { diff --git a/fuzz/fuzz_targets/just_writer.rs b/fuzz/fuzz_targets/just_writer.rs index d5e85c3..4e1ed47 100644 --- a/fuzz/fuzz_targets/just_writer.rs +++ b/fuzz/fuzz_targets/just_writer.rs @@ -5,23 +5,13 @@ use std::io::Result; use parity_wasm::elements::Module as WasmModule; use wasm_smith::Module as SmModule; -use wasm::backend::{ - ast::transformer::Transformer, - edition::{data::Edition, luajit::LuaJIT}, - translator::{arity::List, writer::Data}, -}; +use wasm::writer::{luajit::LuaJIT, visit::Transpiler}; -fn fuzz_writer(wasm: &WasmModule, ed: &dyn Edition) -> Result<()> { - let mut sink = std::io::sink(); - let arity = List::new(wasm); +fn fuzz_writer(wasm: &WasmModule) -> Result<()> { + let trans = LuaJIT::new(wasm); + let list = trans.build_func_list(); - for i in 0..arity.in_arity.len() { - let func = Transformer::new(wasm, &arity).consume(i); - - func.output(&mut Data::new(ed), &mut sink)?; - } - - Ok(()) + trans.gen_func_list(&list, &mut std::io::sink()) } libfuzzer_sys::fuzz_target!(|module: SmModule| { @@ -31,5 +21,5 @@ libfuzzer_sys::fuzz_target!(|module: SmModule| { Err(_) => return, }; - fuzz_writer(&wasm, &LuaJIT).expect("LuaJIT should succeed"); + fuzz_writer(&wasm).expect("LuaJIT should succeed"); }); diff --git a/wasm/src/backend/visitor/localize.rs b/wasm/src/analyzer/localize.rs similarity index 88% rename from wasm/src/backend/visitor/localize.rs rename to wasm/src/analyzer/localize.rs index ea58767..ecf8c0c 100644 --- a/wasm/src/backend/visitor/localize.rs +++ b/wasm/src/analyzer/localize.rs @@ -1,8 +1,8 @@ use std::collections::BTreeSet; -use crate::backend::ast::data::{AnyBinOp, AnyLoad, AnyStore, AnyUnOp, Function}; +use crate::ast::node::{AnyBinOp, AnyLoad, AnyStore, AnyUnOp, Function}; -use super::data::Visitor; +use super::visit::{Driver, Visitor}; struct Visit { result: BTreeSet<(&'static str, &'static str)>, diff --git a/wasm/src/backend/visitor/memory.rs b/wasm/src/analyzer/memory.rs similarity index 83% rename from wasm/src/backend/visitor/memory.rs rename to wasm/src/analyzer/memory.rs index 6f2a742..44b38a8 100644 --- a/wasm/src/backend/visitor/memory.rs +++ b/wasm/src/analyzer/memory.rs @@ -1,8 +1,8 @@ use std::collections::BTreeSet; -use crate::backend::ast::data::{AnyLoad, AnyStore, Function, MemoryGrow, MemorySize}; +use crate::ast::node::{AnyLoad, AnyStore, Function, MemoryGrow, MemorySize}; -use super::data::Visitor; +use super::visit::{Driver, Visitor}; struct Visit { result: BTreeSet, diff --git a/wasm/src/backend/visitor/mod.rs b/wasm/src/analyzer/mod.rs similarity index 70% rename from wasm/src/backend/visitor/mod.rs rename to wasm/src/analyzer/mod.rs index 132b917..bb93ed4 100644 --- a/wasm/src/backend/visitor/mod.rs +++ b/wasm/src/analyzer/mod.rs @@ -1,3 +1,3 @@ -pub mod data; pub mod localize; pub mod memory; +mod visit; diff --git a/wasm/src/analyzer/visit.rs b/wasm/src/analyzer/visit.rs new file mode 100644 index 0000000..ca00a0f --- /dev/null +++ b/wasm/src/analyzer/visit.rs @@ -0,0 +1,317 @@ +use crate::ast::node::{ + AnyBinOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, CallIndirect, Else, + Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize, MemoryGrow, MemorySize, + Recall, Return, Select, SetGlobal, SetLocal, Statement, Value, +}; + +pub trait Visitor { + fn visit_recall(&mut self, _: &Recall) {} + + fn visit_select(&mut self, _: &Select) {} + + fn visit_get_local(&mut self, _: &GetLocal) {} + + fn visit_get_global(&mut self, _: &GetGlobal) {} + + fn visit_any_load(&mut self, _: &AnyLoad) {} + + fn visit_memory_size(&mut self, _: &MemorySize) {} + + fn visit_memory_grow(&mut self, _: &MemoryGrow) {} + + fn visit_value(&mut self, _: &Value) {} + + fn visit_any_unop(&mut self, _: &AnyUnOp) {} + + fn visit_any_binop(&mut self, _: &AnyBinOp) {} + + fn visit_expression(&mut self, _: &Expression) {} + + fn visit_unreachable(&mut self) {} + + fn visit_memorize(&mut self, _: &Memorize) {} + + fn visit_forward(&mut self, _: &Forward) {} + + fn visit_backward(&mut self, _: &Backward) {} + + fn visit_else(&mut self, _: &Else) {} + + fn visit_if(&mut self, _: &If) {} + + fn visit_br(&mut self, _: &Br) {} + + fn visit_br_if(&mut self, _: &BrIf) {} + + fn visit_br_table(&mut self, _: &BrTable) {} + + fn visit_return(&mut self, _: &Return) {} + + fn visit_call(&mut self, _: &Call) {} + + fn visit_call_indirect(&mut self, _: &CallIndirect) {} + + fn visit_set_local(&mut self, _: &SetLocal) {} + + fn visit_set_global(&mut self, _: &SetGlobal) {} + + fn visit_any_store(&mut self, _: &AnyStore) {} + + fn visit_statement(&mut self, _: &Statement) {} +} + +pub trait Driver { + fn accept(&self, visitor: &mut T); +} + +impl Driver for Recall { + fn accept(&self, visitor: &mut T) { + visitor.visit_recall(self); + } +} + +impl Driver for Select { + fn accept(&self, visitor: &mut T) { + self.cond.accept(visitor); + self.a.accept(visitor); + self.b.accept(visitor); + + visitor.visit_select(self); + } +} + +impl Driver for GetLocal { + fn accept(&self, visitor: &mut T) { + visitor.visit_get_local(self); + } +} + +impl Driver for GetGlobal { + fn accept(&self, visitor: &mut T) { + visitor.visit_get_global(self); + } +} + +impl Driver for AnyLoad { + fn accept(&self, visitor: &mut T) { + self.pointer.accept(visitor); + + visitor.visit_any_load(self); + } +} + +impl Driver for MemorySize { + fn accept(&self, visitor: &mut T) { + visitor.visit_memory_size(self); + } +} + +impl Driver for MemoryGrow { + fn accept(&self, visitor: &mut T) { + self.value.accept(visitor); + + visitor.visit_memory_grow(self); + } +} + +impl Driver for Value { + fn accept(&self, visitor: &mut T) { + visitor.visit_value(self); + } +} + +impl Driver for AnyUnOp { + fn accept(&self, visitor: &mut T) { + self.rhs.accept(visitor); + + visitor.visit_any_unop(self); + } +} + +impl Driver for AnyBinOp { + fn accept(&self, visitor: &mut T) { + self.lhs.accept(visitor); + self.rhs.accept(visitor); + + visitor.visit_any_binop(self); + } +} + +impl Driver for Expression { + fn accept(&self, visitor: &mut T) { + match self { + Expression::Recall(v) => v.accept(visitor), + 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), + } + + visitor.visit_expression(self); + } +} + +impl Driver for Memorize { + fn accept(&self, visitor: &mut T) { + self.value.accept(visitor); + + visitor.visit_memorize(self); + } +} + +impl Driver for Forward { + fn accept(&self, visitor: &mut T) { + for v in &self.body { + v.accept(visitor); + } + + visitor.visit_forward(self); + } +} + +impl Driver for Backward { + fn accept(&self, visitor: &mut T) { + for v in &self.body { + v.accept(visitor); + } + + visitor.visit_backward(self); + } +} + +impl Driver for Else { + fn accept(&self, visitor: &mut T) { + for v in &self.body { + v.accept(visitor); + } + + visitor.visit_else(self); + } +} + +impl Driver for If { + fn accept(&self, visitor: &mut T) { + self.cond.accept(visitor); + + for v in &self.truthy { + v.accept(visitor); + } + + if let Some(v) = &self.falsey { + v.accept(visitor); + } + + visitor.visit_if(self); + } +} + +impl Driver for Br { + fn accept(&self, visitor: &mut T) { + visitor.visit_br(self); + } +} + +impl Driver for BrIf { + fn accept(&self, visitor: &mut T) { + self.cond.accept(visitor); + + visitor.visit_br_if(self); + } +} + +impl Driver for BrTable { + fn accept(&self, visitor: &mut T) { + self.cond.accept(visitor); + + visitor.visit_br_table(self); + } +} + +impl Driver for Return { + fn accept(&self, visitor: &mut T) { + for v in &self.list { + v.accept(visitor); + } + + visitor.visit_return(self); + } +} + +impl Driver for Call { + fn accept(&self, visitor: &mut T) { + for v in &self.param_list { + v.accept(visitor); + } + + visitor.visit_call(self); + } +} + +impl Driver for CallIndirect { + fn accept(&self, visitor: &mut T) { + self.index.accept(visitor); + + for v in &self.param_list { + v.accept(visitor); + } + + visitor.visit_call_indirect(self); + } +} + +impl Driver for SetLocal { + fn accept(&self, visitor: &mut T) { + self.value.accept(visitor); + + visitor.visit_set_local(self); + } +} + +impl Driver for SetGlobal { + fn accept(&self, visitor: &mut T) { + self.value.accept(visitor); + + visitor.visit_set_global(self); + } +} + +impl Driver for AnyStore { + fn accept(&self, visitor: &mut T) { + self.pointer.accept(visitor); + self.value.accept(visitor); + + visitor.visit_any_store(self); + } +} + +impl Driver for Statement { + fn accept(&self, visitor: &mut T) { + 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), + } + } +} + +impl Driver for Function { + fn accept(&self, visitor: &mut T) { + self.body.accept(visitor); + } +} diff --git a/wasm/src/backend/ast/transformer.rs b/wasm/src/ast/builder.rs similarity index 80% rename from wasm/src/backend/ast/transformer.rs rename to wasm/src/ast/builder.rs index 9687e4f..1980d39 100644 --- a/wasm/src/backend/ast/transformer.rs +++ b/wasm/src/ast/builder.rs @@ -1,24 +1,106 @@ -use parity_wasm::elements::{BlockType, 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}, - }, +use parity_wasm::elements::{ + BlockType, External, FunctionType, ImportEntry, Instruction, Local, Module, Type, }; -pub struct Transformer<'a> { +use super::{ + node::{ + AnyBinOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, CallIndirect, + Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize, MemoryGrow, + MemorySize, Recall, Return, Select, SetGlobal, SetLocal, Statement, Value, + }, + tag::{BinOp, Load, Store, UnOp}, +}; + +struct Arity { + num_param: u32, + 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, + } + } + + fn from_index(types: &[Type], index: u32) -> Self { + let Type::Function(typ) = &types[index as usize]; + + Self::from_type(typ) + } + + 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_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| Self::from_index(types, i.type_ref())) + .collect() + } + + fn new_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() + } +} + +pub struct Arities { + ex_arity: Vec, + in_arity: Vec, +} + +impl Arities { + pub fn new(parent: &Module) -> Self { + Self { + ex_arity: Arity::new_ex_list(parent), + in_arity: Arity::new_in_list(parent), + } + } + + pub fn len_in(&self) -> usize { + self.in_arity.len() + } + + pub fn len_ex(&self) -> usize { + self.ex_arity.len() + } + + 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() + } +} + +pub struct Builder<'a> { // target state wasm: &'a Module, - other: &'a ArityList, + other: &'a Arities, num_result: u32, // translation state @@ -42,9 +124,9 @@ fn is_dead_precursor(inst: &Instruction) -> bool { ) } -impl<'a> Transformer<'a> { - pub fn new(wasm: &'a Module, other: &'a ArityList) -> Transformer<'a> { - Transformer { +impl<'a> Builder<'a> { + pub fn new(wasm: &'a Module, other: &'a Arities) -> Builder<'a> { + Builder { wasm, other, num_result: 0, @@ -79,9 +161,9 @@ impl<'a> Transformer<'a> { fn push_recall(&mut self, num: u32) { let len = self.stack.len(); - (len..len + num as usize) - .map(Expression::Recall) - .for_each(|v| self.stack.push(v)); + for var in len..len + num as usize { + self.stack.push(Expression::Recall(Recall { var })); + } } fn push_block_result(&mut self, typ: BlockType) { @@ -109,7 +191,7 @@ impl<'a> Transformer<'a> { .enumerate() .filter(|v| !v.1.is_recalling(v.0)) { - let new = Expression::Recall(i); + let new = Expression::Recall(Recall { var: i }); let mem = Memorize { var: i, value: std::mem::replace(v, new), @@ -218,7 +300,7 @@ impl<'a> Transformer<'a> { .push(Expression::AnyBinOp(AnyBinOp { op, lhs, rhs })); } - fn drop_unreachable(&mut self, list: &mut &[Instruction]) { + fn drop_unreachable(list: &mut &[Instruction]) { use Instruction as Inst; let mut level = 1; @@ -421,7 +503,7 @@ impl<'a> Transformer<'a> { } if is_dead_precursor(inst) { - self.drop_unreachable(list); + Self::drop_unreachable(list); break; } @@ -440,12 +522,18 @@ impl<'a> Transformer<'a> { body } + fn new_else(&mut self, list: &mut &[Instruction]) -> Else { + Else { + body: self.new_stored_body(list), + } + } + fn new_if(&mut self, cond: Expression, list: &mut &[Instruction]) -> If { let copied = <&[Instruction]>::clone(list); let truthy = self.new_stored_body(list); let end = copied.len() - list.len() - 1; - let falsey = is_else_stat(&copied[end]).then(|| self.new_stored_body(list)); + let falsey = is_else_stat(&copied[end]).then(|| self.new_else(list)); If { cond, diff --git a/wasm/src/ast/mod.rs b/wasm/src/ast/mod.rs new file mode 100644 index 0000000..055c273 --- /dev/null +++ b/wasm/src/ast/mod.rs @@ -0,0 +1,3 @@ +pub mod builder; +pub mod node; +mod tag; diff --git a/wasm/src/ast/node.rs b/wasm/src/ast/node.rs new file mode 100644 index 0000000..7b7927d --- /dev/null +++ b/wasm/src/ast/node.rs @@ -0,0 +1,184 @@ +use std::ops::Range; + +use parity_wasm::elements::BrTableData; + +use super::tag::{BinOp, Load, Store, UnOp}; + +#[derive(Clone)] +pub struct Recall { + pub var: usize, +} + +#[derive(Clone)] +pub struct Select { + pub cond: Box, + pub a: Box, + pub b: Box, +} + +#[derive(Clone)] +pub struct GetLocal { + pub var: u32, +} + +#[derive(Clone)] +pub struct GetGlobal { + pub var: u32, +} + +#[derive(Clone)] +pub struct AnyLoad { + pub op: Load, + pub offset: u32, + pub pointer: Box, +} + +#[derive(Clone)] +pub struct MemorySize { + pub memory: u8, +} + +#[derive(Clone)] +pub struct MemoryGrow { + pub memory: u8, + pub value: Box, +} + +#[derive(Clone, Copy)] +pub enum Value { + I32(i32), + I64(i64), + F32(f32), + F64(f64), +} + +#[derive(Clone)] +pub struct AnyUnOp { + pub op: UnOp, + pub rhs: Box, +} + +#[derive(Clone)] +pub struct AnyBinOp { + pub op: BinOp, + pub lhs: Box, + pub rhs: Box, +} + +#[derive(Clone)] +pub enum Expression { + Recall(Recall), + Select(Select), + GetLocal(GetLocal), + GetGlobal(GetGlobal), + AnyLoad(AnyLoad), + MemorySize(MemorySize), + MemoryGrow(MemoryGrow), + Value(Value), + AnyUnOp(AnyUnOp), + AnyBinOp(AnyBinOp), +} + +impl Expression { + pub fn is_recalling(&self, wanted: usize) -> bool { + match self { + Expression::Recall(v) => v.var == wanted, + _ => false, + } + } +} + +pub struct Memorize { + pub var: usize, + pub value: Expression, +} + +pub struct Forward { + pub body: Vec, +} + +pub struct Backward { + pub body: Vec, +} + +pub struct Else { + pub body: Vec, +} + +pub struct If { + pub cond: Expression, + pub truthy: Vec, + pub falsey: Option, +} + +pub struct Br { + pub target: u32, +} + +pub struct BrIf { + pub cond: Expression, + pub target: u32, +} + +pub struct BrTable { + pub cond: Expression, + pub data: BrTableData, +} + +pub struct Return { + pub list: Vec, +} + +pub struct Call { + pub func: u32, + pub result: Range, + pub param_list: Vec, +} + +pub struct CallIndirect { + pub table: u8, + pub index: Expression, + pub result: Range, + pub param_list: Vec, +} + +pub struct SetLocal { + pub var: u32, + pub value: Expression, +} + +pub struct SetGlobal { + pub var: u32, + pub value: Expression, +} + +pub struct AnyStore { + pub op: Store, + pub offset: u32, + pub pointer: Expression, + pub value: Expression, +} + +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), +} + +pub struct Function { + pub num_param: u32, + pub num_local: u32, + pub num_stack: u32, + pub body: Forward, +} diff --git a/wasm/src/backend/ast/operation.rs b/wasm/src/ast/tag.rs similarity index 58% rename from wasm/src/backend/ast/operation.rs rename to wasm/src/ast/tag.rs index 5a86071..3120319 100644 --- a/wasm/src/backend/ast/operation.rs +++ b/wasm/src/ast/tag.rs @@ -46,21 +46,23 @@ impl TryFrom<&Instruction> for Load { type Error = (); fn try_from(inst: &Instruction) -> Result { + use Instruction as Inst; + let result = match inst { - Instruction::I32Load(_, _) => Self::I32, - Instruction::I64Load(_, _) => Self::I64, - Instruction::F32Load(_, _) => Self::F32, - Instruction::F64Load(_, _) => Self::F64, - Instruction::I32Load8S(_, _) => Self::I32_I8, - Instruction::I32Load8U(_, _) => Self::I32_U8, - Instruction::I32Load16S(_, _) => Self::I32_I16, - Instruction::I32Load16U(_, _) => Self::I32_U16, - Instruction::I64Load8S(_, _) => Self::I64_I8, - Instruction::I64Load8U(_, _) => Self::I64_U8, - Instruction::I64Load16S(_, _) => Self::I64_I16, - Instruction::I64Load16U(_, _) => Self::I64_U16, - Instruction::I64Load32S(_, _) => Self::I64_I32, - Instruction::I64Load32U(_, _) => Self::I64_U32, + 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, _ => return Err(()), }; @@ -102,16 +104,18 @@ impl TryFrom<&Instruction> for Store { type Error = (); fn try_from(inst: &Instruction) -> Result { + use Instruction as Inst; + let result = match inst { - Instruction::I32Store(_, _) => Self::I32, - Instruction::I64Store(_, _) => Self::I64, - Instruction::F32Store(_, _) => Self::F32, - Instruction::F64Store(_, _) => Self::F64, - Instruction::I32Store8(_, _) => Self::I32_N8, - Instruction::I32Store16(_, _) => Self::I32_N16, - Instruction::I64Store8(_, _) => Self::I64_N8, - Instruction::I64Store16(_, _) => Self::I64_N16, - Instruction::I64Store32(_, _) => Self::I64_N32, + 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, _ => return Err(()), }; @@ -234,54 +238,56 @@ impl TryFrom<&Instruction> for UnOp { type Error = (); fn try_from(inst: &Instruction) -> Result { + use Instruction as Inst; + let result = match inst { - Instruction::SignExt(ext) => match ext { + 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, }, - 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, - Instruction::I64Clz => Self::Clz_I64, - 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, - Instruction::F32Nearest | Instruction::F64Nearest => Self::Nearest_FN, - Instruction::F32Sqrt | Instruction::F64Sqrt => Self::Sqrt_FN, - Instruction::I32WrapI64 => Self::Wrap_I32_I64, - Instruction::I32TruncSF32 => Self::Trunc_I32_F32, - Instruction::I32TruncUF32 => Self::Trunc_U32_F32, - Instruction::I32TruncSF64 => Self::Trunc_I32_F64, - Instruction::I32TruncUF64 => Self::Trunc_U32_F64, - Instruction::I64ExtendSI32 => Self::Extend_I64_I32, - Instruction::I64ExtendUI32 => Self::Extend_U64_I32, - Instruction::I64TruncSF32 => Self::Trunc_I64_F32, - Instruction::I64TruncUF32 => Self::Trunc_U64_F32, - Instruction::I64TruncSF64 => Self::Trunc_I64_F64, - Instruction::I64TruncUF64 => Self::Trunc_U64_F64, - Instruction::F32ConvertSI32 => Self::Convert_F32_I32, - Instruction::F32ConvertUI32 => Self::Convert_F32_U32, - Instruction::F32ConvertSI64 => Self::Convert_F32_I64, - Instruction::F32ConvertUI64 => Self::Convert_F32_U64, - Instruction::F32DemoteF64 => Self::Demote_F32_F64, - Instruction::F64ConvertSI32 => Self::Convert_F64_I32, - Instruction::F64ConvertUI32 => Self::Convert_F64_U32, - Instruction::F64ConvertSI64 => Self::Convert_F64_I64, - Instruction::F64ConvertUI64 => Self::Convert_F64_U64, - Instruction::F64PromoteF32 => Self::Promote_F64_F32, - Instruction::I32ReinterpretF32 => Self::Reinterpret_I32_F32, - Instruction::I64ReinterpretF64 => Self::Reinterpret_I64_F64, - Instruction::F32ReinterpretI32 => Self::Reinterpret_F32_I32, - Instruction::F64ReinterpretI64 => Self::Reinterpret_F64_I64, + Inst::I32Eqz => Self::Eqz_I32, + Inst::I64Eqz => Self::Eqz_I64, + 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, _ => return Err(()), }; @@ -444,70 +450,72 @@ impl TryFrom<&Instruction> for BinOp { type Error = (); fn try_from(inst: &Instruction) -> Result { + use Instruction as Inst; + 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, - Instruction::I32RemU => Self::RemU_I32, - Instruction::I32And => Self::And_I32, - Instruction::I32Or => Self::Or_I32, - Instruction::I32Xor => Self::Xor_I32, - Instruction::I32Shl => Self::Shl_I32, - Instruction::I32ShrS => Self::ShrS_I32, - 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, - Instruction::I64RemU => Self::RemU_I64, - Instruction::I64And => Self::And_I64, - Instruction::I64Or => Self::Or_I64, - Instruction::I64Xor => Self::Xor_I64, - Instruction::I64Shl => Self::Shl_I64, - Instruction::I64ShrS => Self::ShrS_I64, - 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, - Instruction::F32Copysign | Instruction::F64Copysign => Self::Copysign_FN, + 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::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::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, + 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, _ => { return Err(()); } diff --git a/wasm/src/backend/ast/data.rs b/wasm/src/backend/ast/data.rs deleted file mode 100644 index 70f5fd8..0000000 --- a/wasm/src/backend/ast/data.rs +++ /dev/null @@ -1,413 +0,0 @@ -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 truthy: Vec, - pub falsey: Option>, -} - -impl If { - fn accept(&self, visitor: &mut V) { - visitor.visit_if(self); - - self.cond.accept(visitor); - - for v in &self.truthy { - v.accept(visitor); - } - - if let Some(v) = &self.falsey { - 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: Forward, -} - -impl Function { - pub fn accept(&self, visitor: &mut V) { - self.body.accept(visitor); - } -} diff --git a/wasm/src/backend/ast/mod.rs b/wasm/src/backend/ast/mod.rs deleted file mode 100644 index 7b61030..0000000 --- a/wasm/src/backend/ast/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod data; -mod operation; -pub mod transformer; diff --git a/wasm/src/backend/edition/data.rs b/wasm/src/backend/edition/data.rs deleted file mode 100644 index 51b5cee..0000000 --- a/wasm/src/backend/edition/data.rs +++ /dev/null @@ -1,51 +0,0 @@ -use std::{ - fmt::Display, - io::{Result, Write}, -}; - -use super::{luajit::LuaJIT, luau::Luau}; - -pub struct Infix { - rhs: &'static str, - inner: T, -} - -impl Infix { - pub fn new(rhs: &'static str, inner: T) -> Self { - Infix { rhs, inner } - } -} - -impl Display for Infix -where - T: Display, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.inner.fmt(f)?; - self.rhs.fmt(f) - } -} - -pub trait Edition { - fn runtime(&self) -> &'static str; - - 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: &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; -} - -pub fn from_string(name: &str) -> Option<&'static dyn Edition> { - match name.to_ascii_lowercase().as_str() { - "luau" => Some(&Luau), - "luajit" => Some(&LuaJIT), - _ => None, - } -} diff --git a/wasm/src/backend/edition/luajit.rs b/wasm/src/backend/edition/luajit.rs deleted file mode 100644 index 36e0016..0000000 --- a/wasm/src/backend/edition/luajit.rs +++ /dev/null @@ -1,56 +0,0 @@ -use std::io::{Result, Write}; - -use super::data::{Edition, Infix}; - -pub struct LuaJIT; - -impl Edition for LuaJIT { - fn runtime(&self) -> &'static str { - "'luajit'" - } - - fn start_block(&self, w: &mut dyn Write) -> Result<()> { - write!(w, "do ") - } - - 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: &mut dyn Write) -> Result<()> { - write!(w, "if {} ~= 0 then ", cond) - } - - fn end_block(&self, level: usize, w: &mut dyn Write) -> Result<()> { - write!(w, "::continue_at_{}::", level)?; - write!(w, "end ") - } - - fn end_loop(&self, w: &mut dyn Write) -> Result<()> { - write!(w, "end ") - } - - 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: &mut dyn Write) -> Result<()> { - Ok(()) - } - - fn br_to_level( - &self, - level: usize, - up: usize, - _is_loop: bool, - w: &mut dyn Write, - ) -> Result<()> { - write!(w, "goto continue_at_{} ", level - up) - } - - fn i64(&self, i: i64) -> Infix { - Infix::new("LL", i) - } -} diff --git a/wasm/src/backend/edition/luau.rs b/wasm/src/backend/edition/luau.rs deleted file mode 100644 index 00b4adc..0000000 --- a/wasm/src/backend/edition/luau.rs +++ /dev/null @@ -1,75 +0,0 @@ -use std::io::{Result, Write}; - -use super::data::{Edition, Infix}; - -pub struct Luau; - -impl Edition for Luau { - fn runtime(&self) -> &'static str { - "script.Runtime" - } - - fn start_block(&self, w: &mut dyn Write) -> Result<()> { - write!(w, "while true do ") - } - - fn start_loop(&self, _level: usize, w: &mut dyn Write) -> Result<()> { - write!(w, "while true do ") - } - - 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: &mut dyn Write) -> Result<()> { - write!(w, "break ")?; - write!(w, "end ") - } - - fn end_loop(&self, w: &mut dyn Write) -> Result<()> { - write!(w, "break ")?; - write!(w, "end ") - } - - 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: &mut dyn Write) -> Result<()> { - write!(w, "if desired then ")?; - write!(w, "if desired == {} then ", level)?; - write!(w, "desired = nil ")?; - - if in_loop { - write!(w, "continue ")?; - } - - write!(w, "end ")?; - write!(w, "break ")?; - write!(w, "end ") - } - - fn br_to_level(&self, level: usize, up: usize, is_loop: bool, w: &mut dyn Write) -> Result<()> { - write!(w, "do ")?; - - if up == 0 { - if is_loop { - write!(w, "continue ")?; - } else { - write!(w, "break ")?; - } - } else { - write!(w, "desired = {} ", level - up)?; - write!(w, "break ")?; - } - - write!(w, "end ") - } - - fn i64(&self, i: i64) -> Infix { - Infix::new("", i) - } -} diff --git a/wasm/src/backend/mod.rs b/wasm/src/backend/mod.rs deleted file mode 100644 index 89340ed..0000000 --- a/wasm/src/backend/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod ast; -pub mod edition; -pub mod translator; -mod visitor; diff --git a/wasm/src/backend/translator/arity.rs b/wasm/src/backend/translator/arity.rs deleted file mode 100755 index b93e335..0000000 --- a/wasm/src/backend/translator/arity.rs +++ /dev/null @@ -1,81 +0,0 @@ -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/wasm/src/backend/translator/data.rs b/wasm/src/backend/translator/data.rs deleted file mode 100644 index 72bb380..0000000 --- a/wasm/src/backend/translator/data.rs +++ /dev/null @@ -1,311 +0,0 @@ -use std::{ - collections::BTreeSet, - io::{Result, Write}, -}; - -use parity_wasm::elements::{ - External, ImportCountType, Instruction, Internal, Module as WasmModule, ResizableLimits, -}; - -use crate::backend::{ - ast::{data::Function, transformer::Transformer}, - edition::data::Edition, - visitor::localize, -}; - -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 new_limit_max(limits: &ResizableLimits) -> String { - match limits.maximum() { - Some(v) => v.to_string(), - None => "math.huge".to_string(), - } -} - -fn gen_table_init(limit: &ResizableLimits, w: &mut dyn Write) -> Result<()> { - let a = limit.initial(); - let b = new_limit_max(limit); - - write!(w, "{{ min = {}, max = {}, data = {{}} }}", a, b) -} - -fn gen_memory_init(limit: &ResizableLimits, w: &mut dyn Write) -> Result<()> { - let a = limit.initial(); - let b = new_limit_max(limit); - - write!(w, "rt.memory.new({}, {})", a, b) -} - -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<()> { - // FIXME: Badly generated WASM will produce the wrong constant. - for inst in code { - let result = 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), - _ => { - continue; - } - }; - - return result; - } - - write!(w, "error(\"mundane expression\")") -} - -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)?; - - write!(w, "local data = {{")?; - - v.members() - .iter() - .try_for_each(|v| write!(w, "FUNC_LIST[{}],", v))?; - - write!(w, "}}")?; - - write!(w, "table.move(data, 1, #data, offset, target)")?; - - 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 ") - } - - fn gen_localize(func_list: &[Function], w: &mut dyn Write) -> Result<()> { - let mut loc_set = BTreeSet::new(); - - for func in func_list { - loc_set.extend(localize::visit(func)); - } - - loc_set - .into_iter() - .try_for_each(|(a, b)| write!(w, "local {0}_{1} = rt.{0}.{1} ", a, b)) - } - - pub fn translate(&self, ed: &dyn Edition, w: &mut dyn Write) -> Result<()> { - write!(w, "local rt = require({})", ed.runtime())?; - - let func_list: Vec<_> = (0..self.arity.in_arity.len()) - .map(|i| Transformer::new(self.wasm, &self.arity).consume(i)) - .collect(); - - Self::gen_localize(&func_list, w)?; - - 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, v) in func_list.into_iter().enumerate() { - write!(w, "FUNC_LIST[{}] =", i + offset)?; - - v.output(&mut Data::new(ed), w)?; - } - - self.gen_start_point(w) - } -} diff --git a/wasm/src/backend/translator/mod.rs b/wasm/src/backend/translator/mod.rs deleted file mode 100644 index 297d79a..0000000 --- a/wasm/src/backend/translator/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod arity; -pub mod data; -pub mod writer; diff --git a/wasm/src/backend/translator/writer.rs b/wasm/src/backend/translator/writer.rs deleted file mode 100644 index 6996233..0000000 --- a/wasm/src/backend/translator/writer.rs +++ /dev/null @@ -1,505 +0,0 @@ -use std::{ - io::{Result, Write}, - ops::Range, -}; - -use crate::backend::{ - ast::data::{ - AnyBinOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, CallIndirect, - Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize, MemoryGrow, MemorySize, - Return, Select, SetGlobal, SetLocal, Statement, Value, - }, - edition::data::Edition, - visitor::memory, -}; - -fn write_in_order(prefix: &'static str, len: u32, w: &mut dyn Write) -> Result<()> { - if len == 0 { - return Ok(()); - } - - write!(w, "{}_{}", prefix, 0)?; - (1..len).try_for_each(|i| write!(w, ", {}_{}", prefix, i)) -} - -fn write_br_gadget(rem: usize, d: &mut Data, w: &mut dyn Write) -> Result<()> { - match d.label_list.last() { - Some(Label::Forward | Label::If) => d.edition.br_target(rem, false, w), - Some(Label::Backward) => d.edition.br_target(rem, true, w), - None => Ok(()), - } -} - -pub fn condense_jump_table(list: &[u32]) -> Vec<(usize, usize, 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 - 1, list[start])); - } - - result -} - -#[derive(PartialEq, Eq)] -enum Label { - Forward, - Backward, - If, -} - -pub struct Data<'a> { - label_list: Vec