Refactor the codebase and organize files

This commit is contained in:
Rerumu 2021-11-30 03:27:17 -05:00
parent 82e97ad643
commit 96a27c9626
29 changed files with 2370 additions and 1771 deletions

View File

@ -1,30 +1,19 @@
#![no_main] #![no_main]
use std::io::Result; use wasm_smith::Module;
use parity_wasm::elements::Module as WasmModule; use wasm::writer::{luajit::LuaJIT, visit::Transpiler};
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)
}
// We are not interested in parity_wasm errors. // We are not interested in parity_wasm errors.
// Only 1 edition should need to be tested too. // 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 data = module.to_bytes();
let wasm = match parity_wasm::deserialize_buffer(&data) { let wasm = match parity_wasm::deserialize_buffer(&data) {
Ok(v) => v, Ok(v) => v,
Err(_) => return, Err(_) => return,
}; };
fuzz_translate(&wasm, &LuaJIT).expect("LuaJIT should succeed"); LuaJIT::new(&wasm)
.transpile(&mut std::io::sink())
.expect("LuaJIT should succeed");
}); });

View File

@ -3,14 +3,11 @@
use parity_wasm::elements::Module as WasmModule; use parity_wasm::elements::Module as WasmModule;
use wasm_smith::Module as SmModule; 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) { fn fuzz_transformer(wasm: &WasmModule) {
let arity = List::new(wasm); let trans = LuaJIT::new(wasm);
let _func = trans.build_func_list();
for i in 0..arity.in_arity.len() {
let _ = Transformer::new(wasm, &arity).consume(i);
}
} }
libfuzzer_sys::fuzz_target!(|module: SmModule| { libfuzzer_sys::fuzz_target!(|module: SmModule| {

View File

@ -5,23 +5,13 @@ use std::io::Result;
use parity_wasm::elements::Module as WasmModule; use parity_wasm::elements::Module as WasmModule;
use wasm_smith::Module as SmModule; use wasm_smith::Module as SmModule;
use wasm::backend::{ use wasm::writer::{luajit::LuaJIT, visit::Transpiler};
ast::transformer::Transformer,
edition::{data::Edition, luajit::LuaJIT},
translator::{arity::List, writer::Data},
};
fn fuzz_writer(wasm: &WasmModule, ed: &dyn Edition) -> Result<()> { fn fuzz_writer(wasm: &WasmModule) -> Result<()> {
let mut sink = std::io::sink(); let trans = LuaJIT::new(wasm);
let arity = List::new(wasm); let list = trans.build_func_list();
for i in 0..arity.in_arity.len() { trans.gen_func_list(&list, &mut std::io::sink())
let func = Transformer::new(wasm, &arity).consume(i);
func.output(&mut Data::new(ed), &mut sink)?;
}
Ok(())
} }
libfuzzer_sys::fuzz_target!(|module: SmModule| { libfuzzer_sys::fuzz_target!(|module: SmModule| {
@ -31,5 +21,5 @@ libfuzzer_sys::fuzz_target!(|module: SmModule| {
Err(_) => return, Err(_) => return,
}; };
fuzz_writer(&wasm, &LuaJIT).expect("LuaJIT should succeed"); fuzz_writer(&wasm).expect("LuaJIT should succeed");
}); });

View File

@ -1,8 +1,8 @@
use std::collections::BTreeSet; 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 { struct Visit {
result: BTreeSet<(&'static str, &'static str)>, result: BTreeSet<(&'static str, &'static str)>,

View File

@ -1,8 +1,8 @@
use std::collections::BTreeSet; 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 { struct Visit {
result: BTreeSet<u8>, result: BTreeSet<u8>,

View File

@ -1,3 +1,3 @@
pub mod data;
pub mod localize; pub mod localize;
pub mod memory; pub mod memory;
mod visit;

317
wasm/src/analyzer/visit.rs Normal file
View File

@ -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<T: Visitor> {
fn accept(&self, visitor: &mut T);
}
impl<T: Visitor> Driver<T> for Recall {
fn accept(&self, visitor: &mut T) {
visitor.visit_recall(self);
}
}
impl<T: Visitor> Driver<T> 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<T: Visitor> Driver<T> for GetLocal {
fn accept(&self, visitor: &mut T) {
visitor.visit_get_local(self);
}
}
impl<T: Visitor> Driver<T> for GetGlobal {
fn accept(&self, visitor: &mut T) {
visitor.visit_get_global(self);
}
}
impl<T: Visitor> Driver<T> for AnyLoad {
fn accept(&self, visitor: &mut T) {
self.pointer.accept(visitor);
visitor.visit_any_load(self);
}
}
impl<T: Visitor> Driver<T> for MemorySize {
fn accept(&self, visitor: &mut T) {
visitor.visit_memory_size(self);
}
}
impl<T: Visitor> Driver<T> for MemoryGrow {
fn accept(&self, visitor: &mut T) {
self.value.accept(visitor);
visitor.visit_memory_grow(self);
}
}
impl<T: Visitor> Driver<T> for Value {
fn accept(&self, visitor: &mut T) {
visitor.visit_value(self);
}
}
impl<T: Visitor> Driver<T> for AnyUnOp {
fn accept(&self, visitor: &mut T) {
self.rhs.accept(visitor);
visitor.visit_any_unop(self);
}
}
impl<T: Visitor> Driver<T> for AnyBinOp {
fn accept(&self, visitor: &mut T) {
self.lhs.accept(visitor);
self.rhs.accept(visitor);
visitor.visit_any_binop(self);
}
}
impl<T: Visitor> Driver<T> 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<T: Visitor> Driver<T> for Memorize {
fn accept(&self, visitor: &mut T) {
self.value.accept(visitor);
visitor.visit_memorize(self);
}
}
impl<T: Visitor> Driver<T> for Forward {
fn accept(&self, visitor: &mut T) {
for v in &self.body {
v.accept(visitor);
}
visitor.visit_forward(self);
}
}
impl<T: Visitor> Driver<T> for Backward {
fn accept(&self, visitor: &mut T) {
for v in &self.body {
v.accept(visitor);
}
visitor.visit_backward(self);
}
}
impl<T: Visitor> Driver<T> for Else {
fn accept(&self, visitor: &mut T) {
for v in &self.body {
v.accept(visitor);
}
visitor.visit_else(self);
}
}
impl<T: Visitor> Driver<T> 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<T: Visitor> Driver<T> for Br {
fn accept(&self, visitor: &mut T) {
visitor.visit_br(self);
}
}
impl<T: Visitor> Driver<T> for BrIf {
fn accept(&self, visitor: &mut T) {
self.cond.accept(visitor);
visitor.visit_br_if(self);
}
}
impl<T: Visitor> Driver<T> for BrTable {
fn accept(&self, visitor: &mut T) {
self.cond.accept(visitor);
visitor.visit_br_table(self);
}
}
impl<T: Visitor> Driver<T> for Return {
fn accept(&self, visitor: &mut T) {
for v in &self.list {
v.accept(visitor);
}
visitor.visit_return(self);
}
}
impl<T: Visitor> Driver<T> for Call {
fn accept(&self, visitor: &mut T) {
for v in &self.param_list {
v.accept(visitor);
}
visitor.visit_call(self);
}
}
impl<T: Visitor> Driver<T> 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<T: Visitor> Driver<T> for SetLocal {
fn accept(&self, visitor: &mut T) {
self.value.accept(visitor);
visitor.visit_set_local(self);
}
}
impl<T: Visitor> Driver<T> for SetGlobal {
fn accept(&self, visitor: &mut T) {
self.value.accept(visitor);
visitor.visit_set_global(self);
}
}
impl<T: Visitor> Driver<T> for AnyStore {
fn accept(&self, visitor: &mut T) {
self.pointer.accept(visitor);
self.value.accept(visitor);
visitor.visit_any_store(self);
}
}
impl<T: Visitor> Driver<T> 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<T: Visitor> Driver<T> for Function {
fn accept(&self, visitor: &mut T) {
self.body.accept(visitor);
}
}

View File

@ -1,24 +1,106 @@
use parity_wasm::elements::{BlockType, Instruction, Local, Module}; use parity_wasm::elements::{
BlockType, External, FunctionType, ImportEntry, Instruction, Local, Module, Type,
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> { 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<Arity> {
if let External::Function(i) = import.external() {
Some(Arity::from_index(types, *i))
} else {
None
}
}
fn new_in_list(wasm: &Module) -> Vec<Self> {
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<Self> {
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<Arity>,
in_arity: Vec<Arity>,
}
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 // target state
wasm: &'a Module, wasm: &'a Module,
other: &'a ArityList, other: &'a Arities,
num_result: u32, num_result: u32,
// translation state // translation state
@ -42,9 +124,9 @@ fn is_dead_precursor(inst: &Instruction) -> bool {
) )
} }
impl<'a> Transformer<'a> { impl<'a> Builder<'a> {
pub fn new(wasm: &'a Module, other: &'a ArityList) -> Transformer<'a> { pub fn new(wasm: &'a Module, other: &'a Arities) -> Builder<'a> {
Transformer { Builder {
wasm, wasm,
other, other,
num_result: 0, num_result: 0,
@ -79,9 +161,9 @@ impl<'a> Transformer<'a> {
fn push_recall(&mut self, num: u32) { fn push_recall(&mut self, num: u32) {
let len = self.stack.len(); let len = self.stack.len();
(len..len + num as usize) for var in len..len + num as usize {
.map(Expression::Recall) self.stack.push(Expression::Recall(Recall { var }));
.for_each(|v| self.stack.push(v)); }
} }
fn push_block_result(&mut self, typ: BlockType) { fn push_block_result(&mut self, typ: BlockType) {
@ -109,7 +191,7 @@ impl<'a> Transformer<'a> {
.enumerate() .enumerate()
.filter(|v| !v.1.is_recalling(v.0)) .filter(|v| !v.1.is_recalling(v.0))
{ {
let new = Expression::Recall(i); let new = Expression::Recall(Recall { var: i });
let mem = Memorize { let mem = Memorize {
var: i, var: i,
value: std::mem::replace(v, new), value: std::mem::replace(v, new),
@ -218,7 +300,7 @@ impl<'a> Transformer<'a> {
.push(Expression::AnyBinOp(AnyBinOp { op, lhs, rhs })); .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; use Instruction as Inst;
let mut level = 1; let mut level = 1;
@ -421,7 +503,7 @@ impl<'a> Transformer<'a> {
} }
if is_dead_precursor(inst) { if is_dead_precursor(inst) {
self.drop_unreachable(list); Self::drop_unreachable(list);
break; break;
} }
@ -440,12 +522,18 @@ impl<'a> Transformer<'a> {
body 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 { fn new_if(&mut self, cond: Expression, list: &mut &[Instruction]) -> If {
let copied = <&[Instruction]>::clone(list); let copied = <&[Instruction]>::clone(list);
let truthy = self.new_stored_body(list); let truthy = self.new_stored_body(list);
let end = copied.len() - list.len() - 1; 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 { If {
cond, cond,

3
wasm/src/ast/mod.rs Normal file
View File

@ -0,0 +1,3 @@
pub mod builder;
pub mod node;
mod tag;

184
wasm/src/ast/node.rs Normal file
View File

@ -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<Expression>,
pub a: Box<Expression>,
pub b: Box<Expression>,
}
#[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<Expression>,
}
#[derive(Clone)]
pub struct MemorySize {
pub memory: u8,
}
#[derive(Clone)]
pub struct MemoryGrow {
pub memory: u8,
pub value: Box<Expression>,
}
#[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<Expression>,
}
#[derive(Clone)]
pub struct AnyBinOp {
pub op: BinOp,
pub lhs: Box<Expression>,
pub rhs: Box<Expression>,
}
#[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<Statement>,
}
pub struct Backward {
pub body: Vec<Statement>,
}
pub struct Else {
pub body: Vec<Statement>,
}
pub struct If {
pub cond: Expression,
pub truthy: Vec<Statement>,
pub falsey: Option<Else>,
}
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<Expression>,
}
pub struct Call {
pub func: u32,
pub result: Range<u32>,
pub param_list: Vec<Expression>,
}
pub struct CallIndirect {
pub table: u8,
pub index: Expression,
pub result: Range<u32>,
pub param_list: Vec<Expression>,
}
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,
}

View File

@ -46,21 +46,23 @@ impl TryFrom<&Instruction> for Load {
type Error = (); type Error = ();
fn try_from(inst: &Instruction) -> Result<Self, Self::Error> { fn try_from(inst: &Instruction) -> Result<Self, Self::Error> {
use Instruction as Inst;
let result = match inst { let result = match inst {
Instruction::I32Load(_, _) => Self::I32, Inst::I32Load(_, _) => Self::I32,
Instruction::I64Load(_, _) => Self::I64, Inst::I64Load(_, _) => Self::I64,
Instruction::F32Load(_, _) => Self::F32, Inst::F32Load(_, _) => Self::F32,
Instruction::F64Load(_, _) => Self::F64, Inst::F64Load(_, _) => Self::F64,
Instruction::I32Load8S(_, _) => Self::I32_I8, Inst::I32Load8S(_, _) => Self::I32_I8,
Instruction::I32Load8U(_, _) => Self::I32_U8, Inst::I32Load8U(_, _) => Self::I32_U8,
Instruction::I32Load16S(_, _) => Self::I32_I16, Inst::I32Load16S(_, _) => Self::I32_I16,
Instruction::I32Load16U(_, _) => Self::I32_U16, Inst::I32Load16U(_, _) => Self::I32_U16,
Instruction::I64Load8S(_, _) => Self::I64_I8, Inst::I64Load8S(_, _) => Self::I64_I8,
Instruction::I64Load8U(_, _) => Self::I64_U8, Inst::I64Load8U(_, _) => Self::I64_U8,
Instruction::I64Load16S(_, _) => Self::I64_I16, Inst::I64Load16S(_, _) => Self::I64_I16,
Instruction::I64Load16U(_, _) => Self::I64_U16, Inst::I64Load16U(_, _) => Self::I64_U16,
Instruction::I64Load32S(_, _) => Self::I64_I32, Inst::I64Load32S(_, _) => Self::I64_I32,
Instruction::I64Load32U(_, _) => Self::I64_U32, Inst::I64Load32U(_, _) => Self::I64_U32,
_ => return Err(()), _ => return Err(()),
}; };
@ -102,16 +104,18 @@ impl TryFrom<&Instruction> for Store {
type Error = (); type Error = ();
fn try_from(inst: &Instruction) -> Result<Self, Self::Error> { fn try_from(inst: &Instruction) -> Result<Self, Self::Error> {
use Instruction as Inst;
let result = match inst { let result = match inst {
Instruction::I32Store(_, _) => Self::I32, Inst::I32Store(_, _) => Self::I32,
Instruction::I64Store(_, _) => Self::I64, Inst::I64Store(_, _) => Self::I64,
Instruction::F32Store(_, _) => Self::F32, Inst::F32Store(_, _) => Self::F32,
Instruction::F64Store(_, _) => Self::F64, Inst::F64Store(_, _) => Self::F64,
Instruction::I32Store8(_, _) => Self::I32_N8, Inst::I32Store8(_, _) => Self::I32_N8,
Instruction::I32Store16(_, _) => Self::I32_N16, Inst::I32Store16(_, _) => Self::I32_N16,
Instruction::I64Store8(_, _) => Self::I64_N8, Inst::I64Store8(_, _) => Self::I64_N8,
Instruction::I64Store16(_, _) => Self::I64_N16, Inst::I64Store16(_, _) => Self::I64_N16,
Instruction::I64Store32(_, _) => Self::I64_N32, Inst::I64Store32(_, _) => Self::I64_N32,
_ => return Err(()), _ => return Err(()),
}; };
@ -234,54 +238,56 @@ impl TryFrom<&Instruction> for UnOp {
type Error = (); type Error = ();
fn try_from(inst: &Instruction) -> Result<Self, Self::Error> { fn try_from(inst: &Instruction) -> Result<Self, Self::Error> {
use Instruction as Inst;
let result = match inst { let result = match inst {
Instruction::SignExt(ext) => match ext { Inst::SignExt(ext) => match ext {
SignExtInstruction::I32Extend8S => Self::Extend_I32_I8, SignExtInstruction::I32Extend8S => Self::Extend_I32_I8,
SignExtInstruction::I32Extend16S => Self::Extend_I32_I16, SignExtInstruction::I32Extend16S => Self::Extend_I32_I16,
SignExtInstruction::I64Extend8S => Self::Extend_I64_I8, SignExtInstruction::I64Extend8S => Self::Extend_I64_I8,
SignExtInstruction::I64Extend16S => Self::Extend_I64_I16, SignExtInstruction::I64Extend16S => Self::Extend_I64_I16,
SignExtInstruction::I64Extend32S => Self::Extend_I64_I32, SignExtInstruction::I64Extend32S => Self::Extend_I64_I32,
}, },
Instruction::I32Eqz => Self::Eqz_I32, Inst::I32Eqz => Self::Eqz_I32,
Instruction::I64Eqz => Self::Eqz_I64, Inst::I64Eqz => Self::Eqz_I64,
Instruction::I32Clz => Self::Clz_I32, Inst::I32Clz => Self::Clz_I32,
Instruction::I32Ctz => Self::Ctz_I32, Inst::I32Ctz => Self::Ctz_I32,
Instruction::I32Popcnt => Self::Popcnt_I32, Inst::I32Popcnt => Self::Popcnt_I32,
Instruction::I64Clz => Self::Clz_I64, Inst::I64Clz => Self::Clz_I64,
Instruction::I64Ctz => Self::Ctz_I64, Inst::I64Ctz => Self::Ctz_I64,
Instruction::I64Popcnt => Self::Popcnt_I64, Inst::I64Popcnt => Self::Popcnt_I64,
Instruction::F32Abs | Instruction::F64Abs => Self::Abs_FN, Inst::F32Abs | Inst::F64Abs => Self::Abs_FN,
Instruction::F32Neg | Instruction::F64Neg => Self::Neg_FN, Inst::F32Neg | Inst::F64Neg => Self::Neg_FN,
Instruction::F32Ceil | Instruction::F64Ceil => Self::Ceil_FN, Inst::F32Ceil | Inst::F64Ceil => Self::Ceil_FN,
Instruction::F32Floor | Instruction::F64Floor => Self::Floor_FN, Inst::F32Floor | Inst::F64Floor => Self::Floor_FN,
Instruction::F32Trunc | Instruction::F64Trunc => Self::Trunc_FN, Inst::F32Trunc | Inst::F64Trunc => Self::Trunc_FN,
Instruction::F32Nearest | Instruction::F64Nearest => Self::Nearest_FN, Inst::F32Nearest | Inst::F64Nearest => Self::Nearest_FN,
Instruction::F32Sqrt | Instruction::F64Sqrt => Self::Sqrt_FN, Inst::F32Sqrt | Inst::F64Sqrt => Self::Sqrt_FN,
Instruction::I32WrapI64 => Self::Wrap_I32_I64, Inst::I32WrapI64 => Self::Wrap_I32_I64,
Instruction::I32TruncSF32 => Self::Trunc_I32_F32, Inst::I32TruncSF32 => Self::Trunc_I32_F32,
Instruction::I32TruncUF32 => Self::Trunc_U32_F32, Inst::I32TruncUF32 => Self::Trunc_U32_F32,
Instruction::I32TruncSF64 => Self::Trunc_I32_F64, Inst::I32TruncSF64 => Self::Trunc_I32_F64,
Instruction::I32TruncUF64 => Self::Trunc_U32_F64, Inst::I32TruncUF64 => Self::Trunc_U32_F64,
Instruction::I64ExtendSI32 => Self::Extend_I64_I32, Inst::I64ExtendSI32 => Self::Extend_I64_I32,
Instruction::I64ExtendUI32 => Self::Extend_U64_I32, Inst::I64ExtendUI32 => Self::Extend_U64_I32,
Instruction::I64TruncSF32 => Self::Trunc_I64_F32, Inst::I64TruncSF32 => Self::Trunc_I64_F32,
Instruction::I64TruncUF32 => Self::Trunc_U64_F32, Inst::I64TruncUF32 => Self::Trunc_U64_F32,
Instruction::I64TruncSF64 => Self::Trunc_I64_F64, Inst::I64TruncSF64 => Self::Trunc_I64_F64,
Instruction::I64TruncUF64 => Self::Trunc_U64_F64, Inst::I64TruncUF64 => Self::Trunc_U64_F64,
Instruction::F32ConvertSI32 => Self::Convert_F32_I32, Inst::F32ConvertSI32 => Self::Convert_F32_I32,
Instruction::F32ConvertUI32 => Self::Convert_F32_U32, Inst::F32ConvertUI32 => Self::Convert_F32_U32,
Instruction::F32ConvertSI64 => Self::Convert_F32_I64, Inst::F32ConvertSI64 => Self::Convert_F32_I64,
Instruction::F32ConvertUI64 => Self::Convert_F32_U64, Inst::F32ConvertUI64 => Self::Convert_F32_U64,
Instruction::F32DemoteF64 => Self::Demote_F32_F64, Inst::F32DemoteF64 => Self::Demote_F32_F64,
Instruction::F64ConvertSI32 => Self::Convert_F64_I32, Inst::F64ConvertSI32 => Self::Convert_F64_I32,
Instruction::F64ConvertUI32 => Self::Convert_F64_U32, Inst::F64ConvertUI32 => Self::Convert_F64_U32,
Instruction::F64ConvertSI64 => Self::Convert_F64_I64, Inst::F64ConvertSI64 => Self::Convert_F64_I64,
Instruction::F64ConvertUI64 => Self::Convert_F64_U64, Inst::F64ConvertUI64 => Self::Convert_F64_U64,
Instruction::F64PromoteF32 => Self::Promote_F64_F32, Inst::F64PromoteF32 => Self::Promote_F64_F32,
Instruction::I32ReinterpretF32 => Self::Reinterpret_I32_F32, Inst::I32ReinterpretF32 => Self::Reinterpret_I32_F32,
Instruction::I64ReinterpretF64 => Self::Reinterpret_I64_F64, Inst::I64ReinterpretF64 => Self::Reinterpret_I64_F64,
Instruction::F32ReinterpretI32 => Self::Reinterpret_F32_I32, Inst::F32ReinterpretI32 => Self::Reinterpret_F32_I32,
Instruction::F64ReinterpretI64 => Self::Reinterpret_F64_I64, Inst::F64ReinterpretI64 => Self::Reinterpret_F64_I64,
_ => return Err(()), _ => return Err(()),
}; };
@ -444,70 +450,72 @@ impl TryFrom<&Instruction> for BinOp {
type Error = (); type Error = ();
fn try_from(inst: &Instruction) -> Result<Self, Self::Error> { fn try_from(inst: &Instruction) -> Result<Self, Self::Error> {
use Instruction as Inst;
let result = match inst { let result = match inst {
Instruction::I32Eq => Self::Eq_I32, Inst::I32Eq => Self::Eq_I32,
Instruction::I32Ne => Self::Ne_I32, Inst::I32Ne => Self::Ne_I32,
Instruction::I32LtS => Self::LtS_I32, Inst::I32LtS => Self::LtS_I32,
Instruction::I32LtU => Self::LtU_I32, Inst::I32LtU => Self::LtU_I32,
Instruction::I32GtS => Self::GtS_I32, Inst::I32GtS => Self::GtS_I32,
Instruction::I32GtU => Self::GtU_I32, Inst::I32GtU => Self::GtU_I32,
Instruction::I32LeS => Self::LeS_I32, Inst::I32LeS => Self::LeS_I32,
Instruction::I32LeU => Self::LeU_I32, Inst::I32LeU => Self::LeU_I32,
Instruction::I32GeS => Self::GeS_I32, Inst::I32GeS => Self::GeS_I32,
Instruction::I32GeU => Self::GeU_I32, Inst::I32GeU => Self::GeU_I32,
Instruction::I64Eq => Self::Eq_I64, Inst::I64Eq => Self::Eq_I64,
Instruction::I64Ne => Self::Ne_I64, Inst::I64Ne => Self::Ne_I64,
Instruction::I64LtS => Self::LtS_I64, Inst::I64LtS => Self::LtS_I64,
Instruction::I64LtU => Self::LtU_I64, Inst::I64LtU => Self::LtU_I64,
Instruction::I64GtS => Self::GtS_I64, Inst::I64GtS => Self::GtS_I64,
Instruction::I64GtU => Self::GtU_I64, Inst::I64GtU => Self::GtU_I64,
Instruction::I64LeS => Self::LeS_I64, Inst::I64LeS => Self::LeS_I64,
Instruction::I64LeU => Self::LeU_I64, Inst::I64LeU => Self::LeU_I64,
Instruction::I64GeS => Self::GeS_I64, Inst::I64GeS => Self::GeS_I64,
Instruction::I64GeU => Self::GeU_I64, Inst::I64GeU => Self::GeU_I64,
Instruction::I32Add => Self::Add_I32, Inst::I32Add => Self::Add_I32,
Instruction::I32Sub => Self::Sub_I32, Inst::I32Sub => Self::Sub_I32,
Instruction::I32Mul => Self::Mul_I32, Inst::I32Mul => Self::Mul_I32,
Instruction::I32DivS => Self::DivS_I32, Inst::I32DivS => Self::DivS_I32,
Instruction::I32DivU => Self::DivU_I32, Inst::I32DivU => Self::DivU_I32,
Instruction::I32RemS => Self::RemS_I32, Inst::I32RemS => Self::RemS_I32,
Instruction::I32RemU => Self::RemU_I32, Inst::I32RemU => Self::RemU_I32,
Instruction::I32And => Self::And_I32, Inst::I32And => Self::And_I32,
Instruction::I32Or => Self::Or_I32, Inst::I32Or => Self::Or_I32,
Instruction::I32Xor => Self::Xor_I32, Inst::I32Xor => Self::Xor_I32,
Instruction::I32Shl => Self::Shl_I32, Inst::I32Shl => Self::Shl_I32,
Instruction::I32ShrS => Self::ShrS_I32, Inst::I32ShrS => Self::ShrS_I32,
Instruction::I32ShrU => Self::ShrU_I32, Inst::I32ShrU => Self::ShrU_I32,
Instruction::I32Rotl => Self::Rotl_I32, Inst::I32Rotl => Self::Rotl_I32,
Instruction::I32Rotr => Self::Rotr_I32, Inst::I32Rotr => Self::Rotr_I32,
Instruction::I64Add => Self::Add_I64, Inst::I64Add => Self::Add_I64,
Instruction::I64Sub => Self::Sub_I64, Inst::I64Sub => Self::Sub_I64,
Instruction::I64Mul => Self::Mul_I64, Inst::I64Mul => Self::Mul_I64,
Instruction::I64DivS => Self::DivS_I64, Inst::I64DivS => Self::DivS_I64,
Instruction::I64DivU => Self::DivU_I64, Inst::I64DivU => Self::DivU_I64,
Instruction::I64RemS => Self::RemS_I64, Inst::I64RemS => Self::RemS_I64,
Instruction::I64RemU => Self::RemU_I64, Inst::I64RemU => Self::RemU_I64,
Instruction::I64And => Self::And_I64, Inst::I64And => Self::And_I64,
Instruction::I64Or => Self::Or_I64, Inst::I64Or => Self::Or_I64,
Instruction::I64Xor => Self::Xor_I64, Inst::I64Xor => Self::Xor_I64,
Instruction::I64Shl => Self::Shl_I64, Inst::I64Shl => Self::Shl_I64,
Instruction::I64ShrS => Self::ShrS_I64, Inst::I64ShrS => Self::ShrS_I64,
Instruction::I64ShrU => Self::ShrU_I64, Inst::I64ShrU => Self::ShrU_I64,
Instruction::I64Rotl => Self::Rotl_I64, Inst::I64Rotl => Self::Rotl_I64,
Instruction::I64Rotr => Self::Rotr_I64, Inst::I64Rotr => Self::Rotr_I64,
Instruction::F32Eq | Instruction::F64Eq => Self::Eq_FN, Inst::F32Eq | Inst::F64Eq => Self::Eq_FN,
Instruction::F32Ne | Instruction::F64Ne => Self::Ne_FN, Inst::F32Ne | Inst::F64Ne => Self::Ne_FN,
Instruction::F32Lt | Instruction::F64Lt => Self::Lt_FN, Inst::F32Lt | Inst::F64Lt => Self::Lt_FN,
Instruction::F32Gt | Instruction::F64Gt => Self::Gt_FN, Inst::F32Gt | Inst::F64Gt => Self::Gt_FN,
Instruction::F32Le | Instruction::F64Le => Self::Le_FN, Inst::F32Le | Inst::F64Le => Self::Le_FN,
Instruction::F32Ge | Instruction::F64Ge => Self::Ge_FN, Inst::F32Ge | Inst::F64Ge => Self::Ge_FN,
Instruction::F32Add | Instruction::F64Add => Self::Add_FN, Inst::F32Add | Inst::F64Add => Self::Add_FN,
Instruction::F32Sub | Instruction::F64Sub => Self::Sub_FN, Inst::F32Sub | Inst::F64Sub => Self::Sub_FN,
Instruction::F32Mul | Instruction::F64Mul => Self::Mul_FN, Inst::F32Mul | Inst::F64Mul => Self::Mul_FN,
Instruction::F32Div | Instruction::F64Div => Self::Div_FN, Inst::F32Div | Inst::F64Div => Self::Div_FN,
Instruction::F32Min | Instruction::F64Min => Self::Min_FN, Inst::F32Min | Inst::F64Min => Self::Min_FN,
Instruction::F32Max | Instruction::F64Max => Self::Max_FN, Inst::F32Max | Inst::F64Max => Self::Max_FN,
Instruction::F32Copysign | Instruction::F64Copysign => Self::Copysign_FN, Inst::F32Copysign | Inst::F64Copysign => Self::Copysign_FN,
_ => { _ => {
return Err(()); return Err(());
} }

View File

@ -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<Expression>,
pub a: Box<Expression>,
pub b: Box<Expression>,
}
impl Select {
fn accept<V: Visitor>(&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<V: Visitor>(&self, visitor: &mut V) {
visitor.visit_get_local(self);
}
}
#[derive(Clone)]
pub struct GetGlobal {
pub var: u32,
}
impl GetGlobal {
fn accept<V: Visitor>(&self, visitor: &mut V) {
visitor.visit_get_global(self);
}
}
#[derive(Clone)]
pub struct AnyLoad {
pub op: Load,
pub offset: u32,
pub pointer: Box<Expression>,
}
impl AnyLoad {
fn accept<V: Visitor>(&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<V: Visitor>(&self, visitor: &mut V) {
visitor.visit_memory_size(self);
}
}
#[derive(Clone)]
pub struct MemoryGrow {
pub memory: u8,
pub value: Box<Expression>,
}
impl MemoryGrow {
fn accept<V: Visitor>(&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<V: Visitor>(&self, visitor: &mut V) {
visitor.visit_value(self);
}
}
#[derive(Clone)]
pub struct AnyUnOp {
pub op: UnOp,
pub rhs: Box<Expression>,
}
impl AnyUnOp {
fn accept<V: Visitor>(&self, visitor: &mut V) {
visitor.visit_any_unop(self);
self.rhs.accept(visitor);
}
}
#[derive(Clone)]
pub struct AnyBinOp {
pub op: BinOp,
pub lhs: Box<Expression>,
pub rhs: Box<Expression>,
}
impl AnyBinOp {
fn accept<V: Visitor>(&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<V: Visitor>(&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<V: Visitor>(&self, visitor: &mut V) {
visitor.visit_memorize(self);
self.value.accept(visitor);
}
}
pub struct Forward {
pub body: Vec<Statement>,
}
impl Forward {
fn accept<V: Visitor>(&self, visitor: &mut V) {
visitor.visit_forward(self);
for v in &self.body {
v.accept(visitor);
}
}
}
pub struct Backward {
pub body: Vec<Statement>,
}
impl Backward {
fn accept<V: Visitor>(&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<Statement>,
pub falsey: Option<Vec<Statement>>,
}
impl If {
fn accept<V: Visitor>(&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<V: Visitor>(&self, visitor: &mut V) {
visitor.visit_br(self);
}
}
pub struct BrIf {
pub cond: Expression,
pub target: u32,
}
impl BrIf {
fn accept<V: Visitor>(&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<V: Visitor>(&self, visitor: &mut V) {
visitor.visit_br_table(self);
self.cond.accept(visitor);
}
}
pub struct Return {
pub list: Vec<Expression>,
}
impl Return {
fn accept<V: Visitor>(&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<u32>,
pub param_list: Vec<Expression>,
}
impl Call {
fn accept<V: Visitor>(&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<u32>,
pub param_list: Vec<Expression>,
}
impl CallIndirect {
fn accept<V: Visitor>(&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<V: Visitor>(&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<V: Visitor>(&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<V: Visitor>(&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<V: Visitor>(&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<V: Visitor>(&self, visitor: &mut V) {
self.body.accept(visitor);
}
}

View File

@ -1,3 +0,0 @@
pub mod data;
mod operation;
pub mod transformer;

View File

@ -1,51 +0,0 @@
use std::{
fmt::Display,
io::{Result, Write},
};
use super::{luajit::LuaJIT, luau::Luau};
pub struct Infix<T> {
rhs: &'static str,
inner: T,
}
impl<T> Infix<T> {
pub fn new(rhs: &'static str, inner: T) -> Self {
Infix { rhs, inner }
}
}
impl<T> Display for Infix<T>
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<i64>;
}
pub fn from_string(name: &str) -> Option<&'static dyn Edition> {
match name.to_ascii_lowercase().as_str() {
"luau" => Some(&Luau),
"luajit" => Some(&LuaJIT),
_ => None,
}
}

View File

@ -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<i64> {
Infix::new("LL", i)
}
}

View File

@ -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<i64> {
Infix::new("", i)
}
}

View File

@ -1,4 +0,0 @@
pub mod ast;
pub mod edition;
pub mod translator;
mod visitor;

View File

@ -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<Arity>,
pub in_arity: Vec<Arity>,
}
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<Arity> {
if let External::Function(i) = import.external() {
Some(Arity::from_index(types, *i))
} else {
None
}
}
fn new_arity_in_list(wasm: &Module) -> Vec<Arity> {
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<Arity> {
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()
}
}

View File

@ -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<T>(&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<T>(&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)
}
}

View File

@ -1,3 +0,0 @@
pub mod arity;
pub mod data;
pub mod writer;

View File

@ -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<Label>,
num_param: u32,
edition: &'a dyn Edition,
}
impl<'a> Data<'a> {
pub fn new(edition: &'a dyn Edition) -> Self {
Self {
label_list: Vec::new(),
num_param: 0,
edition,
}
}
}
impl Select {
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
write!(w, "(")?;
self.cond.output(d, w)?;
write!(w, " ~= 0 and ")?;
self.a.output(d, w)?;
write!(w, " or ")?;
self.b.output(d, w)?;
write!(w, ")")
}
}
impl GetLocal {
fn write_variable(var: u32, d: &Data, w: &mut dyn Write) -> Result<()> {
if let Some(rem) = var.checked_sub(d.num_param) {
write!(w, "loc_{} ", rem)
} else {
write!(w, "param_{} ", var)
}
}
fn output(&self, d: &Data, w: &mut dyn Write) -> Result<()> {
Self::write_variable(self.var, d, w)
}
}
impl GetGlobal {
fn output(&self, w: &mut dyn Write) -> Result<()> {
write!(w, "GLOBAL_LIST[{}].value ", self.var)
}
}
impl AnyLoad {
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
write!(w, "load_{}(memory_at_0, ", self.op.as_name())?;
self.pointer.output(d, w)?;
write!(w, "+ {})", self.offset)
}
}
impl MemorySize {
fn output(&self, w: &mut dyn Write) -> Result<()> {
write!(w, "rt.memory.size(memory_at_{})", self.memory)
}
}
impl MemoryGrow {
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
write!(w, "rt.memory.grow(memory_at_{}, ", self.memory)?;
self.value.output(d, w)?;
write!(w, ")")
}
}
impl Value {
fn write_f32(f: f32, w: &mut dyn Write) -> Result<()> {
let sign = if f.is_sign_negative() { "-" } else { "" };
if f.is_infinite() {
write!(w, "{}math.huge", sign)
} else if f.is_nan() {
write!(w, "{}0/0", sign)
} else {
write!(w, "{:e}", f)
}
}
fn write_f64(f: f64, w: &mut dyn Write) -> Result<()> {
let sign = if f.is_sign_negative() { "-" } else { "" };
if f.is_infinite() {
write!(w, "{}math.huge", sign)
} else if f.is_nan() {
write!(w, "{}0/0", sign)
} else {
write!(w, "{:e}", f)
}
}
fn output(&self, d: &Data, w: &mut dyn Write) -> Result<()> {
match self {
Self::I32(i) => write!(w, "{} ", i),
Self::I64(i) => write!(w, "{} ", d.edition.i64(*i)),
Self::F32(f) => Self::write_f32(*f, w),
Self::F64(f) => Self::write_f64(*f, w),
}
}
}
impl AnyUnOp {
fn write_as_call(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
let (a, b) = self.op.as_name();
write!(w, "{}_{}(", a, b)?;
self.rhs.output(d, w)?;
write!(w, ")")
}
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
if let Some(op) = self.op.as_operator() {
write!(w, "{}", op)?;
self.rhs.output(d, w)
} else {
self.write_as_call(d, w)
}
}
}
impl AnyBinOp {
fn write_as_op(&self, op: &'static str, d: &mut Data, w: &mut dyn Write) -> Result<()> {
write!(w, "(")?;
self.lhs.output(d, w)?;
write!(w, "{} ", op)?;
self.rhs.output(d, w)?;
write!(w, ")")
}
fn write_as_call(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
let (a, b) = self.op.as_name();
write!(w, "{}_{}(", a, b)?;
self.lhs.output(d, w)?;
write!(w, ", ")?;
self.rhs.output(d, w)?;
write!(w, ")")
}
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
if let Some(op) = self.op.as_operator() {
self.write_as_op(op, d, w)
} else {
self.write_as_call(d, w)
}
}
}
impl Expression {
fn write_list(list: &[Self], d: &mut Data, w: &mut dyn Write) -> Result<()> {
list.iter().enumerate().try_for_each(|(i, v)| {
if i != 0 {
write!(w, ", ")?;
}
v.output(d, w)
})
}
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
match self {
Self::Recall(i) => write!(w, "reg_{} ", i),
Self::Select(s) => s.output(d, w),
Self::GetLocal(g) => g.output(d, w),
Self::GetGlobal(g) => g.output(w),
Self::AnyLoad(a) => a.output(d, w),
Self::MemorySize(m) => m.output(w),
Self::MemoryGrow(m) => m.output(d, w),
Self::Value(v) => v.output(d, w),
Self::AnyUnOp(a) => a.output(d, w),
Self::AnyBinOp(a) => a.output(d, w),
}
}
fn to_buffer(&self, d: &mut Data) -> Result<String> {
let mut buf = Vec::new();
self.output(d, &mut buf)?;
Ok(String::from_utf8(buf).unwrap())
}
}
impl Memorize {
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
write!(w, "reg_{} = ", self.var)?;
self.value.output(d, w)
}
}
impl Forward {
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
let rem = d.label_list.len();
d.label_list.push(Label::Forward);
d.edition.start_block(w)?;
self.body.iter().try_for_each(|s| s.output(d, w))?;
d.edition.end_block(rem, w)?;
d.label_list.pop().unwrap();
write_br_gadget(rem, d, w)
}
}
impl Backward {
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
let rem = d.label_list.len();
d.label_list.push(Label::Backward);
d.edition.start_loop(rem, w)?;
self.body.iter().try_for_each(|s| s.output(d, w))?;
d.edition.end_loop(w)?;
d.label_list.pop().unwrap();
write_br_gadget(rem, d, w)
}
}
impl If {
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
let rem = d.label_list.len();
d.label_list.push(Label::If);
let var = self.cond.to_buffer(d)?;
d.edition.start_if(&var, w)?;
self.truthy.iter().try_for_each(|s| s.output(d, w))?;
if let Some(v) = &self.falsey {
write!(w, "else ")?;
v.iter().try_for_each(|s| s.output(d, w))?;
}
d.edition.end_if(rem, w)?;
d.label_list.pop().unwrap();
write_br_gadget(rem, d, w)
}
}
impl Br {
fn write_at(up: u32, d: &Data, w: &mut dyn Write) -> Result<()> {
let up = up as usize;
let level = d.label_list.len() - 1;
let is_loop = d.label_list[level - up] == Label::Backward;
d.edition.br_to_level(level, up, is_loop, w)
}
fn output(&self, d: &Data, w: &mut dyn Write) -> Result<()> {
Self::write_at(self.target, d, w)
}
}
impl BrIf {
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
write!(w, "if ")?;
self.cond.output(d, w)?;
write!(w, "~= 0 then ")?;
Br::write_at(self.target, d, w)?;
write!(w, "end ")
}
}
impl BrTable {
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
write!(w, "local temp = ")?;
self.cond.output(d, w)?;
write!(w, " ")?;
for (start, end, dest) in condense_jump_table(&self.data.table) {
if start == end {
write!(w, "if temp == {} then ", start)?;
} else {
write!(w, "if temp >= {} and temp <= {} then ", start, end)?;
}
Br::write_at(dest, d, w)?;
write!(w, "else")?;
}
write!(w, " ")?;
Br::write_at(self.data.default, d, w)?;
write!(w, "end ")
}
}
impl Return {
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
write!(w, "do return ")?;
self.list.iter().enumerate().try_for_each(|(i, v)| {
if i > 0 {
write!(w, ", ")?;
}
v.output(d, w)
})?;
write!(w, "end ")
}
}
impl Call {
fn write_result_list(range: Range<u32>, w: &mut dyn Write) -> Result<()> {
if range.is_empty() {
return Ok(());
}
range.clone().try_for_each(|i| {
if i != range.start {
write!(w, ", ")?;
}
write!(w, "reg_{}", i)
})?;
write!(w, " = ")
}
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
Self::write_result_list(self.result.clone(), w)?;
write!(w, "FUNC_LIST[{}](", self.func)?;
Expression::write_list(&self.param_list, d, w)?;
write!(w, ")")
}
}
impl CallIndirect {
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
Call::write_result_list(self.result.clone(), w)?;
write!(w, "TABLE_LIST[{}].data[", self.table)?;
self.index.output(d, w)?;
write!(w, "](")?;
Expression::write_list(&self.param_list, d, w)?;
write!(w, ")")
}
}
impl SetLocal {
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
GetLocal::write_variable(self.var, d, w)?;
write!(w, "= ")?;
self.value.output(d, w)
}
}
impl SetGlobal {
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
write!(w, "GLOBAL_LIST[{}].value = ", self.var)?;
self.value.output(d, w)
}
}
impl AnyStore {
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
write!(w, "store_{}(memory_at_0, ", self.op.as_name())?;
self.pointer.output(d, w)?;
write!(w, "+ {}, ", self.offset)?;
self.value.output(d, w)?;
write!(w, ")")
}
}
impl Statement {
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
match self {
Statement::Unreachable => write!(w, "error(\"out of code bounds\")"),
Statement::Memorize(v) => v.output(d, w),
Statement::Forward(v) => v.output(d, w),
Statement::Backward(v) => v.output(d, w),
Statement::If(v) => v.output(d, w),
Statement::Br(v) => v.output(d, w),
Statement::BrIf(v) => v.output(d, w),
Statement::BrTable(v) => v.output(d, w),
Statement::Return(v) => v.output(d, w),
Statement::Call(v) => v.output(d, w),
Statement::CallIndirect(v) => v.output(d, w),
Statement::SetLocal(v) => v.output(d, w),
Statement::SetGlobal(v) => v.output(d, w),
Statement::AnyStore(v) => v.output(d, w),
}
}
}
impl Function {
fn write_variable_list(&self, w: &mut dyn Write) -> Result<()> {
if self.num_local != 0 {
let list = vec!["0"; self.num_local as usize].join(", ");
write!(w, "local ")?;
write_in_order("loc", self.num_local, w)?;
write!(w, " = {} ", list)?;
}
if self.num_stack != 0 {
write!(w, "local ")?;
write_in_order("reg", self.num_stack, w)?;
write!(w, " ")?;
}
Ok(())
}
pub fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
write!(w, "function(")?;
write_in_order("param", self.num_param, w)?;
write!(w, ")")?;
d.num_param = self.num_param;
for v in memory::visit(self) {
write!(w, "local memory_at_{0} = MEMORY_LIST[{0}]", v)?;
}
self.write_variable_list(w)?;
self.body.output(d, w)?;
write!(w, "end ")
}
}

View File

@ -1,59 +0,0 @@
use crate::backend::ast::data::{
AnyBinOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, CallIndirect,
Expression, Forward, GetGlobal, GetLocal, If, Memorize, MemoryGrow, MemorySize, Return, Select,
SetGlobal, SetLocal, Statement, Value,
};
pub trait Visitor {
fn visit_recall(&mut self, _: usize) {}
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_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) {}
}

View File

@ -1 +1,3 @@
pub mod backend; mod analyzer;
mod ast;
pub mod writer;

View File

@ -1,22 +1,28 @@
use backend::{edition::data::from_string, translator::data::Module}; use parity_wasm::{deserialize_file, elements::Module};
use parity_wasm::deserialize_file; use writer::{luajit::LuaJIT, luau::Luau, visit::Transpiler};
mod backend; mod analyzer;
mod ast;
mod writer;
fn lang_from_string<'a>(name: &str, wasm: &'a Module) -> Box<dyn Transpiler<'a> + 'a> {
match name.to_lowercase().as_str() {
"luau" => Box::new(Luau::new(wasm)),
"luajit" => Box::new(LuaJIT::new(wasm)),
_ => panic!("Bad option: {}", name),
}
}
fn main() { fn main() {
let mut args = std::env::args().skip(1); let mut args = std::env::args().skip(1);
let ed = args let name = args.next().expect("No language specified");
.next()
.as_deref()
.and_then(from_string)
.expect("No language argument provided");
let output = std::io::stdout(); let output = std::io::stdout();
for v in args { for v in args {
let wasm = deserialize_file(v).unwrap(); let wasm = deserialize_file(v).unwrap();
let module = Module::new(&wasm); let module = lang_from_string(&name, &wasm);
module.translate(ed, &mut output.lock()).unwrap(); module.transpile(&mut output.lock()).unwrap();
} }
} }

724
wasm/src/writer/luajit.rs Normal file
View File

@ -0,0 +1,724 @@
use std::{collections::BTreeSet, io::Result};
use parity_wasm::elements::{External, ImportCountType, Instruction, Internal, Module};
use crate::{
analyzer::{localize, memory},
ast::{
builder::{Arities, Builder},
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,
},
},
writer::shared::write_result_list,
};
use super::{
shared::{
aux_internal_index, write_f32, write_f64, write_in_order, write_memory_init,
write_nil_array, write_table_init, write_variable_list,
},
visit::{Transpiler, Writer},
};
fn write_expression(code: &[Instruction], w: Writer) -> 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, "{}LL ", v),
Instruction::F32Const(v) => write_f32(f32::from_bits(v), w),
Instruction::F64Const(v) => write_f64(f64::from_bits(v), w),
Instruction::GetGlobal(i) => write!(w, "GLOBAL_LIST[{}].value ", i),
_ => {
continue;
}
};
return result;
}
write!(w, "error(\"mundane expression\")")
}
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,
}
#[derive(Default)]
struct Visitor {
label_list: Vec<Label>,
num_param: u32,
}
trait Driver {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()>;
}
impl Driver for Recall {
fn visit(&self, _: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "reg_{} ", self.var)
}
}
impl Driver for Select {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "(")?;
self.cond.visit(v, w)?;
write!(w, "~= 0 and ")?;
self.a.visit(v, w)?;
write!(w, "or ")?;
self.b.visit(v, w)?;
write!(w, ")")
}
}
fn write_variable(var: u32, v: &Visitor, w: Writer) -> Result<()> {
if let Some(rem) = var.checked_sub(v.num_param) {
write!(w, "loc_{} ", rem)
} else {
write!(w, "param_{} ", var)
}
}
impl Driver for GetLocal {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write_variable(self.var, v, w)
}
}
impl Driver for GetGlobal {
fn visit(&self, _: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "GLOBAL_LIST[{}].value ", self.var)
}
}
impl Driver for AnyLoad {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "load_{}(memory_at_0, ", self.op.as_name())?;
self.pointer.visit(v, w)?;
write!(w, "+ {})", self.offset)
}
}
impl Driver for MemorySize {
fn visit(&self, _: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "rt.memory.size(memory_at_{})", self.memory)
}
}
impl Driver for MemoryGrow {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "rt.memory.grow(memory_at_{}, ", self.memory)?;
self.value.visit(v, w)?;
write!(w, ")")
}
}
impl Driver for Value {
fn visit(&self, _: &mut Visitor, w: Writer) -> Result<()> {
match self {
Self::I32(i) => write!(w, "{} ", i),
Self::I64(i) => write!(w, "{}LL ", i),
Self::F32(f) => write_f32(*f, w),
Self::F64(f) => write_f64(*f, w),
}
}
}
fn write_un_op_call(un_op: &AnyUnOp, v: &mut Visitor, w: Writer) -> Result<()> {
let (a, b) = un_op.op.as_name();
write!(w, "{}_{}(", a, b)?;
un_op.rhs.visit(v, w)?;
write!(w, ")")
}
impl Driver for AnyUnOp {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
if let Some(op) = self.op.as_operator() {
write!(w, "{}", op)?;
self.rhs.visit(v, w)
} else {
write_un_op_call(self, v, w)
}
}
}
fn write_bin_op(bin_op: &AnyBinOp, v: &mut Visitor, w: Writer) -> Result<()> {
let op = bin_op.op.as_operator().unwrap();
write!(w, "(")?;
bin_op.lhs.visit(v, w)?;
write!(w, "{} ", op)?;
bin_op.rhs.visit(v, w)?;
write!(w, ")")
}
fn write_bin_op_call(bin_op: &AnyBinOp, v: &mut Visitor, w: Writer) -> Result<()> {
let (a, b) = bin_op.op.as_name();
write!(w, "{}_{}(", a, b)?;
bin_op.lhs.visit(v, w)?;
write!(w, ", ")?;
bin_op.rhs.visit(v, w)?;
write!(w, ")")
}
impl Driver for AnyBinOp {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
if self.op.as_operator().is_some() {
write_bin_op(self, v, w)
} else {
write_bin_op_call(self, v, w)
}
}
}
fn write_expr_list(list: &[Expression], v: &mut Visitor, w: Writer) -> Result<()> {
list.iter().enumerate().try_for_each(|(i, e)| {
if i != 0 {
write!(w, ", ")?;
}
e.visit(v, w)
})
}
impl Driver for Expression {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
match self {
Self::Recall(e) => e.visit(v, w),
Self::Select(e) => e.visit(v, w),
Self::GetLocal(e) => e.visit(v, w),
Self::GetGlobal(e) => e.visit(v, w),
Self::AnyLoad(e) => e.visit(v, w),
Self::MemorySize(e) => e.visit(v, w),
Self::MemoryGrow(e) => e.visit(v, w),
Self::Value(e) => e.visit(v, w),
Self::AnyUnOp(e) => e.visit(v, w),
Self::AnyBinOp(e) => e.visit(v, w),
}
}
}
impl Driver for Memorize {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "reg_{} = ", self.var)?;
self.value.visit(v, w)
}
}
impl Driver for Forward {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
let rem = v.label_list.len();
v.label_list.push(Label::Forward);
write!(w, "do ")?;
self.body.iter().try_for_each(|s| s.visit(v, w))?;
write!(w, "::continue_at_{}::", rem)?;
write!(w, "end ")?;
v.label_list.pop().unwrap();
Ok(())
}
}
impl Driver for Backward {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
let rem = v.label_list.len();
v.label_list.push(Label::Backward);
write!(w, "do ")?;
write!(w, "::continue_at_{}::", rem)?;
self.body.iter().try_for_each(|s| s.visit(v, w))?;
write!(w, "end ")?;
v.label_list.pop().unwrap();
Ok(())
}
}
impl Driver for Else {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "else ")?;
self.body.iter().try_for_each(|s| s.visit(v, w))
}
}
impl Driver for If {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
let rem = v.label_list.len();
v.label_list.push(Label::If);
write!(w, "if ")?;
self.cond.visit(v, w)?;
write!(w, "~= 0 then ")?;
self.truthy.iter().try_for_each(|s| s.visit(v, w))?;
if let Some(s) = &self.falsey {
s.visit(v, w)?;
}
write!(w, "::continue_at_{}::", rem)?;
write!(w, "end ")?;
v.label_list.pop().unwrap();
Ok(())
}
}
fn write_br_at(up: u32, v: &Visitor, w: Writer) -> Result<()> {
let up = up as usize;
let level = v.label_list.len() - 1;
write!(w, "goto continue_at_{} ", level - up)
}
impl Driver for Br {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write_br_at(self.target, v, w)
}
}
impl Driver for BrIf {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "if ")?;
self.cond.visit(v, w)?;
write!(w, "~= 0 then ")?;
write_br_at(self.target, v, w)?;
write!(w, "end ")
}
}
impl Driver for BrTable {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "local temp = ")?;
self.cond.visit(v, w)?;
write!(w, " ")?;
for (start, end, dest) in condense_jump_table(&self.data.table) {
if start == end {
write!(w, "if temp == {} then ", start)?;
} else {
write!(w, "if temp >= {} and temp <= {} then ", start, end)?;
}
write_br_at(dest, v, w)?;
write!(w, "else")?;
}
write!(w, " ")?;
write_br_at(self.data.default, v, w)?;
write!(w, "end ")
}
}
impl Driver for Return {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "do return ")?;
self.list.iter().enumerate().try_for_each(|(i, r)| {
if i > 0 {
write!(w, ", ")?;
}
r.visit(v, w)
})?;
write!(w, "end ")
}
}
impl Driver for Call {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write_result_list(self.result.clone(), w)?;
write!(w, "FUNC_LIST[{}](", self.func)?;
write_expr_list(&self.param_list, v, w)?;
write!(w, ")")
}
}
impl Driver for CallIndirect {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write_result_list(self.result.clone(), w)?;
write!(w, "TABLE_LIST[{}].data[", self.table)?;
self.index.visit(v, w)?;
write!(w, "](")?;
write_expr_list(&self.param_list, v, w)?;
write!(w, ")")
}
}
impl Driver for SetLocal {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write_variable(self.var, v, w)?;
write!(w, "= ")?;
self.value.visit(v, w)
}
}
impl Driver for SetGlobal {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "GLOBAL_LIST[{}].value = ", self.var)?;
self.value.visit(v, w)
}
}
impl Driver for AnyStore {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "store_{}(memory_at_0, ", self.op.as_name())?;
self.pointer.visit(v, w)?;
write!(w, "+ {}, ", self.offset)?;
self.value.visit(v, w)?;
write!(w, ")")
}
}
impl Driver for Statement {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
match self {
Self::Unreachable => write!(w, "error(\"out of code bounds\")"),
Self::Memorize(s) => s.visit(v, w),
Self::Forward(s) => s.visit(v, w),
Self::Backward(s) => s.visit(v, w),
Self::If(s) => s.visit(v, w),
Self::Br(s) => s.visit(v, w),
Self::BrIf(s) => s.visit(v, w),
Self::BrTable(s) => s.visit(v, w),
Self::Return(s) => s.visit(v, w),
Self::Call(s) => s.visit(v, w),
Self::CallIndirect(s) => s.visit(v, w),
Self::SetLocal(s) => s.visit(v, w),
Self::SetGlobal(s) => s.visit(v, w),
Self::AnyStore(s) => s.visit(v, w),
}
}
}
impl Driver for Function {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "function(")?;
write_in_order("param", self.num_param, w)?;
write!(w, ")")?;
v.num_param = self.num_param;
for v in memory::visit(self) {
write!(w, "local memory_at_{0} = MEMORY_LIST[{0}]", v)?;
}
write_variable_list(self, w)?;
self.body.visit(v, w)?;
write!(w, "end ")
}
}
pub struct LuaJIT<'a> {
wasm: &'a Module,
arity: Arities,
}
impl<'a> LuaJIT<'a> {
fn gen_import_of<T>(&self, w: Writer, 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<T>(&self, w: Writer, 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: Writer) -> 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: Writer) -> 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: Writer) -> 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)?;
write_table_init(v.limits(), w)?;
}
Ok(())
}
fn gen_memory_list(&self, w: Writer) -> 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)?;
write_memory_init(v.limits(), w)?;
}
Ok(())
}
fn gen_global_list(&self, w: Writer) -> 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)?;
write_expression(v.init_expr().code(), w)?;
write!(w, "}}")?;
}
Ok(())
}
fn gen_element_list(&self, w: Writer) -> 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 =")?;
write_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: Writer) -> 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 =")?;
write_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: Writer) -> 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: Writer) -> 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))
}
// FIXME: Make `pub` only for fuzzing.
#[must_use]
pub fn build_func_list(&self) -> Vec<Function> {
let range = 0..self.arity.len_in();
range
.map(|i| Builder::new(self.wasm, &self.arity).consume(i))
.collect()
}
/// # Errors
/// Returns `Err` if writing to `Writer` failed.
pub fn gen_func_list(&self, func_list: &[Function], w: Writer) -> Result<()> {
let offset = self.arity.len_ex();
func_list.iter().enumerate().try_for_each(|(i, v)| {
write!(w, "FUNC_LIST[{}] =", i + offset)?;
v.visit(&mut Visitor::default(), w)
})
}
}
impl<'a> Transpiler<'a> for LuaJIT<'a> {
fn new(wasm: &'a Module) -> Self {
let arity = Arities::new(wasm);
Self { wasm, arity }
}
fn transpile(&self, w: Writer) -> Result<()> {
write!(w, "local rt = require(\"luajit\")")?;
let func_list = self.build_func_list();
Self::gen_localize(&func_list, w)?;
write_nil_array("FUNC_LIST", self.wasm.functions_space(), w)?;
write_nil_array("TABLE_LIST", self.wasm.table_space(), w)?;
write_nil_array("MEMORY_LIST", self.wasm.memory_space(), w)?;
write_nil_array("GLOBAL_LIST", self.wasm.globals_space(), w)?;
self.gen_func_list(&func_list, w)?;
self.gen_start_point(w)
}
}

727
wasm/src/writer/luau.rs Normal file
View File

@ -0,0 +1,727 @@
use std::{collections::BTreeSet, io::Result};
use parity_wasm::elements::{External, ImportCountType, Instruction, Internal, Module};
use crate::{
analyzer::{localize, memory},
ast::{
builder::{Arities, Builder},
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,
},
},
};
use super::{
shared::{
aux_internal_index, write_f32, write_f64, write_in_order, write_memory_init,
write_nil_array, write_result_list, write_table_init, write_variable_list,
},
visit::{Transpiler, Writer},
};
fn write_expression(code: &[Instruction], w: Writer) -> 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_f32(f32::from_bits(v), w),
Instruction::F64Const(v) => write_f64(f64::from_bits(v), w),
Instruction::GetGlobal(i) => write!(w, "GLOBAL_LIST[{}].value ", i),
_ => {
continue;
}
};
return result;
}
write!(w, "error(\"mundane expression\")")
}
fn br_target(level: usize, in_loop: bool, w: Writer) -> 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 ")
}
#[derive(PartialEq, Eq)]
enum Label {
Forward,
Backward,
If,
}
#[derive(Default)]
struct Visitor {
label_list: Vec<Label>,
num_param: u32,
}
impl Visitor {
fn write_br_gadget(&self, rem: usize, w: Writer) -> Result<()> {
match self.label_list.last() {
Some(Label::Forward | Label::If) => br_target(rem, false, w),
Some(Label::Backward) => br_target(rem, true, w),
None => Ok(()),
}
}
}
trait Driver {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()>;
}
impl Driver for Recall {
fn visit(&self, _: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "reg_{} ", self.var)
}
}
impl Driver for Select {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "(")?;
self.cond.visit(v, w)?;
write!(w, "~= 0 and ")?;
self.a.visit(v, w)?;
write!(w, "or ")?;
self.b.visit(v, w)?;
write!(w, ")")
}
}
fn write_variable(var: u32, v: &Visitor, w: Writer) -> Result<()> {
if let Some(rem) = var.checked_sub(v.num_param) {
write!(w, "loc_{} ", rem)
} else {
write!(w, "param_{} ", var)
}
}
impl Driver for GetLocal {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write_variable(self.var, v, w)
}
}
impl Driver for GetGlobal {
fn visit(&self, _: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "GLOBAL_LIST[{}].value ", self.var)
}
}
impl Driver for AnyLoad {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "load_{}(memory_at_0, ", self.op.as_name())?;
self.pointer.visit(v, w)?;
write!(w, "+ {})", self.offset)
}
}
impl Driver for MemorySize {
fn visit(&self, _: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "rt.memory.size(memory_at_{})", self.memory)
}
}
impl Driver for MemoryGrow {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "rt.memory.grow(memory_at_{}, ", self.memory)?;
self.value.visit(v, w)?;
write!(w, ")")
}
}
impl Driver for Value {
fn visit(&self, _: &mut Visitor, w: Writer) -> Result<()> {
match self {
Self::I32(i) => write!(w, "{} ", i),
Self::I64(i) => write!(w, "{} ", i),
Self::F32(f) => write_f32(*f, w),
Self::F64(f) => write_f64(*f, w),
}
}
}
fn write_un_op_call(un_op: &AnyUnOp, v: &mut Visitor, w: Writer) -> Result<()> {
let (a, b) = un_op.op.as_name();
write!(w, "{}_{}(", a, b)?;
un_op.rhs.visit(v, w)?;
write!(w, ")")
}
impl Driver for AnyUnOp {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
if let Some(op) = self.op.as_operator() {
write!(w, "{}", op)?;
self.rhs.visit(v, w)
} else {
write_un_op_call(self, v, w)
}
}
}
fn write_bin_op(bin_op: &AnyBinOp, v: &mut Visitor, w: Writer) -> Result<()> {
let op = bin_op.op.as_operator().unwrap();
write!(w, "(")?;
bin_op.lhs.visit(v, w)?;
write!(w, "{} ", op)?;
bin_op.rhs.visit(v, w)?;
write!(w, ")")
}
fn write_bin_op_call(bin_op: &AnyBinOp, v: &mut Visitor, w: Writer) -> Result<()> {
let (a, b) = bin_op.op.as_name();
write!(w, "{}_{}(", a, b)?;
bin_op.lhs.visit(v, w)?;
write!(w, ", ")?;
bin_op.rhs.visit(v, w)?;
write!(w, ")")
}
impl Driver for AnyBinOp {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
if self.op.as_operator().is_some() {
write_bin_op(self, v, w)
} else {
write_bin_op_call(self, v, w)
}
}
}
fn write_expr_list(list: &[Expression], v: &mut Visitor, w: Writer) -> Result<()> {
list.iter().enumerate().try_for_each(|(i, e)| {
if i != 0 {
write!(w, ", ")?;
}
e.visit(v, w)
})
}
impl Driver for Expression {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
match self {
Self::Recall(e) => e.visit(v, w),
Self::Select(e) => e.visit(v, w),
Self::GetLocal(e) => e.visit(v, w),
Self::GetGlobal(e) => e.visit(v, w),
Self::AnyLoad(e) => e.visit(v, w),
Self::MemorySize(e) => e.visit(v, w),
Self::MemoryGrow(e) => e.visit(v, w),
Self::Value(e) => e.visit(v, w),
Self::AnyUnOp(e) => e.visit(v, w),
Self::AnyBinOp(e) => e.visit(v, w),
}
}
}
impl Driver for Memorize {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "reg_{} = ", self.var)?;
self.value.visit(v, w)
}
}
impl Driver for Forward {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
let rem = v.label_list.len();
v.label_list.push(Label::Forward);
write!(w, "while true do ")?;
self.body.iter().try_for_each(|s| s.visit(v, w))?;
write!(w, "break ")?;
write!(w, "end ")?;
v.label_list.pop().unwrap();
v.write_br_gadget(rem, w)
}
}
impl Driver for Backward {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
let rem = v.label_list.len();
v.label_list.push(Label::Backward);
write!(w, "while true do ")?;
self.body.iter().try_for_each(|s| s.visit(v, w))?;
write!(w, "break ")?;
write!(w, "end ")?;
v.label_list.pop().unwrap();
v.write_br_gadget(rem, w)
}
}
impl Driver for Else {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "else ")?;
self.body.iter().try_for_each(|s| s.visit(v, w))
}
}
impl Driver for If {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
let rem = v.label_list.len();
v.label_list.push(Label::If);
write!(w, "while true do ")?;
write!(w, "if ")?;
self.cond.visit(v, w)?;
write!(w, "~= 0 then ")?;
self.truthy.iter().try_for_each(|s| s.visit(v, w))?;
if let Some(s) = &self.falsey {
s.visit(v, w)?;
}
write!(w, "end ")?;
write!(w, "break ")?;
write!(w, "end ")?;
v.label_list.pop().unwrap();
v.write_br_gadget(rem, w)
}
}
fn write_br_at(up: u32, v: &Visitor, w: Writer) -> Result<()> {
let up = up as usize;
let level = v.label_list.len() - 1;
write!(w, "do ")?;
if up == 0 {
let is_loop = v.label_list[level - up] == Label::Backward;
if is_loop {
write!(w, "continue ")?;
} else {
write!(w, "break ")?;
}
} else {
write!(w, "desired = {} ", level - up)?;
write!(w, "break ")?;
}
write!(w, "end ")
}
impl Driver for Br {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write_br_at(self.target, v, w)
}
}
impl Driver for BrIf {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "if ")?;
self.cond.visit(v, w)?;
write!(w, "~= 0 then ")?;
write_br_at(self.target, v, w)?;
write!(w, "end ")
}
}
impl Driver for BrTable {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "local temp = {{")?;
for d in self.data.table.iter() {
write!(w, "{}, ", d)?;
}
write!(w, "}} ")?;
write!(w, "desired = temp[")?;
self.cond.visit(v, w)?;
write!(w, "] or {} ", self.data.default)?;
write!(w, "break ")
}
}
impl Driver for Return {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "do return ")?;
self.list.iter().enumerate().try_for_each(|(i, r)| {
if i > 0 {
write!(w, ", ")?;
}
r.visit(v, w)
})?;
write!(w, "end ")
}
}
impl Driver for Call {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write_result_list(self.result.clone(), w)?;
write!(w, "FUNC_LIST[{}](", self.func)?;
write_expr_list(&self.param_list, v, w)?;
write!(w, ")")
}
}
impl Driver for CallIndirect {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write_result_list(self.result.clone(), w)?;
write!(w, "TABLE_LIST[{}].data[", self.table)?;
self.index.visit(v, w)?;
write!(w, "](")?;
write_expr_list(&self.param_list, v, w)?;
write!(w, ")")
}
}
impl Driver for SetLocal {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write_variable(self.var, v, w)?;
write!(w, "= ")?;
self.value.visit(v, w)
}
}
impl Driver for SetGlobal {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "GLOBAL_LIST[{}].value = ", self.var)?;
self.value.visit(v, w)
}
}
impl Driver for AnyStore {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "store_{}(memory_at_0, ", self.op.as_name())?;
self.pointer.visit(v, w)?;
write!(w, "+ {}, ", self.offset)?;
self.value.visit(v, w)?;
write!(w, ")")
}
}
impl Driver for Statement {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
match self {
Statement::Unreachable => write!(w, "error(\"out of code bounds\")"),
Statement::Memorize(s) => s.visit(v, w),
Statement::Forward(s) => s.visit(v, w),
Statement::Backward(s) => s.visit(v, w),
Statement::If(s) => s.visit(v, w),
Statement::Br(s) => s.visit(v, w),
Statement::BrIf(s) => s.visit(v, w),
Statement::BrTable(s) => s.visit(v, w),
Statement::Return(s) => s.visit(v, w),
Statement::Call(s) => s.visit(v, w),
Statement::CallIndirect(s) => s.visit(v, w),
Statement::SetLocal(s) => s.visit(v, w),
Statement::SetGlobal(s) => s.visit(v, w),
Statement::AnyStore(s) => s.visit(v, w),
}
}
}
impl Driver for Function {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
write!(w, "function(")?;
write_in_order("param", self.num_param, w)?;
write!(w, ")")?;
v.num_param = self.num_param;
for v in memory::visit(self) {
write!(w, "local memory_at_{0} = MEMORY_LIST[{0}]", v)?;
}
write_variable_list(self, w)?;
self.body.visit(v, w)?;
write!(w, "end ")
}
}
pub struct Luau<'a> {
wasm: &'a Module,
arity: Arities,
}
impl<'a> Luau<'a> {
fn gen_import_of<T>(&self, w: Writer, 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<T>(&self, w: Writer, 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: Writer) -> 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: Writer) -> 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: Writer) -> 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)?;
write_table_init(v.limits(), w)?;
}
Ok(())
}
fn gen_memory_list(&self, w: Writer) -> 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)?;
write_memory_init(v.limits(), w)?;
}
Ok(())
}
fn gen_global_list(&self, w: Writer) -> 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)?;
write_expression(v.init_expr().code(), w)?;
write!(w, "}}")?;
}
Ok(())
}
fn gen_element_list(&self, w: Writer) -> 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 =")?;
write_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: Writer) -> 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 =")?;
write_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: Writer) -> 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: Writer) -> 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))
}
fn build_func_list(&self) -> Vec<Function> {
let range = 0..self.arity.len_in();
range
.map(|i| Builder::new(self.wasm, &self.arity).consume(i))
.collect()
}
fn gen_func_list(&self, func_list: &[Function], w: Writer) -> Result<()> {
let offset = self.arity.len_ex();
func_list.iter().enumerate().try_for_each(|(i, v)| {
write!(w, "FUNC_LIST[{}] =", i + offset)?;
v.visit(&mut Visitor::default(), w)
})
}
}
impl<'a> Transpiler<'a> for Luau<'a> {
fn new(wasm: &'a Module) -> Self {
let arity = Arities::new(wasm);
Self { wasm, arity }
}
fn transpile(&self, w: Writer) -> Result<()> {
write!(w, "local rt = require(script.Runtime)")?;
let func_list = self.build_func_list();
Self::gen_localize(&func_list, w)?;
write_nil_array("FUNC_LIST", self.wasm.functions_space(), w)?;
write_nil_array("TABLE_LIST", self.wasm.table_space(), w)?;
write_nil_array("MEMORY_LIST", self.wasm.memory_space(), w)?;
write_nil_array("GLOBAL_LIST", self.wasm.globals_space(), w)?;
self.gen_func_list(&func_list, w)?;
self.gen_start_point(w)
}
}

View File

@ -1,3 +1,4 @@
pub mod data;
pub mod luajit; pub mod luajit;
pub mod luau; pub mod luau;
mod shared;
pub mod visit;

109
wasm/src/writer/shared.rs Normal file
View File

@ -0,0 +1,109 @@
use std::{io::Result, ops::Range};
use parity_wasm::elements::{Internal, ResizableLimits};
use crate::ast::node::Function;
use super::visit::Writer;
pub fn aux_internal_index(internal: Internal) -> u32 {
match internal {
Internal::Function(v) | Internal::Table(v) | Internal::Memory(v) | Internal::Global(v) => v,
}
}
pub fn new_limit_max(limits: &ResizableLimits) -> String {
match limits.maximum() {
Some(v) => v.to_string(),
None => "math.huge".to_string(),
}
}
pub fn write_table_init(limit: &ResizableLimits, w: Writer) -> Result<()> {
let a = limit.initial();
let b = new_limit_max(limit);
write!(w, "{{ min = {}, max = {}, data = {{}} }}", a, b)
}
pub fn write_memory_init(limit: &ResizableLimits, w: Writer) -> Result<()> {
let a = limit.initial();
let b = new_limit_max(limit);
write!(w, "rt.memory.new({}, {})", a, b)
}
pub fn write_nil_array(name: &str, len: usize, w: Writer) -> Result<()> {
if len == 0 {
return Ok(());
}
write!(w, "local {} = {{[0] = {}}}", name, "nil, ".repeat(len))
}
pub fn write_in_order(prefix: &str, len: u32, w: Writer) -> Result<()> {
if len == 0 {
return Ok(());
}
write!(w, "{}_{}", prefix, 0)?;
(1..len).try_for_each(|i| write!(w, ", {}_{}", prefix, i))
}
pub fn write_f32(f: f32, w: Writer) -> Result<()> {
let sign = if f.is_sign_negative() { "-" } else { "" };
if f.is_infinite() {
write!(w, "{}math.huge ", sign)
} else if f.is_nan() {
write!(w, "{}0/0 ", sign)
} else {
write!(w, "{:e} ", f)
}
}
pub fn write_f64(f: f64, w: Writer) -> Result<()> {
let sign = if f.is_sign_negative() { "-" } else { "" };
if f.is_infinite() {
write!(w, "{}math.huge ", sign)
} else if f.is_nan() {
write!(w, "{}0/0 ", sign)
} else {
write!(w, "{:e} ", f)
}
}
pub fn write_result_list(range: Range<u32>, w: Writer) -> Result<()> {
if range.is_empty() {
return Ok(());
}
range.clone().try_for_each(|i| {
if i != range.start {
write!(w, ", ")?;
}
write!(w, "reg_{}", i)
})?;
write!(w, " = ")
}
pub fn write_variable_list(func: &Function, w: Writer) -> Result<()> {
if func.num_local != 0 {
let list = vec!["0"; func.num_local as usize].join(", ");
write!(w, "local ")?;
write_in_order("loc", func.num_local, w)?;
write!(w, " = {} ", list)?;
}
if func.num_stack != 0 {
write!(w, "local ")?;
write_in_order("reg", func.num_stack, w)?;
write!(w, " ")?;
}
Ok(())
}

15
wasm/src/writer/visit.rs Normal file
View File

@ -0,0 +1,15 @@
use std::io::{Result, Write};
use parity_wasm::elements::Module;
pub type Writer<'a> = &'a mut dyn Write;
pub trait Transpiler<'a> {
fn new(wasm: &'a Module) -> Self
where
Self: Sized;
/// # Errors
/// Returns `Err` if writing to `Writer` failed.
fn transpile(&self, writer: Writer) -> Result<()>;
}