Simplify type and local handling
This commit is contained in:
parent
a97bd899da
commit
233aee2c5e
@ -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)?;
|
||||||
|
@ -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)?;
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user