WIP.
This commit is contained in:
parent
1e26c0aaa4
commit
8e8464f76a
|
@ -14,6 +14,9 @@ pub struct Expression(BinaryenModule, BinaryenExpression);
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct Export(BinaryenModule, BinaryenExport);
|
pub struct Export(BinaryenModule, BinaryenExport);
|
||||||
|
|
||||||
|
type BinaryenIndex = u32;
|
||||||
|
type BinaryenType = usize;
|
||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
pub fn read(data: &[u8]) -> Result<Module> {
|
pub fn read(data: &[u8]) -> Result<Module> {
|
||||||
let ptr = unsafe { BinaryenModuleRead(data.as_ptr(), data.len()) };
|
let ptr = unsafe { BinaryenModuleRead(data.as_ptr(), data.len()) };
|
||||||
|
@ -268,128 +271,6 @@ fn name_to_string(name: *const c_char) -> Option<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expression {
|
impl Expression {
|
||||||
pub fn unpack(&self) -> Expr {
|
|
||||||
if self.1.is_null() {
|
|
||||||
return Expr::None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let kind = unsafe { BinaryenExpressionGetId(self.1) };
|
|
||||||
let kinds = &*EXPR_IDS;
|
|
||||||
|
|
||||||
if kind == kinds.nop {
|
|
||||||
Expr::Nop
|
|
||||||
} else if kind == kinds.block {
|
|
||||||
let name = name_to_string(unsafe { BinaryenBlockGetName(self.1) });
|
|
||||||
let children = unsafe {
|
|
||||||
(0..BinaryenBlockGetNumChildren(self.1))
|
|
||||||
.map(|i| Expression(self.0, BinaryenBlockGetChildAt(self.1, i)))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
};
|
|
||||||
Expr::Block(name, children)
|
|
||||||
} else if kind == kinds.if_ {
|
|
||||||
let cond = unsafe { Expression(self.0, BinaryenIfGetCondition(self.1)) };
|
|
||||||
let if_true = unsafe { Expression(self.0, BinaryenIfGetIfTrue(self.1)) };
|
|
||||||
let if_false = unsafe { Expression(self.0, BinaryenIfGetIfFalse(self.1)) };
|
|
||||||
Expr::If(cond, if_true, if_false)
|
|
||||||
} else if kind == kinds.loop_ {
|
|
||||||
let name = name_to_string(unsafe { BinaryenLoopGetName(self.1) });
|
|
||||||
let value = unsafe { Expression(self.0, BinaryenLoopGetBody(self.1)) };
|
|
||||||
Expr::Loop(name, value)
|
|
||||||
} else if kind == kinds.break_ {
|
|
||||||
let name = name_to_string(unsafe { BinaryenBreakGetName(self.1) }).unwrap();
|
|
||||||
let value = unsafe { Expression(self.0, BinaryenBreakGetValue(self.1)) };
|
|
||||||
Expr::Break(name, value)
|
|
||||||
} else if kind == kinds.switch {
|
|
||||||
let n = unsafe { BinaryenSwitchGetNumNames(self.1) };
|
|
||||||
let default_name = name_to_string(unsafe { BinaryenSwitchGetDefaultName(self.1) });
|
|
||||||
let names = (0..n)
|
|
||||||
.map(|i| name_to_string(unsafe { BinaryenSwitchGetNameAt(self.1, i) }))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let value = unsafe { Expression(self.0, BinaryenSwitchGetValue(self.1)) };
|
|
||||||
let cond = Expression(self.0, unsafe { BinaryenSwitchGetCondition(self.1) });
|
|
||||||
Expr::Switch(cond, value, default_name, names)
|
|
||||||
} else if kind == kinds.call {
|
|
||||||
let target = name_to_string(unsafe { BinaryenCallGetTarget(self.1) }).unwrap();
|
|
||||||
let n = unsafe { BinaryenCallGetNumOperands(self.1) };
|
|
||||||
let args = (0..n)
|
|
||||||
.map(|i| unsafe { Expression(self.0, BinaryenCallGetOperandAt(self.1, i)) })
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
Expr::Call(target, args)
|
|
||||||
} else if kind == kinds.call_indirect {
|
|
||||||
let target = unsafe { Expression(self.0, BinaryenCallIndirectGetTarget(self.1)) };
|
|
||||||
let n = unsafe { BinaryenCallIndirectGetNumOperands(self.1) };
|
|
||||||
let args = (0..n)
|
|
||||||
.map(|i| unsafe { Expression(self.0, BinaryenCallIndirectGetOperandAt(self.1, i)) })
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
Expr::CallIndirect(target, args)
|
|
||||||
} else if kind == kinds.local_get {
|
|
||||||
let index = unsafe { BinaryenLocalGetGetIndex(self.1) };
|
|
||||||
Expr::LocalGet(index)
|
|
||||||
} else if kind == kinds.local_set {
|
|
||||||
let index = unsafe { BinaryenLocalSetGetIndex(self.1) };
|
|
||||||
let value = unsafe { Expression(self.0, BinaryenLocalSetGetValue(self.1)) };
|
|
||||||
Expr::LocalSet(index, value)
|
|
||||||
} else if kind == kinds.global_get {
|
|
||||||
let name = name_to_string(unsafe { BinaryenGlobalGetGetName(self.1) }).unwrap();
|
|
||||||
Expr::GlobalGet(name)
|
|
||||||
} else if kind == kinds.global_set {
|
|
||||||
let name = name_to_string(unsafe { BinaryenGlobalSetGetName(self.1) }).unwrap();
|
|
||||||
let value = unsafe { Expression(self.0, BinaryenGlobalSetGetValue(self.1)) };
|
|
||||||
Expr::GlobalSet(name, value)
|
|
||||||
} else if kind == kinds.table_get {
|
|
||||||
let name = name_to_string(unsafe { BinaryenTableGetGetTable(self.1) }).unwrap();
|
|
||||||
let index = unsafe { Expression(self.0, BinaryenTableGetGetIndex(self.1)) };
|
|
||||||
Expr::TableGet(name, index)
|
|
||||||
} else if kind == kinds.table_set {
|
|
||||||
let name = name_to_string(unsafe { BinaryenTableSetGetTable(self.1) }).unwrap();
|
|
||||||
let index = unsafe { Expression(self.0, BinaryenTableSetGetIndex(self.1)) };
|
|
||||||
let value = unsafe { Expression(self.0, BinaryenTableSetGetIndex(self.1)) };
|
|
||||||
Expr::TableSet(name, index, value)
|
|
||||||
} else if kind == kinds.load {
|
|
||||||
let ptr = unsafe { Expression(self.0, BinaryenLoadGetPtr(self.1)) };
|
|
||||||
let offset = unsafe { BinaryenLoadGetOffset(self.1) };
|
|
||||||
Expr::Load(ptr, offset)
|
|
||||||
} else if kind == kinds.store {
|
|
||||||
let ptr = unsafe { Expression(self.0, BinaryenStoreGetPtr(self.1)) };
|
|
||||||
let offset = unsafe { BinaryenStoreGetOffset(self.1) };
|
|
||||||
let value = unsafe { Expression(self.0, BinaryenStoreGetValue(self.1)) };
|
|
||||||
Expr::Store(ptr, offset, value)
|
|
||||||
} else if kind == kinds.const_ {
|
|
||||||
let value = match self.ty() {
|
|
||||||
Type::None => unreachable!(),
|
|
||||||
Type::I32 => Value::I32(unsafe { BinaryenConstGetValueI32(self.1) }),
|
|
||||||
Type::I64 => Value::I64(unsafe { BinaryenConstGetValueI64(self.1) }),
|
|
||||||
Type::F32 => Value::F32(unsafe { BinaryenConstGetValueF32(self.1).to_bits() }),
|
|
||||||
Type::F64 => Value::F64(unsafe { BinaryenConstGetValueF64(self.1).to_bits() }),
|
|
||||||
};
|
|
||||||
Expr::Const(value)
|
|
||||||
} else if kind == kinds.unary {
|
|
||||||
let op = unsafe { BinaryenUnaryGetOp(self.1) };
|
|
||||||
let value = unsafe { Expression(self.0, BinaryenUnaryGetValue(self.1)) };
|
|
||||||
Expr::Unary(UnaryOp::from_kind(op), value)
|
|
||||||
} else if kind == kinds.binary {
|
|
||||||
let op = unsafe { BinaryenBinaryGetOp(self.1) };
|
|
||||||
let left = unsafe { Expression(self.0, BinaryenBinaryGetLeft(self.1)) };
|
|
||||||
let right = unsafe { Expression(self.0, BinaryenBinaryGetRight(self.1)) };
|
|
||||||
Expr::Binary(BinaryOp::from_kind(op), left, right)
|
|
||||||
} else if kind == kinds.select {
|
|
||||||
let cond = unsafe { Expression(self.0, BinaryenSelectGetCondition(self.1)) };
|
|
||||||
let if_true = unsafe { Expression(self.0, BinaryenSelectGetIfTrue(self.1)) };
|
|
||||||
let if_false = unsafe { Expression(self.0, BinaryenSelectGetIfFalse(self.1)) };
|
|
||||||
Expr::Select(cond, if_true, if_false)
|
|
||||||
} else if kind == kinds.drop_ {
|
|
||||||
let value = unsafe { Expression(self.0, BinaryenDropGetValue(self.1)) };
|
|
||||||
Expr::Drop(value)
|
|
||||||
} else if kind == kinds.return_ {
|
|
||||||
let value = unsafe { Expression(self.0, BinaryenReturnGetValue(self.1)) };
|
|
||||||
Expr::Return(value)
|
|
||||||
} else if kind == kinds.unreachable {
|
|
||||||
Expr::Unreachable
|
|
||||||
} else {
|
|
||||||
panic!("Unknown kind: {}", kind);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ty(&self) -> Type {
|
pub fn ty(&self) -> Type {
|
||||||
Type::from_kind(unsafe { BinaryenExpressionGetType(self.1) }).unwrap()
|
Type::from_kind(unsafe { BinaryenExpressionGetType(self.1) }).unwrap()
|
||||||
}
|
}
|
||||||
|
@ -401,6 +282,19 @@ impl Expression {
|
||||||
pub fn module(&self) -> BinaryenModule {
|
pub fn module(&self) -> BinaryenModule {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn block(module: &Module, exprs: &[Expression]) -> Expression {
|
||||||
|
let children = exprs.iter().map(|expr| expr.1).collect::<Vec<_>>();
|
||||||
|
Expression(module.0, unsafe {
|
||||||
|
BinaryenBlock(
|
||||||
|
module.0,
|
||||||
|
/* name = */ std::ptr::null(),
|
||||||
|
children.as_ptr(),
|
||||||
|
children.len() as BinaryenIndex,
|
||||||
|
BinaryenUndefined(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
@ -467,168 +361,6 @@ impl BinaryOp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum Expr {
|
|
||||||
None,
|
|
||||||
Nop,
|
|
||||||
Block(Option<String>, Vec<Expression>),
|
|
||||||
If(Expression, Expression, Expression),
|
|
||||||
Loop(Option<String>, Expression),
|
|
||||||
Break(String, Expression),
|
|
||||||
Switch(Expression, Expression, Option<String>, Vec<Option<String>>),
|
|
||||||
Call(String, Vec<Expression>),
|
|
||||||
CallIndirect(Expression, Vec<Expression>),
|
|
||||||
LocalGet(u32),
|
|
||||||
LocalSet(u32, Expression),
|
|
||||||
GlobalGet(String),
|
|
||||||
GlobalSet(String, Expression),
|
|
||||||
TableGet(String, Expression),
|
|
||||||
TableSet(String, Expression, Expression),
|
|
||||||
Load(Expression, u32),
|
|
||||||
Store(Expression, u32, Expression),
|
|
||||||
Const(Value),
|
|
||||||
Unary(UnaryOp, Expression),
|
|
||||||
Binary(BinaryOp, Expression, Expression),
|
|
||||||
Select(Expression, Expression, Expression),
|
|
||||||
Drop(Expression),
|
|
||||||
Return(Expression),
|
|
||||||
Unreachable,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Expr {
|
|
||||||
pub fn visit_children<F: FnMut(Expression)>(&self, mut f: F) {
|
|
||||||
self.visit_children_and_ret(|e| {
|
|
||||||
f(e);
|
|
||||||
let ret: Option<()> = None;
|
|
||||||
ret
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn visit_children_and_ret<R, F: FnMut(Expression) -> Option<R>>(
|
|
||||||
&self,
|
|
||||||
mut f: F,
|
|
||||||
) -> Option<R> {
|
|
||||||
match self {
|
|
||||||
&Expr::None => None,
|
|
||||||
&Expr::Block(_, ref subexprs) => {
|
|
||||||
for e in subexprs {
|
|
||||||
if let Some(ret) = f(*e) {
|
|
||||||
return Some(ret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
&Expr::If(cond, if_true, if_false) => {
|
|
||||||
if let Some(ret) = f(cond) {
|
|
||||||
return Some(ret);
|
|
||||||
}
|
|
||||||
if let Some(ret) = f(if_true) {
|
|
||||||
return Some(ret);
|
|
||||||
}
|
|
||||||
if let Some(ret) = f(if_false) {
|
|
||||||
return Some(ret);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
&Expr::Loop(_, body) => f(body),
|
|
||||||
&Expr::Drop(expr) => f(expr),
|
|
||||||
|
|
||||||
&Expr::Break(_, value) => f(value),
|
|
||||||
&Expr::Switch(index, value, ..) => {
|
|
||||||
if let Some(ret) = f(index) {
|
|
||||||
return Some(ret);
|
|
||||||
}
|
|
||||||
if let Some(ret) = f(value) {
|
|
||||||
return Some(ret);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
&Expr::Call(_, ref ops) => {
|
|
||||||
for op in ops {
|
|
||||||
if let Some(ret) = f(*op) {
|
|
||||||
return Some(ret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
&Expr::CallIndirect(target, ref ops) => {
|
|
||||||
if let Some(ret) = f(target) {
|
|
||||||
return Some(ret);
|
|
||||||
}
|
|
||||||
for op in ops {
|
|
||||||
if let Some(ret) = f(*op) {
|
|
||||||
return Some(ret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
&Expr::LocalGet(_) => None,
|
|
||||||
&Expr::LocalSet(_, expr) => f(expr),
|
|
||||||
&Expr::GlobalGet(_) => None,
|
|
||||||
&Expr::GlobalSet(_, expr) => f(expr),
|
|
||||||
&Expr::TableGet(_, index) => f(index),
|
|
||||||
&Expr::TableSet(_, index, value) => {
|
|
||||||
if let Some(val) = f(index) {
|
|
||||||
return Some(val);
|
|
||||||
}
|
|
||||||
if let Some(val) = f(value) {
|
|
||||||
return Some(val);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
&Expr::Load(ptr, _) => f(ptr),
|
|
||||||
&Expr::Store(ptr, _, value) => {
|
|
||||||
if let Some(ret) = f(ptr) {
|
|
||||||
return Some(ret);
|
|
||||||
}
|
|
||||||
if let Some(ret) = f(value) {
|
|
||||||
return Some(ret);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
&Expr::Const(_) => None,
|
|
||||||
&Expr::Unary(_, value) => f(value),
|
|
||||||
&Expr::Binary(_, left, right) => {
|
|
||||||
if let Some(ret) = f(left) {
|
|
||||||
return Some(ret);
|
|
||||||
}
|
|
||||||
if let Some(ret) = f(right) {
|
|
||||||
return Some(ret);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
&Expr::Select(cond, if_true, if_false) => {
|
|
||||||
if let Some(ret) = f(cond) {
|
|
||||||
return Some(ret);
|
|
||||||
}
|
|
||||||
if let Some(ret) = f(if_true) {
|
|
||||||
return Some(ret);
|
|
||||||
}
|
|
||||||
if let Some(ret) = f(if_false) {
|
|
||||||
return Some(ret);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
&Expr::Return(expr) => f(expr),
|
|
||||||
&Expr::Unreachable => None,
|
|
||||||
&Expr::Nop => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_expression(&self, module: BinaryenModule) -> Expression {
|
|
||||||
match self {
|
|
||||||
&Expr::Const(Value::I32(value)) => unsafe {
|
|
||||||
let literal = BinaryenLiteralInt32(value);
|
|
||||||
Expression(module, BinaryenConst(module, literal))
|
|
||||||
},
|
|
||||||
&Expr::LocalSet(idx, value) => unsafe {
|
|
||||||
Expression(module, BinaryenLocalSet(module, idx, value.1))
|
|
||||||
},
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
I32(i32),
|
I32(i32),
|
||||||
|
@ -803,6 +535,15 @@ extern "C" {
|
||||||
index: u32,
|
index: u32,
|
||||||
value: BinaryenExpression,
|
value: BinaryenExpression,
|
||||||
) -> BinaryenExpression;
|
) -> BinaryenExpression;
|
||||||
|
fn BinaryenBlock(
|
||||||
|
module: BinaryenModule,
|
||||||
|
name: *const c_char,
|
||||||
|
children: *const BinaryenExpression,
|
||||||
|
n_children: BinaryenIndex,
|
||||||
|
ty: BinaryenType,
|
||||||
|
) -> BinaryenExpression;
|
||||||
|
|
||||||
|
fn BinaryenUndefined() -> BinaryenType;
|
||||||
|
|
||||||
fn BinaryenLiteralInt32(x: i32) -> BinaryenLiteral;
|
fn BinaryenLiteralInt32(x: i32) -> BinaryenLiteral;
|
||||||
fn BinaryenLiteralInt64(x: i64) -> BinaryenLiteral;
|
fn BinaryenLiteralInt64(x: i64) -> BinaryenLiteral;
|
||||||
|
|
|
@ -220,6 +220,10 @@ impl FunctionBody {
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(idx, value_def)| (Value(idx as u32), value_def))
|
.map(|(idx, value_def)| (Value(idx as u32), value_def))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn blocks(&self) -> impl Iterator<Item = BlockId> {
|
||||||
|
(0..self.blocks.len()).into_iter()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::ops::Index<Value> for FunctionBody {
|
impl std::ops::Index<Value> for FunctionBody {
|
||||||
|
@ -516,11 +520,11 @@ impl<'a> Module<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_wasm_bytes(&self) -> Result<Vec<u8>> {
|
pub fn to_wasm_bytes(&self) -> Result<Vec<u8>> {
|
||||||
let binaryen_module = binaryen::Module::read(self.orig_bytes)?;
|
let mut binaryen_module = binaryen::Module::read(self.orig_bytes)?;
|
||||||
for &func in &self.dirty_funcs {
|
for &func in &self.dirty_funcs {
|
||||||
if let Some(body) = self.func(func).body() {
|
if let Some(body) = self.func(func).body() {
|
||||||
let mut binaryen_func = binaryen_module.func(func);
|
let mut binaryen_func = binaryen_module.func(func);
|
||||||
let binaryen_expr = backend::lower::generate_body(self, body);
|
let binaryen_expr = backend::lower::generate_body(body, &mut binaryen_module);
|
||||||
binaryen_func.set_body(binaryen_expr);
|
binaryen_func.set_body(binaryen_expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue