Refactor the codebase and organize files
This commit is contained in:
parent
82e97ad643
commit
96a27c9626
@ -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");
|
||||||
});
|
});
|
||||||
|
@ -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| {
|
||||||
|
@ -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");
|
||||||
});
|
});
|
||||||
|
@ -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)>,
|
@ -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>,
|
@ -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
317
wasm/src/analyzer/visit.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
@ -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
3
wasm/src/ast/mod.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pub mod builder;
|
||||||
|
pub mod node;
|
||||||
|
mod tag;
|
184
wasm/src/ast/node.rs
Normal file
184
wasm/src/ast/node.rs
Normal 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,
|
||||||
|
}
|
@ -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(());
|
||||||
}
|
}
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
pub mod data;
|
|
||||||
mod operation;
|
|
||||||
pub mod transformer;
|
|
@ -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,
|
|
||||||
}
|
|
||||||
}
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
pub mod ast;
|
|
||||||
pub mod edition;
|
|
||||||
pub mod translator;
|
|
||||||
mod visitor;
|
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
pub mod arity;
|
|
||||||
pub mod data;
|
|
||||||
pub mod writer;
|
|
@ -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 ")
|
|
||||||
}
|
|
||||||
}
|
|
@ -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) {}
|
|
||||||
}
|
|
@ -1 +1,3 @@
|
|||||||
pub mod backend;
|
mod analyzer;
|
||||||
|
mod ast;
|
||||||
|
pub mod writer;
|
||||||
|
@ -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
724
wasm/src/writer/luajit.rs
Normal 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
727
wasm/src/writer/luau.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
@ -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
109
wasm/src/writer/shared.rs
Normal 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
15
wasm/src/writer/visit.rs
Normal 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<()>;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user