Simplify type and local handling

This commit is contained in:
Rerumu 2022-04-22 03:54:45 -04:00
parent a97bd899da
commit 233aee2c5e
5 changed files with 100 additions and 129 deletions

View File

@ -5,7 +5,7 @@ use parity_wasm::elements::{
}; };
use wasm_ast::{ use wasm_ast::{
builder::{Arities, Builder}, builder::{Builder, TypeInfo},
node::{ node::{
AnyBinOp, AnyCmpOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, AnyBinOp, AnyCmpOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call,
CallIndirect, Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize, CallIndirect, Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize,
@ -121,19 +121,17 @@ fn write_result_list(range: Range<u32>, w: Writer) -> Result<()> {
} }
fn write_variable_list(func: &Function, w: Writer) -> Result<()> { fn write_variable_list(func: &Function, w: Writer) -> Result<()> {
if !func.local_list.is_empty() { for data in &func.local_data {
let num_local = func.local_list.len().try_into().unwrap();
write!(w, "local ")?; write!(w, "local ")?;
write_in_order("loc", num_local, w)?; write_in_order("loc", data.count(), w)?;
write!(w, " = ")?; write!(w, " = ")?;
for (i, t) in func.local_list.iter().enumerate() { for i in 0..data.count() {
if i != 0 { if i != 0 {
write!(w, ", ")?; write!(w, ", ")?;
} }
write!(w, "ZERO_{} ", t)?; write!(w, "ZERO_{} ", data.value_type())?;
} }
} }
@ -597,7 +595,7 @@ impl Driver for Function {
write!(w, "local temp ")?; write!(w, "local temp ")?;
v.num_param = self.num_param; v.num_param = self.num_param;
self.body.visit(v, w)?; self.code.visit(v, w)?;
write!(w, "end ") write!(w, "end ")
} }
@ -605,16 +603,16 @@ impl Driver for Function {
pub struct Generator<'a> { pub struct Generator<'a> {
wasm: &'a Module, wasm: &'a Module,
arity: Arities, type_info: TypeInfo<'a>,
} }
static RUNTIME: &str = include_str!("../runtime/runtime.lua"); static RUNTIME: &str = include_str!("../runtime/runtime.lua");
impl<'a> Transpiler<'a> for Generator<'a> { impl<'a> Transpiler<'a> for Generator<'a> {
fn new(wasm: &'a Module) -> Self { fn new(wasm: &'a Module) -> Self {
let arity = Arities::new(wasm); let type_info = TypeInfo::from_module(wasm);
Self { wasm, arity } Self { wasm, type_info }
} }
fn runtime(w: Writer) -> Result<()> { fn runtime(w: Writer) -> Result<()> {
@ -850,10 +848,10 @@ impl<'a> Generator<'a> {
// FIXME: Make `pub` only for fuzzing. // FIXME: Make `pub` only for fuzzing.
#[must_use] #[must_use]
pub fn build_func_list(&self) -> Vec<Function> { pub fn build_func_list(&self) -> Vec<Function> {
let range = 0..self.arity.len_in(); let list = self.wasm.code_section().unwrap().bodies();
let iter = list.iter().enumerate();
range iter.map(|f| Builder::new(&self.type_info).consume(f.0, f.1))
.map(|i| Builder::new(self.wasm, &self.arity).consume(i))
.collect() .collect()
} }
@ -863,7 +861,7 @@ impl<'a> Generator<'a> {
/// # Panics /// # Panics
/// If the number of functions overflows 32 bits. /// If the number of functions overflows 32 bits.
pub fn gen_func_list(&self, func_list: &[Function], w: Writer) -> Result<()> { pub fn gen_func_list(&self, func_list: &[Function], w: Writer) -> Result<()> {
let o = self.arity.len_ex(); let o = self.type_info.len_ex();
func_list.iter().enumerate().try_for_each(|(i, v)| { func_list.iter().enumerate().try_for_each(|(i, v)| {
write_func_name(self.wasm, i.try_into().unwrap(), o.try_into().unwrap(), w)?; write_func_name(self.wasm, i.try_into().unwrap(), o.try_into().unwrap(), w)?;

View File

@ -5,7 +5,7 @@ use parity_wasm::elements::{
}; };
use wasm_ast::{ use wasm_ast::{
builder::{Arities, Builder}, builder::{Builder, TypeInfo},
node::{ node::{
AnyBinOp, AnyCmpOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, AnyBinOp, AnyCmpOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call,
CallIndirect, Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize, CallIndirect, Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize,
@ -120,19 +120,17 @@ fn write_result_list(range: Range<u32>, w: Writer) -> Result<()> {
} }
fn write_variable_list(func: &Function, w: Writer) -> Result<()> { fn write_variable_list(func: &Function, w: Writer) -> Result<()> {
if !func.local_list.is_empty() { for data in &func.local_data {
let num_local = func.local_list.len().try_into().unwrap();
write!(w, "local ")?; write!(w, "local ")?;
write_in_order("loc", num_local, w)?; write_in_order("loc", data.count(), w)?;
write!(w, " = ")?; write!(w, " = ")?;
for (i, t) in func.local_list.iter().enumerate() { for i in 0..data.count() {
if i != 0 { if i != 0 {
write!(w, ", ")?; write!(w, ", ")?;
} }
write!(w, "ZERO_{} ", t)?; write!(w, "ZERO_{} ", data.value_type())?;
} }
} }
@ -593,7 +591,7 @@ impl Driver for Function {
write_variable_list(self, w)?; write_variable_list(self, w)?;
v.num_param = self.num_param; v.num_param = self.num_param;
self.body.visit(v, w)?; self.code.visit(v, w)?;
write!(w, "end ") write!(w, "end ")
} }
@ -601,16 +599,16 @@ impl Driver for Function {
pub struct Generator<'a> { pub struct Generator<'a> {
wasm: &'a Module, wasm: &'a Module,
arity: Arities, type_info: TypeInfo<'a>,
} }
static RUNTIME: &str = include_str!("../runtime/runtime.lua"); static RUNTIME: &str = include_str!("../runtime/runtime.lua");
impl<'a> Transpiler<'a> for Generator<'a> { impl<'a> Transpiler<'a> for Generator<'a> {
fn new(wasm: &'a Module) -> Self { fn new(wasm: &'a Module) -> Self {
let arity = Arities::new(wasm); let type_info = TypeInfo::from_module(wasm);
Self { wasm, arity } Self { wasm, type_info }
} }
fn runtime(w: Writer) -> Result<()> { fn runtime(w: Writer) -> Result<()> {
@ -843,15 +841,15 @@ impl<'a> Generator<'a> {
} }
fn build_func_list(&self) -> Vec<Function> { fn build_func_list(&self) -> Vec<Function> {
let range = 0..self.arity.len_in(); let list = self.wasm.code_section().unwrap().bodies();
let iter = list.iter().enumerate();
range iter.map(|f| Builder::new(&self.type_info).consume(f.0, f.1))
.map(|i| Builder::new(self.wasm, &self.arity).consume(i))
.collect() .collect()
} }
fn gen_func_list(&self, func_list: &[Function], w: Writer) -> Result<()> { fn gen_func_list(&self, func_list: &[Function], w: Writer) -> Result<()> {
let o = self.arity.len_ex(); let o = self.type_info.len_ex();
func_list.iter().enumerate().try_for_each(|(i, v)| { func_list.iter().enumerate().try_for_each(|(i, v)| {
write_func_name(self.wasm, i.try_into().unwrap(), o.try_into().unwrap(), w)?; write_func_name(self.wasm, i.try_into().unwrap(), o.try_into().unwrap(), w)?;

View File

@ -1,6 +1,6 @@
use parity_wasm::elements::{ use parity_wasm::elements::{
BlockType, External, FuncBody, FunctionType, ImportEntry, Instruction, Local, Module, Type, BlockType, External, Func, FuncBody, FunctionSection, FunctionType, ImportEntry, ImportSection,
ValueType, Instruction, Module, Type, TypeSection,
}; };
use crate::node::{ use crate::node::{
@ -25,77 +25,80 @@ impl Arity {
num_result, 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 { pub struct TypeInfo<'a> {
ex_arity: Vec<Arity>, data: &'a [Type],
in_arity: Vec<Arity>, func_ex: Vec<u32>,
func_in: Vec<u32>,
} }
impl Arities { impl<'a> TypeInfo<'a> {
#[must_use] #[must_use]
pub fn new(parent: &Module) -> Self { pub fn from_module(parent: &'a Module) -> Self {
let data = parent
.type_section()
.map_or([].as_ref(), TypeSection::types);
let func_ex = Self::new_ex_list(parent);
let func_in = Self::new_in_list(parent);
Self { Self {
ex_arity: Arity::new_ex_list(parent), data,
in_arity: Arity::new_in_list(parent), func_ex,
func_in,
} }
} }
#[must_use] #[must_use]
pub fn len_in(&self) -> usize { pub fn len_in(&self) -> usize {
self.in_arity.len() self.func_in.len()
} }
#[must_use] #[must_use]
pub fn len_ex(&self) -> usize { pub fn len_ex(&self) -> usize {
self.ex_arity.len() self.func_ex.len()
} }
fn arity_of(&self, index: usize) -> &Arity { fn raw_arity_of(&self, index: u32) -> Arity {
let offset = self.ex_arity.len(); let Type::Function(typ) = &self.data[index as usize];
self.ex_arity Arity::from_type(typ)
.get(index) }
.or_else(|| self.in_arity.get(index - offset))
.unwrap() fn arity_of(&self, index: usize) -> Arity {
let adjusted = self
.func_ex
.iter()
.chain(self.func_in.iter())
.nth(index)
.unwrap();
self.raw_arity_of(*adjusted)
}
fn func_of_import(import: &ImportEntry) -> Option<u32> {
if let &External::Function(i) = import.external() {
Some(i)
} else {
None
}
}
fn new_ex_list(wasm: &Module) -> Vec<u32> {
let list = wasm
.import_section()
.map_or([].as_ref(), ImportSection::entries);
list.iter().filter_map(Self::func_of_import).collect()
}
fn new_in_list(wasm: &Module) -> Vec<u32> {
let list = wasm
.function_section()
.map_or([].as_ref(), FunctionSection::entries);
list.iter().map(Func::type_ref).collect()
} }
} }
@ -259,8 +262,7 @@ impl Stacked {
pub struct Builder<'a> { pub struct Builder<'a> {
// target state // target state
wasm: &'a Module, type_info: &'a TypeInfo<'a>,
other: &'a Arities,
num_result: u32, num_result: u32,
// translation state // translation state
@ -278,67 +280,40 @@ fn is_dead_precursor(inst: &Instruction) -> bool {
) )
} }
fn flat_local_list(local: Local) -> impl Iterator<Item = ValueType> {
std::iter::repeat(local.value_type()).take(local.count().try_into().unwrap())
}
fn load_local_list(func: &FuncBody) -> Vec<ValueType> {
func.locals()
.iter()
.copied()
.flat_map(flat_local_list)
.collect()
}
fn load_func_at(wasm: &Module, index: usize) -> &FuncBody {
&wasm.code_section().unwrap().bodies()[index]
}
impl<'a> Builder<'a> { impl<'a> Builder<'a> {
#[must_use] #[must_use]
pub fn new(wasm: &'a Module, other: &'a Arities) -> Builder<'a> { pub fn new(info: &'a TypeInfo) -> Builder<'a> {
Builder { Builder {
wasm, type_info: info,
other,
num_result: 0, num_result: 0,
data: Stacked::new(), data: Stacked::new(),
} }
} }
#[must_use] #[must_use]
pub fn consume(mut self, index: usize) -> Function { pub fn consume(mut self, index: usize, func: &'a FuncBody) -> Function {
let func = load_func_at(self.wasm, index); let arity = &self.type_info.arity_of(self.type_info.len_ex() + index);
let arity = &self.other.in_arity[index];
let local_list = load_local_list(func);
let num_param = arity.num_param;
self.num_result = arity.num_result; self.num_result = arity.num_result;
let body = self.new_forward(&mut func.code().elements()); let code = self.new_forward(&mut func.code().elements());
let num_stack = self.data.last_stack.try_into().unwrap(); let num_stack = self.data.last_stack.try_into().unwrap();
Function { Function {
local_list, local_data: func.locals().to_vec(),
num_param, num_param: arity.num_param,
num_stack, num_stack,
body, code,
} }
} }
fn get_type_of(&self, index: u32) -> Arity {
let types = self.wasm.type_section().unwrap().types();
Arity::from_index(types, index)
}
fn push_block_result(&mut self, typ: BlockType) { fn push_block_result(&mut self, typ: BlockType) {
let num = match typ { let num = match typ {
BlockType::NoResult => { BlockType::NoResult => {
return; return;
} }
BlockType::Value(_) => 1, BlockType::Value(_) => 1,
BlockType::TypeIndex(i) => self.get_type_of(i).num_result, BlockType::TypeIndex(i) => self.type_info.raw_arity_of(i).num_result,
}; };
self.data.push_recall(num); self.data.push_recall(num);
@ -354,7 +329,7 @@ impl<'a> Builder<'a> {
} }
fn gen_call(&mut self, func: u32, stat: &mut Vec<Statement>) { fn gen_call(&mut self, func: u32, stat: &mut Vec<Statement>) {
let arity = self.other.arity_of(func as usize); let arity = self.type_info.arity_of(func as usize);
let param_list = self.data.pop_many(arity.num_param as usize); let param_list = self.data.pop_many(arity.num_param as usize);
let first = u32::try_from(self.data.stack.len()).unwrap(); let first = u32::try_from(self.data.stack.len()).unwrap();
@ -371,7 +346,7 @@ impl<'a> Builder<'a> {
} }
fn gen_call_indirect(&mut self, typ: u32, table: u8, stat: &mut Vec<Statement>) { fn gen_call_indirect(&mut self, typ: u32, table: u8, stat: &mut Vec<Statement>) {
let arity = self.get_type_of(typ); let arity = self.type_info.raw_arity_of(typ);
let index = self.data.pop(); let index = self.data.pop();
let param_list = self.data.pop_many(arity.num_param as usize); let param_list = self.data.pop_many(arity.num_param as usize);

View File

@ -1,6 +1,6 @@
use std::ops::Range; use std::ops::Range;
use parity_wasm::elements::{BrTableData, ValueType}; use parity_wasm::elements::{BrTableData, Local};
use std::convert::TryFrom; use std::convert::TryFrom;
@ -767,8 +767,8 @@ pub enum Statement {
} }
pub struct Function { pub struct Function {
pub local_list: Vec<ValueType>, pub local_data: Vec<Local>,
pub num_param: u32, pub num_param: u32,
pub num_stack: u32, pub num_stack: u32,
pub body: Forward, pub code: Forward,
} }

View File

@ -324,6 +324,6 @@ impl<T: Visitor> Driver<T> for Statement {
impl<T: Visitor> Driver<T> for Function { impl<T: Visitor> Driver<T> for Function {
fn accept(&self, visitor: &mut T) { fn accept(&self, visitor: &mut T) {
self.body.accept(visitor); self.code.accept(visitor);
} }
} }