Refactor Luau codegen to use wasmparser
This commit is contained in:
parent
c52170ba6e
commit
40c985e7e2
@ -3,12 +3,11 @@ name = "codegen-luau"
|
|||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
wasmparser = "0.86.0"
|
||||||
|
|
||||||
[dependencies.wasm-ast]
|
[dependencies.wasm-ast]
|
||||||
path = "../../wasm-ast"
|
path = "../../wasm-ast"
|
||||||
|
|
||||||
[dependencies.parity-wasm]
|
|
||||||
git = "https://github.com/paritytech/parity-wasm.git"
|
|
||||||
features = ["multi_value", "sign_ext"]
|
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "wasm2luau"
|
name = "wasm2luau"
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
use parity_wasm::elements::ValueType;
|
|
||||||
use wasm_ast::{
|
use wasm_ast::{
|
||||||
node::{BinOp, CmpOp, FuncData, LoadAt, MemoryGrow, MemorySize, StoreAt, UnOp, Value},
|
node::{BinOp, CmpOp, FuncData, LoadAt, MemoryGrow, MemorySize, StoreAt, UnOp, Value},
|
||||||
visit::{Driver, Visitor},
|
visit::{Driver, Visitor},
|
||||||
};
|
};
|
||||||
|
use wasmparser::ValType;
|
||||||
|
|
||||||
use super::as_symbol::AsSymbol;
|
use super::as_symbol::AsSymbol;
|
||||||
|
|
||||||
@ -80,11 +80,7 @@ pub fn visit(ast: &FuncData) -> (BTreeSet<(&'static str, &'static str)>, BTreeSe
|
|||||||
memory_set: BTreeSet::new(),
|
memory_set: BTreeSet::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if ast
|
if ast.local_data().iter().any(|v| v.1 == ValType::I64) {
|
||||||
.local_data()
|
|
||||||
.iter()
|
|
||||||
.any(|v| v.value_type() == ValueType::I64)
|
|
||||||
{
|
|
||||||
visit.local_set.insert(("i64", "K_ZERO"));
|
visit.local_set.insert(("i64", "K_ZERO"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,11 +3,11 @@ use std::{
|
|||||||
ops::Range,
|
ops::Range,
|
||||||
};
|
};
|
||||||
|
|
||||||
use parity_wasm::elements::ValueType;
|
|
||||||
use wasm_ast::node::{
|
use wasm_ast::node::{
|
||||||
Backward, Br, BrIf, BrTable, Call, CallIndirect, Forward, FuncData, If, MemoryGrow, SetGlobal,
|
Backward, Br, BrIf, BrTable, Call, CallIndirect, Forward, FuncData, If, MemoryGrow, SetGlobal,
|
||||||
SetLocal, SetTemporary, Statement, StoreAt, Terminator,
|
SetLocal, SetTemporary, Statement, StoreAt, Terminator,
|
||||||
};
|
};
|
||||||
|
use wasmparser::ValType;
|
||||||
|
|
||||||
use crate::analyzer::br_table;
|
use crate::analyzer::br_table;
|
||||||
|
|
||||||
@ -327,9 +327,9 @@ fn write_parameter_list(ast: &FuncData, w: &mut dyn Write) -> Result<()> {
|
|||||||
fn write_variable_list(ast: &FuncData, w: &mut dyn Write) -> Result<()> {
|
fn write_variable_list(ast: &FuncData, w: &mut dyn Write) -> Result<()> {
|
||||||
let mut total = 0;
|
let mut total = 0;
|
||||||
|
|
||||||
for data in ast.local_data().iter().filter(|v| v.count() != 0) {
|
for data in ast.local_data().iter().filter(|v| v.0 != 0) {
|
||||||
let range = total..total + usize::try_from(data.count()).unwrap();
|
let range = total..total + usize::try_from(data.0).unwrap();
|
||||||
let zero = if data.value_type() == ValueType::I64 {
|
let zero = if data.1 == ValType::I64 {
|
||||||
"i64_K_ZERO "
|
"i64_K_ZERO "
|
||||||
} else {
|
} else {
|
||||||
"0 "
|
"0 "
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
use std::io::{Result, Write};
|
use std::io::{Result, Write};
|
||||||
|
|
||||||
use parity_wasm::{deserialize_file, elements::Module};
|
use wasm_ast::module::Module;
|
||||||
|
|
||||||
fn load_module(name: &str) -> Module {
|
fn load_arg_source() -> Result<Vec<u8>> {
|
||||||
deserialize_file(name)
|
let name = std::env::args().nth(1).expect("usage: wasm2luajit <file>");
|
||||||
.expect("Failed to parse WebAssembly file")
|
|
||||||
.parse_names()
|
std::fs::read(name)
|
||||||
.unwrap_or_else(|v| v.1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_runtime(lock: &mut dyn Write) -> Result<()> {
|
fn do_runtime(lock: &mut dyn Write) -> Result<()> {
|
||||||
@ -22,14 +21,8 @@ fn do_runtime(lock: &mut dyn Write) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let wasm = match std::env::args().nth(1) {
|
let data = load_arg_source()?;
|
||||||
Some(name) => load_module(&name),
|
let wasm = Module::from_data(&data);
|
||||||
None => {
|
|
||||||
eprintln!("usage: wasm2luau <file>");
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let lock = &mut std::io::stdout().lock();
|
let lock = &mut std::io::stdout().lock();
|
||||||
|
|
||||||
|
@ -3,42 +3,41 @@ use std::{
|
|||||||
io::{Result, Write},
|
io::{Result, Write},
|
||||||
};
|
};
|
||||||
|
|
||||||
use parity_wasm::elements::{
|
|
||||||
External, ImportCountType, Instruction, Internal, Module, NameSection, ResizableLimits,
|
|
||||||
};
|
|
||||||
|
|
||||||
use wasm_ast::{
|
use wasm_ast::{
|
||||||
builder::{Builder, TypeInfo},
|
factory::Factory,
|
||||||
|
module::{External, Module, TypeInfo},
|
||||||
node::{FuncData, Statement},
|
node::{FuncData, Statement},
|
||||||
};
|
};
|
||||||
|
use wasmparser::{
|
||||||
|
Data, DataKind, Element, ElementItem, ElementKind, Export, FunctionBody, Import, InitExpr,
|
||||||
|
Operator, OperatorsReader,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
analyzer::localize,
|
analyzer::localize,
|
||||||
backend::manager::{Driver, Manager},
|
backend::manager::{Driver, Manager},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn to_internal_index(internal: Internal) -> u32 {
|
trait AsIEName {
|
||||||
match internal {
|
fn as_ie_name(&self) -> &str;
|
||||||
Internal::Function(v) | Internal::Table(v) | Internal::Memory(v) | Internal::Global(v) => v,
|
}
|
||||||
|
|
||||||
|
impl AsIEName for External {
|
||||||
|
fn as_ie_name(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
External::Func => "func_list",
|
||||||
|
External::Table => "table_list",
|
||||||
|
External::Memory => "memory_list",
|
||||||
|
External::Global => "global_list",
|
||||||
|
External::Tag => unimplemented!(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn limit_data_of(limits: &ResizableLimits) -> (u32, u32) {
|
fn reader_to_code(reader: OperatorsReader) -> Vec<Operator> {
|
||||||
let max = limits.maximum().unwrap_or(0xFFFF);
|
let parsed: std::result::Result<_, _> = reader.into_iter().collect();
|
||||||
|
|
||||||
(limits.initial(), max)
|
parsed.unwrap()
|
||||||
}
|
|
||||||
|
|
||||||
fn write_table_init(limit: &ResizableLimits, w: &mut dyn Write) -> Result<()> {
|
|
||||||
let (a, b) = limit_data_of(limit);
|
|
||||||
|
|
||||||
write!(w, "{{ min = {a}, max = {b}, data = {{}} }}")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_memory_init(limit: &ResizableLimits, w: &mut dyn Write) -> Result<()> {
|
|
||||||
let (a, b) = limit_data_of(limit);
|
|
||||||
|
|
||||||
write!(w, "rt.allocator.new({a}, {b})")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_named_array(name: &str, len: usize, w: &mut dyn Write) -> Result<()> {
|
fn write_named_array(name: &str, len: usize, w: &mut dyn Write) -> Result<()> {
|
||||||
@ -47,8 +46,9 @@ fn write_named_array(name: &str, len: usize, w: &mut dyn Write) -> Result<()> {
|
|||||||
write!(w, "local {name} = table.create({len})")
|
write!(w, "local {name} = table.create({len})")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_constant(code: &[Instruction], type_info: &TypeInfo, w: &mut dyn Write) -> Result<()> {
|
fn write_constant(init: &InitExpr, type_info: &TypeInfo, w: &mut dyn Write) -> Result<()> {
|
||||||
let func = Builder::from_type_info(type_info).build_anonymous(code);
|
let code = reader_to_code(init.get_operators_reader());
|
||||||
|
let func = Factory::from_type_info(type_info).create_anonymous(&code);
|
||||||
|
|
||||||
if let Some(Statement::SetTemporary(stat)) = func.code().code().last() {
|
if let Some(Statement::SetTemporary(stat)) = func.code().code().last() {
|
||||||
stat.value().write(&mut Manager::default(), w)
|
stat.value().write(&mut Manager::default(), w)
|
||||||
@ -57,128 +57,118 @@ fn write_constant(code: &[Instruction], type_info: &TypeInfo, w: &mut dyn Write)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_import_of<T>(wasm: &Module, lower: &str, cond: T, w: &mut dyn Write) -> Result<()>
|
fn write_import_of(list: &[Import], wanted: External, w: &mut dyn Write) -> Result<()> {
|
||||||
where
|
let lower = wanted.as_ie_name();
|
||||||
T: Fn(&External) -> bool,
|
|
||||||
{
|
|
||||||
let import = match wasm.import_section() {
|
|
||||||
Some(v) => v.entries(),
|
|
||||||
None => return Ok(()),
|
|
||||||
};
|
|
||||||
let upper = lower.to_uppercase();
|
let upper = lower.to_uppercase();
|
||||||
|
|
||||||
for (i, v) in import.iter().filter(|v| cond(v.external())).enumerate() {
|
for (i, Import { name, module, .. }) in list
|
||||||
let field = v.field();
|
.iter()
|
||||||
let module = v.module();
|
.filter(|v| External::from(v.ty) == wanted)
|
||||||
|
.enumerate()
|
||||||
write!(w, r#"{upper}[{i}] = wasm["{module}"].{lower}["{field}"]"#)?;
|
{
|
||||||
|
write!(w, r#"{upper}[{i}] = wasm["{module}"].{lower}["{name}"]"#)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_export_of<T>(wasm: &Module, lower: &str, cond: T, w: &mut dyn Write) -> Result<()>
|
fn write_export_of(list: &[Export], wanted: External, w: &mut dyn Write) -> Result<()> {
|
||||||
where
|
let lower = wanted.as_ie_name();
|
||||||
T: Fn(&Internal) -> bool,
|
|
||||||
{
|
|
||||||
let export = match wasm.export_section() {
|
|
||||||
Some(v) => v.entries(),
|
|
||||||
None => return Ok(()),
|
|
||||||
};
|
|
||||||
let upper = lower.to_uppercase();
|
let upper = lower.to_uppercase();
|
||||||
|
|
||||||
write!(w, "{lower} = {{")?;
|
write!(w, "{lower} = {{")?;
|
||||||
|
|
||||||
for v in export.iter().filter(|v| cond(v.internal())) {
|
for Export { name, index, .. } in list.iter().filter(|v| External::from(v.kind) == wanted) {
|
||||||
let field = v.field();
|
write!(w, r#"["{name}"] = {upper}[{index}],"#)?;
|
||||||
let index = to_internal_index(*v.internal());
|
|
||||||
|
|
||||||
write!(w, r#"["{field}"] = {upper}[{index}],"#)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(w, "}},")
|
write!(w, "}},")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_import_list(wasm: &Module, w: &mut dyn Write) -> Result<()> {
|
fn write_import_list(list: &[Import], w: &mut dyn Write) -> Result<()> {
|
||||||
write_import_of(wasm, "func_list", |v| matches!(v, External::Function(_)), w)?;
|
write_import_of(list, External::Func, w)?;
|
||||||
write_import_of(wasm, "table_list", |v| matches!(v, External::Table(_)), w)?;
|
write_import_of(list, External::Table, w)?;
|
||||||
write_import_of(wasm, "memory_list", |v| matches!(v, External::Memory(_)), w)?;
|
write_import_of(list, External::Memory, w)?;
|
||||||
write_import_of(wasm, "global_list", |v| matches!(v, External::Global(_)), w)
|
write_import_of(list, External::Global, w)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_export_list(wasm: &Module, w: &mut dyn Write) -> Result<()> {
|
fn write_export_list(list: &[Export], w: &mut dyn Write) -> Result<()> {
|
||||||
write_export_of(wasm, "func_list", |v| matches!(v, Internal::Function(_)), w)?;
|
write_export_of(list, External::Func, w)?;
|
||||||
write_export_of(wasm, "table_list", |v| matches!(v, Internal::Table(_)), w)?;
|
write_export_of(list, External::Table, w)?;
|
||||||
write_export_of(wasm, "memory_list", |v| matches!(v, Internal::Memory(_)), w)?;
|
write_export_of(list, External::Memory, w)?;
|
||||||
write_export_of(wasm, "global_list", |v| matches!(v, Internal::Global(_)), w)
|
write_export_of(list, External::Global, w)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_table_list(wasm: &Module, w: &mut dyn Write) -> Result<()> {
|
fn write_table_list(wasm: &Module, w: &mut dyn Write) -> Result<()> {
|
||||||
let table = match wasm.table_section() {
|
let offset = wasm.import_count(External::Table);
|
||||||
Some(v) => v.entries(),
|
let table = wasm.table_section();
|
||||||
None => return Ok(()),
|
|
||||||
};
|
|
||||||
let offset = wasm.import_count(ImportCountType::Table);
|
|
||||||
|
|
||||||
for (i, v) in table.iter().enumerate() {
|
for (i, table) in table.iter().enumerate() {
|
||||||
write!(w, "TABLE_LIST[{}] =", i + offset)?;
|
let index = offset + i;
|
||||||
write_table_init(v.limits(), w)?;
|
let min = table.initial;
|
||||||
|
let max = table.maximum.unwrap_or(0xFFFF);
|
||||||
|
|
||||||
|
write!(
|
||||||
|
w,
|
||||||
|
"TABLE_LIST[{index}] = {{ min = {min}, max = {max}, data = {{}} }}"
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_memory_list(wasm: &Module, w: &mut dyn Write) -> Result<()> {
|
fn write_memory_list(wasm: &Module, w: &mut dyn Write) -> Result<()> {
|
||||||
let memory = match wasm.memory_section() {
|
let offset = wasm.import_count(External::Memory);
|
||||||
Some(v) => v.entries(),
|
let memory = wasm.memory_section();
|
||||||
None => return Ok(()),
|
|
||||||
};
|
|
||||||
let offset = wasm.import_count(ImportCountType::Memory);
|
|
||||||
|
|
||||||
for (i, v) in memory.iter().enumerate() {
|
for (i, v) in memory.iter().enumerate() {
|
||||||
write!(w, "MEMORY_LIST[{}] =", i + offset)?;
|
let index = offset + i;
|
||||||
write_memory_init(v.limits(), w)?;
|
let min = v.initial;
|
||||||
|
let max = v.maximum.unwrap_or(0xFFFF);
|
||||||
|
|
||||||
|
write!(w, "MEMORY_LIST[{index}] = rt.allocator.new({min}, {max})")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_global_list(wasm: &Module, type_info: &TypeInfo, w: &mut dyn Write) -> Result<()> {
|
fn write_global_list(wasm: &Module, type_info: &TypeInfo, w: &mut dyn Write) -> Result<()> {
|
||||||
let global = match wasm.global_section() {
|
let offset = wasm.import_count(External::Global);
|
||||||
Some(v) => v,
|
let global = wasm.global_section();
|
||||||
None => return Ok(()),
|
|
||||||
};
|
|
||||||
let offset = wasm.import_count(ImportCountType::Global);
|
|
||||||
|
|
||||||
for (i, v) in global.entries().iter().enumerate() {
|
for (i, v) in global.iter().enumerate() {
|
||||||
write!(w, "GLOBAL_LIST[{}] = {{ value =", i + offset)?;
|
write!(w, "GLOBAL_LIST[{}] = {{ value =", i + offset)?;
|
||||||
write_constant(v.init_expr().code(), type_info, w)?;
|
write_constant(&v.init_expr, type_info, w)?;
|
||||||
write!(w, "}}")?;
|
write!(w, "}}")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_element_list(wasm: &Module, type_info: &TypeInfo, w: &mut dyn Write) -> Result<()> {
|
fn write_element_list(list: &[Element], type_info: &TypeInfo, w: &mut dyn Write) -> Result<()> {
|
||||||
let element = match wasm.elements_section() {
|
for v in list {
|
||||||
Some(v) => v.entries(),
|
let (index, init) = match v.kind {
|
||||||
None => return Ok(()),
|
ElementKind::Active {
|
||||||
|
table_index,
|
||||||
|
init_expr,
|
||||||
|
} => (table_index, init_expr),
|
||||||
|
_ => unimplemented!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
for v in element {
|
|
||||||
let code = v.offset().as_ref().unwrap().code();
|
|
||||||
|
|
||||||
write!(w, "do ")?;
|
write!(w, "do ")?;
|
||||||
write!(w, "local target = TABLE_LIST[{}].data ", v.index())?;
|
write!(w, "local target = TABLE_LIST[{index}].data ")?;
|
||||||
write!(w, "local offset =")?;
|
write!(w, "local offset =")?;
|
||||||
|
|
||||||
write_constant(code, type_info, w)?;
|
write_constant(&init, type_info, w)?;
|
||||||
|
|
||||||
write!(w, "local data = {{")?;
|
write!(w, "local data = {{")?;
|
||||||
|
|
||||||
v.members()
|
for item in v.items.get_items_reader().unwrap() {
|
||||||
.iter()
|
match item.unwrap() {
|
||||||
.try_for_each(|v| write!(w, "FUNC_LIST[{v}],"))?;
|
ElementItem::Func(index) => write!(w, "FUNC_LIST[{index}],"),
|
||||||
|
ElementItem::Expr(init) => write_constant(&init, type_info, w),
|
||||||
|
}?;
|
||||||
|
}
|
||||||
|
|
||||||
write!(w, "}}")?;
|
write!(w, "}}")?;
|
||||||
|
|
||||||
@ -190,36 +180,31 @@ fn write_element_list(wasm: &Module, type_info: &TypeInfo, w: &mut dyn Write) ->
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_data_list(wasm: &Module, type_info: &TypeInfo, w: &mut dyn Write) -> Result<()> {
|
fn write_data_list(list: &[Data], type_info: &TypeInfo, w: &mut dyn Write) -> Result<()> {
|
||||||
let data = match wasm.data_section() {
|
for data in list {
|
||||||
Some(v) => v.entries(),
|
let (index, init) = match data.kind {
|
||||||
None => return Ok(()),
|
DataKind::Passive => unimplemented!(),
|
||||||
|
DataKind::Active {
|
||||||
|
memory_index,
|
||||||
|
init_expr,
|
||||||
|
} => (memory_index, init_expr),
|
||||||
};
|
};
|
||||||
|
|
||||||
for v in data {
|
|
||||||
let code = v.offset().as_ref().unwrap().code();
|
|
||||||
let index = v.index();
|
|
||||||
|
|
||||||
write!(w, "rt.store.string(")?;
|
write!(w, "rt.store.string(")?;
|
||||||
write!(w, "MEMORY_LIST[{index}],")?;
|
write!(w, "MEMORY_LIST[{index}],")?;
|
||||||
write_constant(code, type_info, w)?;
|
write_constant(&init, type_info, w)?;
|
||||||
write!(w, r#","{}")"#, v.value().escape_ascii())?;
|
write!(w, r#","{}")"#, data.data.escape_ascii())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_func_list(wasm: &Module, type_info: &TypeInfo) -> Vec<FuncData> {
|
fn build_func_list(list: &[FunctionBody], type_info: &TypeInfo) -> Vec<FuncData> {
|
||||||
let list = match wasm.code_section() {
|
let mut builder = Factory::from_type_info(type_info);
|
||||||
Some(v) => v.bodies(),
|
|
||||||
None => return Vec::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut builder = Builder::from_type_info(type_info);
|
|
||||||
|
|
||||||
list.iter()
|
list.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|f| builder.build_indexed(f.0, f.1))
|
.map(|f| builder.create_indexed(f.0, f.1))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,28 +241,20 @@ fn write_localize_used(func_list: &[FuncData], w: &mut dyn Write) -> Result<BTre
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn write_func_start(wasm: &Module, index: u32, w: &mut dyn Write) -> Result<()> {
|
fn write_func_start(wasm: &Module, index: u32, w: &mut dyn Write) -> Result<()> {
|
||||||
let opt = wasm
|
|
||||||
.names_section()
|
|
||||||
.and_then(NameSection::functions)
|
|
||||||
.and_then(|v| v.names().get(index));
|
|
||||||
|
|
||||||
write!(w, "FUNC_LIST")?;
|
write!(w, "FUNC_LIST")?;
|
||||||
|
|
||||||
if let Some(name) = opt {
|
if let Some(name) = wasm.name_section().get(&index) {
|
||||||
write!(w, "--[[ {name} ]]")?;
|
write!(w, "--[[ {name} ]]")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(w, "[{index}] =")
|
write!(w, "[{index}] =")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_func_list(
|
fn write_func_list(wasm: &Module, func_list: &[FuncData], w: &mut dyn Write) -> Result<()> {
|
||||||
wasm: &Module,
|
let offset = wasm.import_count(External::Func);
|
||||||
type_info: &TypeInfo,
|
|
||||||
func_list: &[FuncData],
|
|
||||||
w: &mut dyn Write,
|
|
||||||
) -> Result<()> {
|
|
||||||
func_list.iter().enumerate().try_for_each(|(i, v)| {
|
func_list.iter().enumerate().try_for_each(|(i, v)| {
|
||||||
let index = (type_info.len_ex() + i).try_into().unwrap();
|
let index = (offset + i).try_into().unwrap();
|
||||||
|
|
||||||
write_func_start(wasm, index, w)?;
|
write_func_start(wasm, index, w)?;
|
||||||
|
|
||||||
@ -295,12 +272,12 @@ fn write_module_start(
|
|||||||
write_table_list(wasm, w)?;
|
write_table_list(wasm, w)?;
|
||||||
write_memory_list(wasm, w)?;
|
write_memory_list(wasm, w)?;
|
||||||
write_global_list(wasm, type_info, w)?;
|
write_global_list(wasm, type_info, w)?;
|
||||||
write_element_list(wasm, type_info, w)?;
|
write_element_list(wasm.element_section(), type_info, w)?;
|
||||||
write_data_list(wasm, type_info, w)?;
|
write_data_list(wasm.data_section(), type_info, w)?;
|
||||||
write!(w, "end ")?;
|
write!(w, "end ")?;
|
||||||
|
|
||||||
write!(w, "return function(wasm)")?;
|
write!(w, "return function(wasm)")?;
|
||||||
write_import_list(wasm, w)?;
|
write_import_list(wasm.import_section(), w)?;
|
||||||
write!(w, "run_init_code()")?;
|
write!(w, "run_init_code()")?;
|
||||||
|
|
||||||
for mem in mem_set {
|
for mem in mem_set {
|
||||||
@ -312,30 +289,30 @@ fn write_module_start(
|
|||||||
}
|
}
|
||||||
|
|
||||||
write!(w, "return {{")?;
|
write!(w, "return {{")?;
|
||||||
write_export_list(wasm, w)?;
|
write_export_list(wasm.export_section(), w)?;
|
||||||
write!(w, "}} end ")
|
write!(w, "}} end ")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// Returns `Err` if writing to `Write` failed.
|
/// Returns `Err` if writing to `Write` failed.
|
||||||
pub fn from_inst_list(code: &[Instruction], type_info: &TypeInfo, w: &mut dyn Write) -> Result<()> {
|
pub fn from_inst_list(code: &[Operator], type_info: &TypeInfo, w: &mut dyn Write) -> Result<()> {
|
||||||
Builder::from_type_info(type_info)
|
Factory::from_type_info(type_info)
|
||||||
.build_anonymous(code)
|
.create_anonymous(code)
|
||||||
.write(&mut Manager::default(), w)
|
.write(&mut Manager::default(), w)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// Returns `Err` if writing to `Write` failed.
|
/// Returns `Err` if writing to `Write` failed.
|
||||||
pub fn from_module_typed(wasm: &Module, type_info: &TypeInfo, w: &mut dyn Write) -> Result<()> {
|
pub fn from_module_typed(wasm: &Module, type_info: &TypeInfo, w: &mut dyn Write) -> Result<()> {
|
||||||
let func_list = build_func_list(wasm, type_info);
|
let func_list = build_func_list(wasm.code_section(), type_info);
|
||||||
let mem_set = write_localize_used(&func_list, w)?;
|
let mem_set = write_localize_used(&func_list, w)?;
|
||||||
|
|
||||||
write_named_array("FUNC_LIST", wasm.functions_space(), w)?;
|
write_named_array("FUNC_LIST", wasm.function_space(), w)?;
|
||||||
write_named_array("TABLE_LIST", wasm.table_space(), w)?;
|
write_named_array("TABLE_LIST", wasm.table_space(), w)?;
|
||||||
write_named_array("MEMORY_LIST", wasm.memory_space(), w)?;
|
write_named_array("MEMORY_LIST", wasm.memory_space(), w)?;
|
||||||
write_named_array("GLOBAL_LIST", wasm.globals_space(), w)?;
|
write_named_array("GLOBAL_LIST", wasm.global_space(), w)?;
|
||||||
|
|
||||||
write_func_list(wasm, type_info, &func_list, w)?;
|
write_func_list(wasm, &func_list, w)?;
|
||||||
write_module_start(wasm, type_info, &mem_set, w)
|
write_module_start(wasm, type_info, &mem_set, w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
use wasm_smith::Module;
|
use wasm_ast::module::Module;
|
||||||
|
use wasm_smith::Module as RngModule;
|
||||||
|
|
||||||
// We are not interested in parity_wasm errors.
|
// We are not interested in parity_wasm errors.
|
||||||
libfuzzer_sys::fuzz_target!(|module: Module| {
|
libfuzzer_sys::fuzz_target!(|module: RngModule| {
|
||||||
let data = module.to_bytes();
|
let data = module.to_bytes();
|
||||||
let wasm = match parity_wasm::deserialize_buffer(&data) {
|
let wasm = Module::from_data(&data);
|
||||||
Ok(v) => v,
|
|
||||||
Err(_) => return,
|
|
||||||
};
|
|
||||||
|
|
||||||
let sink = &mut std::io::sink();
|
let sink = &mut std::io::sink();
|
||||||
|
|
||||||
codegen_luau::from_module_untyped(&wasm, sink).expect("Luau should succeed");
|
codegen_luau::from_module_untyped(&wasm, sink).expect("LuaJIT should succeed");
|
||||||
});
|
});
|
||||||
|
@ -3,8 +3,7 @@ use std::{
|
|||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
};
|
};
|
||||||
|
|
||||||
use parity_wasm::elements::Module;
|
use wasm_ast::module::{Module, TypeInfo};
|
||||||
use wasm_ast::builder::TypeInfo;
|
|
||||||
use wast::{
|
use wast::{
|
||||||
core::{Expression, Instruction},
|
core::{Expression, Instruction},
|
||||||
AssertExpression, WastExecute, WastInvoke,
|
AssertExpression, WastExecute, WastInvoke,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user