Remove wasm_encoder backend, and bring in binaryen bindings
This commit is contained in:
parent
e2be302e47
commit
2214c1701b
|
@ -8,7 +8,6 @@ edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmparser = { git = 'https://github.com/cfallin/wasm-tools', rev = '03a81b6a6ed4d5d9730fa71bf65636a3b1538ce7' }
|
wasmparser = { git = 'https://github.com/cfallin/wasm-tools', rev = '03a81b6a6ed4d5d9730fa71bf65636a3b1538ce7' }
|
||||||
wasm-encoder = "0.8"
|
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
structopt = "0.3"
|
structopt = "0.3"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
@ -16,3 +15,5 @@ env_logger = "0.9"
|
||||||
fxhash = "0.2"
|
fxhash = "0.2"
|
||||||
smallvec = "1.7"
|
smallvec = "1.7"
|
||||||
rayon = "1.5"
|
rayon = "1.5"
|
||||||
|
lazy_static = "1.4"
|
||||||
|
libc = "0.2"
|
||||||
|
|
776
src/backend/binaryen.rs
Normal file
776
src/backend/binaryen.rs
Normal file
|
@ -0,0 +1,776 @@
|
||||||
|
//! Binaryen bindings.
|
||||||
|
|
||||||
|
use anyhow::{bail, Result};
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use libc::{c_char, c_void};
|
||||||
|
use std::ffi::{CStr, CString};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Module(BinaryenModule);
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct Function(BinaryenModule, BinaryenFunction);
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct Expression(BinaryenModule, BinaryenExpression);
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct Export(BinaryenModule, BinaryenExport);
|
||||||
|
|
||||||
|
impl Module {
|
||||||
|
pub fn read(data: &[u8]) -> Result<Module> {
|
||||||
|
let ptr = unsafe { BinaryenModuleRead(data.as_ptr(), data.len()) };
|
||||||
|
if ptr.is_null() {
|
||||||
|
bail!("Failed to parse module");
|
||||||
|
}
|
||||||
|
Ok(Module(ptr))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn num_funcs(&self) -> usize {
|
||||||
|
unsafe { BinaryenGetNumFunctions(self.0) as usize }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn func(&self, index: usize) -> Function {
|
||||||
|
assert!(index < self.num_funcs());
|
||||||
|
let ptr = unsafe { BinaryenGetFunctionByIndex(self.0, index as u32) };
|
||||||
|
assert!(!ptr.is_null());
|
||||||
|
Function(self.0, ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn func_by_name(&self, name: &str) -> Option<Function> {
|
||||||
|
let c_str = CString::new(name).unwrap();
|
||||||
|
let ptr = unsafe { BinaryenGetFunction(self.0, c_str.as_ptr()) };
|
||||||
|
if !ptr.is_null() {
|
||||||
|
Some(Function(self.0, ptr))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn num_exports(&self) -> usize {
|
||||||
|
unsafe { BinaryenGetNumExports(self.0) as usize }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn export_by_name(&self, name: &str) -> Option<Export> {
|
||||||
|
let c_str = CString::new(name).unwrap();
|
||||||
|
let ptr = unsafe { BinaryenGetExport(self.0, c_str.as_ptr()) };
|
||||||
|
if !ptr.is_null() {
|
||||||
|
Some(Export(self.0, ptr))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn export(&self, index: usize) -> Export {
|
||||||
|
assert!(index < self.num_exports());
|
||||||
|
let ptr = unsafe { BinaryenGetExportByIndex(self.0, index as u32) };
|
||||||
|
assert!(!ptr.is_null());
|
||||||
|
Export(self.0, ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn module(&self) -> BinaryenModule {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Module {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
BinaryenModuleDispose(self.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Function {
|
||||||
|
pub fn body(&self) -> Option<Expression> {
|
||||||
|
let body = unsafe { BinaryenFunctionGetBody(self.1) };
|
||||||
|
if body.is_null() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Expression(self.0, body))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
let s = unsafe { CStr::from_ptr(BinaryenFunctionGetName(self.1)) };
|
||||||
|
s.to_str().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Export {
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
let s = unsafe { CStr::from_ptr(BinaryenExportGetName(self.1)) };
|
||||||
|
s.to_str().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value(&self) -> &str {
|
||||||
|
let s = unsafe { CStr::from_ptr(BinaryenExportGetValue(self.1)) };
|
||||||
|
s.to_str().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_function(&self, module: &Module) -> Option<Function> {
|
||||||
|
let kind = unsafe { BinaryenExportGetKind(self.1) };
|
||||||
|
if kind == unsafe { BinaryenExternalFunction() } {
|
||||||
|
let name = self.value();
|
||||||
|
module.func_by_name(name)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ExprIds {
|
||||||
|
nop: u32,
|
||||||
|
block: u32,
|
||||||
|
if_: u32,
|
||||||
|
loop_: u32,
|
||||||
|
break_: u32,
|
||||||
|
switch: u32,
|
||||||
|
call: u32,
|
||||||
|
call_indirect: u32,
|
||||||
|
local_get: u32,
|
||||||
|
local_set: u32,
|
||||||
|
global_get: u32,
|
||||||
|
global_set: u32,
|
||||||
|
table_get: u32,
|
||||||
|
table_set: u32,
|
||||||
|
load: u32,
|
||||||
|
store: u32,
|
||||||
|
const_: u32,
|
||||||
|
unary: u32,
|
||||||
|
binary: u32,
|
||||||
|
select: u32,
|
||||||
|
drop_: u32,
|
||||||
|
return_: u32,
|
||||||
|
unreachable: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExprIds {
|
||||||
|
fn get() -> Self {
|
||||||
|
Self {
|
||||||
|
nop: unsafe { BinaryenNopId() },
|
||||||
|
block: unsafe { BinaryenBlockId() },
|
||||||
|
if_: unsafe { BinaryenIfId() },
|
||||||
|
loop_: unsafe { BinaryenLoopId() },
|
||||||
|
break_: unsafe { BinaryenBreakId() },
|
||||||
|
switch: unsafe { BinaryenSwitchId() },
|
||||||
|
call: unsafe { BinaryenCallId() },
|
||||||
|
call_indirect: unsafe { BinaryenCallIndirectId() },
|
||||||
|
local_get: unsafe { BinaryenLocalGetId() },
|
||||||
|
local_set: unsafe { BinaryenLocalSetId() },
|
||||||
|
global_get: unsafe { BinaryenGlobalGetId() },
|
||||||
|
global_set: unsafe { BinaryenGlobalSetId() },
|
||||||
|
table_get: unsafe { BinaryenTableGetId() },
|
||||||
|
table_set: unsafe { BinaryenTableSetId() },
|
||||||
|
load: unsafe { BinaryenLoadId() },
|
||||||
|
store: unsafe { BinaryenStoreId() },
|
||||||
|
const_: unsafe { BinaryenConstId() },
|
||||||
|
unary: unsafe { BinaryenUnaryId() },
|
||||||
|
binary: unsafe { BinaryenBinaryId() },
|
||||||
|
select: unsafe { BinaryenSelectId() },
|
||||||
|
drop_: unsafe { BinaryenDropId() },
|
||||||
|
return_: unsafe { BinaryenReturnId() },
|
||||||
|
unreachable: unsafe { BinaryenUnreachableId() },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref EXPR_IDS: ExprIds = ExprIds::get();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TypeIds {
|
||||||
|
none_t: u32,
|
||||||
|
i32_t: u32,
|
||||||
|
i64_t: u32,
|
||||||
|
f32_t: u32,
|
||||||
|
f64_t: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeIds {
|
||||||
|
fn get() -> Self {
|
||||||
|
TypeIds {
|
||||||
|
none_t: unsafe { BinaryenTypeNone() },
|
||||||
|
i32_t: unsafe { BinaryenTypeInt32() },
|
||||||
|
i64_t: unsafe { BinaryenTypeInt64() },
|
||||||
|
f32_t: unsafe { BinaryenTypeFloat32() },
|
||||||
|
f64_t: unsafe { BinaryenTypeFloat64() },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref TYPE_IDS: TypeIds = TypeIds::get();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub enum Type {
|
||||||
|
None,
|
||||||
|
I32,
|
||||||
|
I64,
|
||||||
|
F32,
|
||||||
|
F64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Type {
|
||||||
|
fn from_kind(kind: u32) -> Option<Type> {
|
||||||
|
let tys = &*TYPE_IDS;
|
||||||
|
if kind == tys.none_t {
|
||||||
|
Some(Type::None)
|
||||||
|
} else if kind == tys.i32_t {
|
||||||
|
Some(Type::I32)
|
||||||
|
} else if kind == tys.i64_t {
|
||||||
|
Some(Type::I64)
|
||||||
|
} else if kind == tys.f32_t {
|
||||||
|
Some(Type::F32)
|
||||||
|
} else if kind == tys.f64_t {
|
||||||
|
Some(Type::F64)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_kind(&self) -> u32 {
|
||||||
|
let tys = &*TYPE_IDS;
|
||||||
|
match self {
|
||||||
|
&Type::None => tys.none_t,
|
||||||
|
&Type::I32 => tys.i32_t,
|
||||||
|
&Type::I64 => tys.i64_t,
|
||||||
|
&Type::F32 => tys.f32_t,
|
||||||
|
&Type::F64 => tys.f64_t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name_to_string(name: *const c_char) -> Option<String> {
|
||||||
|
if name.is_null() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(unsafe { CStr::from_ptr(name).to_str().unwrap().to_string() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
Type::from_kind(unsafe { BinaryenExpressionGetType(self.1) }).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deep_clone(&self) -> Self {
|
||||||
|
Expression(self.0, unsafe { BinaryenExpressionCopy(self.0, self.1) })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn module(&self) -> BinaryenModule {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum UnaryOp {
|
||||||
|
Other(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum BinaryOp {
|
||||||
|
I32Add,
|
||||||
|
I32Sub,
|
||||||
|
I32Shl,
|
||||||
|
I32ShrU,
|
||||||
|
I32ShrS,
|
||||||
|
Other(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
struct OpIds {
|
||||||
|
i32_add: u32,
|
||||||
|
i32_sub: u32,
|
||||||
|
i32_shl: u32,
|
||||||
|
i32_shr_u: u32,
|
||||||
|
i32_shr_s: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OpIds {
|
||||||
|
fn get() -> Self {
|
||||||
|
OpIds {
|
||||||
|
i32_add: unsafe { BinaryenAddInt32() },
|
||||||
|
i32_sub: unsafe { BinaryenSubInt32() },
|
||||||
|
i32_shl: unsafe { BinaryenShlInt32() },
|
||||||
|
i32_shr_u: unsafe { BinaryenShrUInt32() },
|
||||||
|
i32_shr_s: unsafe { BinaryenShrSInt32() },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref OP_IDS: OpIds = OpIds::get();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UnaryOp {
|
||||||
|
fn from_kind(kind: u32) -> UnaryOp {
|
||||||
|
UnaryOp::Other(kind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BinaryOp {
|
||||||
|
fn from_kind(kind: u32) -> BinaryOp {
|
||||||
|
let ids = &*OP_IDS;
|
||||||
|
if kind == ids.i32_add {
|
||||||
|
BinaryOp::I32Add
|
||||||
|
} else if kind == ids.i32_sub {
|
||||||
|
BinaryOp::I32Sub
|
||||||
|
} else if kind == ids.i32_shl {
|
||||||
|
BinaryOp::I32Shl
|
||||||
|
} else if kind == ids.i32_shr_s {
|
||||||
|
BinaryOp::I32ShrS
|
||||||
|
} else if kind == ids.i32_shr_u {
|
||||||
|
BinaryOp::I32ShrU
|
||||||
|
} else {
|
||||||
|
BinaryOp::Other(kind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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)]
|
||||||
|
pub enum Value {
|
||||||
|
I32(i32),
|
||||||
|
I64(i64),
|
||||||
|
F32(u32),
|
||||||
|
F64(u64),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type BinaryenModule = *const c_void;
|
||||||
|
type BinaryenFunction = *const c_void;
|
||||||
|
type BinaryenExpression = *const c_void;
|
||||||
|
type BinaryenExport = *const c_void;
|
||||||
|
|
||||||
|
#[link(name = "binaryen")]
|
||||||
|
extern "C" {
|
||||||
|
fn BinaryenModuleRead(data: *const u8, len: usize) -> BinaryenModule;
|
||||||
|
fn BinaryenModuleDispose(ptr: BinaryenModule);
|
||||||
|
fn BinaryenGetNumFunctions(ptr: BinaryenModule) -> u32;
|
||||||
|
fn BinaryenGetFunctionByIndex(ptr: BinaryenModule, index: u32) -> BinaryenFunction;
|
||||||
|
fn BinaryenGetFunction(ptr: BinaryenModule, name: *const c_char) -> BinaryenFunction;
|
||||||
|
fn BinaryenFunctionGetBody(ptr: BinaryenFunction) -> BinaryenExpression;
|
||||||
|
fn BinaryenFunctionGetName(ptr: BinaryenFunction) -> *const c_char;
|
||||||
|
fn BinaryenGetExport(ptr: BinaryenModule, name: *const c_char) -> BinaryenExport;
|
||||||
|
fn BinaryenGetNumExports(ptr: BinaryenModule) -> u32;
|
||||||
|
fn BinaryenGetExportByIndex(ptr: BinaryenModule, index: u32) -> BinaryenExport;
|
||||||
|
fn BinaryenExportGetName(ptr: BinaryenFunction) -> *const c_char;
|
||||||
|
fn BinaryenExportGetValue(ptr: BinaryenFunction) -> *const c_char;
|
||||||
|
fn BinaryenExportGetKind(ptr: BinaryenFunction) -> u32;
|
||||||
|
fn BinaryenExternalFunction() -> u32;
|
||||||
|
|
||||||
|
fn BinaryenExpressionGetId(ptr: BinaryenExpression) -> u32;
|
||||||
|
fn BinaryenExpressionGetType(ptr: BinaryenExpression) -> u32;
|
||||||
|
fn BinaryenExpressionCopy(
|
||||||
|
ptr: BinaryenExpression,
|
||||||
|
module: BinaryenModule,
|
||||||
|
) -> BinaryenExpression;
|
||||||
|
|
||||||
|
fn BinaryenConstGetValueI32(ptr: BinaryenExpression) -> i32;
|
||||||
|
fn BinaryenConstGetValueI64(ptr: BinaryenExpression) -> i64;
|
||||||
|
fn BinaryenConstGetValueF32(ptr: BinaryenExpression) -> f32;
|
||||||
|
fn BinaryenConstGetValueF64(ptr: BinaryenExpression) -> f64;
|
||||||
|
|
||||||
|
fn BinaryenBlockGetNumChildren(ptr: BinaryenExpression) -> u32;
|
||||||
|
fn BinaryenBlockGetChildAt(ptr: BinaryenExpression, index: u32) -> BinaryenExpression;
|
||||||
|
fn BinaryenBlockGetName(ptr: BinaryenExpression) -> *const c_char;
|
||||||
|
|
||||||
|
fn BinaryenLoopGetBody(ptr: BinaryenExpression) -> BinaryenExpression;
|
||||||
|
fn BinaryenLoopGetName(ptr: BinaryenExpression) -> *const c_char;
|
||||||
|
|
||||||
|
fn BinaryenIfGetCondition(ptr: BinaryenExpression) -> BinaryenExpression;
|
||||||
|
fn BinaryenIfGetIfTrue(ptr: BinaryenExpression) -> BinaryenExpression;
|
||||||
|
fn BinaryenIfGetIfFalse(ptr: BinaryenExpression) -> BinaryenExpression;
|
||||||
|
|
||||||
|
fn BinaryenBreakGetName(ptr: BinaryenExpression) -> *const c_char;
|
||||||
|
fn BinaryenBreakGetValue(ptr: BinaryenExpression) -> BinaryenExpression;
|
||||||
|
|
||||||
|
fn BinaryenDropGetValue(ptr: BinaryenExpression) -> BinaryenExpression;
|
||||||
|
|
||||||
|
fn BinaryenSwitchGetNumNames(ptr: BinaryenExpression) -> u32;
|
||||||
|
fn BinaryenSwitchGetNameAt(ptr: BinaryenExpression, index: u32) -> *const c_char;
|
||||||
|
fn BinaryenSwitchGetDefaultName(ptr: BinaryenExpression) -> *const c_char;
|
||||||
|
fn BinaryenSwitchGetCondition(ptr: BinaryenExpression) -> BinaryenExpression;
|
||||||
|
fn BinaryenSwitchGetValue(ptr: BinaryenExpression) -> BinaryenExpression;
|
||||||
|
|
||||||
|
fn BinaryenCallGetTarget(ptr: BinaryenExpression) -> *const c_char;
|
||||||
|
fn BinaryenCallGetNumOperands(ptr: BinaryenExpression) -> u32;
|
||||||
|
fn BinaryenCallGetOperandAt(ptr: BinaryenExpression, index: u32) -> BinaryenExpression;
|
||||||
|
|
||||||
|
fn BinaryenCallIndirectGetTarget(ptr: BinaryenExpression) -> BinaryenExpression;
|
||||||
|
fn BinaryenCallIndirectGetNumOperands(ptr: BinaryenExpression) -> u32;
|
||||||
|
fn BinaryenCallIndirectGetOperandAt(ptr: BinaryenExpression, index: u32) -> BinaryenExpression;
|
||||||
|
|
||||||
|
fn BinaryenLocalGetGetIndex(ptr: BinaryenExpression) -> u32;
|
||||||
|
fn BinaryenLocalSetGetIndex(ptr: BinaryenExpression) -> u32;
|
||||||
|
fn BinaryenLocalSetGetValue(ptr: BinaryenExpression) -> BinaryenExpression;
|
||||||
|
fn BinaryenGlobalGetGetName(ptr: BinaryenExpression) -> *const c_char;
|
||||||
|
fn BinaryenGlobalSetGetName(ptr: BinaryenExpression) -> *const c_char;
|
||||||
|
fn BinaryenGlobalSetGetValue(ptr: BinaryenExpression) -> BinaryenExpression;
|
||||||
|
fn BinaryenTableGetGetTable(ptr: BinaryenExpression) -> *const c_char;
|
||||||
|
fn BinaryenTableGetGetIndex(ptr: BinaryenExpression) -> BinaryenExpression;
|
||||||
|
fn BinaryenTableSetGetTable(ptr: BinaryenExpression) -> *const c_char;
|
||||||
|
fn BinaryenTableSetGetIndex(ptr: BinaryenExpression) -> BinaryenExpression;
|
||||||
|
fn BinaryenTableSetGetValue(ptr: BinaryenExpression) -> BinaryenExpression;
|
||||||
|
|
||||||
|
fn BinaryenLoadGetPtr(ptr: BinaryenExpression) -> BinaryenExpression;
|
||||||
|
fn BinaryenLoadGetOffset(ptr: BinaryenExpression) -> u32;
|
||||||
|
fn BinaryenStoreGetPtr(ptr: BinaryenExpression) -> BinaryenExpression;
|
||||||
|
fn BinaryenStoreGetValue(ptr: BinaryenExpression) -> BinaryenExpression;
|
||||||
|
fn BinaryenStoreGetOffset(ptr: BinaryenExpression) -> u32;
|
||||||
|
|
||||||
|
fn BinaryenUnaryGetOp(ptr: BinaryenExpression) -> u32;
|
||||||
|
fn BinaryenUnaryGetValue(ptr: BinaryenExpression) -> BinaryenExpression;
|
||||||
|
|
||||||
|
fn BinaryenBinaryGetOp(ptr: BinaryenExpression) -> u32;
|
||||||
|
fn BinaryenBinaryGetLeft(ptr: BinaryenExpression) -> BinaryenExpression;
|
||||||
|
fn BinaryenBinaryGetRight(ptr: BinaryenExpression) -> BinaryenExpression;
|
||||||
|
|
||||||
|
fn BinaryenSelectGetIfTrue(ptr: BinaryenExpression) -> BinaryenExpression;
|
||||||
|
fn BinaryenSelectGetIfFalse(ptr: BinaryenExpression) -> BinaryenExpression;
|
||||||
|
fn BinaryenSelectGetCondition(ptr: BinaryenExpression) -> BinaryenExpression;
|
||||||
|
|
||||||
|
fn BinaryenReturnGetValue(ptr: BinaryenExpression) -> BinaryenExpression;
|
||||||
|
|
||||||
|
fn BinaryenGetNumMemorySegments(module: BinaryenModule) -> u32;
|
||||||
|
fn BinaryenGetMemorySegmentByteOffset(module: BinaryenModule, index: u32) -> u32;
|
||||||
|
fn BinaryenGetMemorySegmentByteLength(module: BinaryenModule, index: u32) -> usize;
|
||||||
|
fn BinaryenCopyMemorySegmentData(module: BinaryenModule, index: u32, buffer: *mut u8);
|
||||||
|
|
||||||
|
fn BinaryenNopId() -> u32;
|
||||||
|
fn BinaryenBlockId() -> u32;
|
||||||
|
fn BinaryenIfId() -> u32;
|
||||||
|
fn BinaryenLoopId() -> u32;
|
||||||
|
fn BinaryenBreakId() -> u32;
|
||||||
|
fn BinaryenSwitchId() -> u32;
|
||||||
|
fn BinaryenCallId() -> u32;
|
||||||
|
fn BinaryenCallIndirectId() -> u32;
|
||||||
|
fn BinaryenLocalGetId() -> u32;
|
||||||
|
fn BinaryenLocalSetId() -> u32;
|
||||||
|
fn BinaryenGlobalGetId() -> u32;
|
||||||
|
fn BinaryenGlobalSetId() -> u32;
|
||||||
|
fn BinaryenTableGetId() -> u32;
|
||||||
|
fn BinaryenTableSetId() -> u32;
|
||||||
|
fn BinaryenLoadId() -> u32;
|
||||||
|
fn BinaryenStoreId() -> u32;
|
||||||
|
fn BinaryenConstId() -> u32;
|
||||||
|
fn BinaryenUnaryId() -> u32;
|
||||||
|
fn BinaryenBinaryId() -> u32;
|
||||||
|
fn BinaryenSelectId() -> u32;
|
||||||
|
fn BinaryenDropId() -> u32;
|
||||||
|
fn BinaryenReturnId() -> u32;
|
||||||
|
fn BinaryenMemorySizeId() -> u32;
|
||||||
|
fn BinaryenMemoryGrowId() -> u32;
|
||||||
|
fn BinaryenUnreachableId() -> u32;
|
||||||
|
fn BinaryenPopId() -> u32;
|
||||||
|
|
||||||
|
fn BinaryenTypeNone() -> u32;
|
||||||
|
fn BinaryenTypeInt32() -> u32;
|
||||||
|
fn BinaryenTypeInt64() -> u32;
|
||||||
|
fn BinaryenTypeFloat32() -> u32;
|
||||||
|
fn BinaryenTypeFloat64() -> u32;
|
||||||
|
|
||||||
|
fn BinaryenAddInt32() -> u32;
|
||||||
|
fn BinaryenSubInt32() -> u32;
|
||||||
|
fn BinaryenShlInt32() -> u32;
|
||||||
|
fn BinaryenShrUInt32() -> u32;
|
||||||
|
fn BinaryenShrSInt32() -> u32;
|
||||||
|
|
||||||
|
fn BinaryenConst(module: BinaryenModule, lit: BinaryenLiteral) -> BinaryenExpression;
|
||||||
|
fn BinaryenLocalSet(
|
||||||
|
module: BinaryenModule,
|
||||||
|
index: u32,
|
||||||
|
value: BinaryenExpression,
|
||||||
|
) -> BinaryenExpression;
|
||||||
|
|
||||||
|
fn BinaryenLiteralInt32(x: i32) -> BinaryenLiteral;
|
||||||
|
fn BinaryenLiteralInt64(x: i64) -> BinaryenLiteral;
|
||||||
|
fn BinaryenLiteralFloat32Bits(x: i32) -> BinaryenLiteral;
|
||||||
|
fn BinaryenLiteralFloat64Bits(x: i64) -> BinaryenLiteral;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct BinaryenLiteral {
|
||||||
|
_pad0: usize,
|
||||||
|
_pad1: [u8; 16],
|
||||||
|
}
|
|
@ -1,11 +1,4 @@
|
||||||
//! Backend: IR to Wasm.
|
//! Backend: IR to Wasm.
|
||||||
|
|
||||||
mod structured;
|
mod binaryen;
|
||||||
pub use structured::*;
|
pub use binaryen::*;
|
||||||
mod serialize;
|
|
||||||
pub use serialize::*;
|
|
||||||
mod locations;
|
|
||||||
pub use locations::*;
|
|
||||||
mod r#final;
|
|
||||||
pub use r#final::*;
|
|
||||||
|
|
||||||
|
|
142
src/ir.rs
142
src/ir.rs
|
@ -1,15 +1,8 @@
|
||||||
//! Intermediate representation for Wasm.
|
//! Intermediate representation for Wasm.
|
||||||
|
|
||||||
use crate::{
|
use crate::{frontend, Operator};
|
||||||
backend::{produce_func_wasm, BlockOrder, Locations, LoopNest, SerializedBody, WasmRegion},
|
|
||||||
cfg::CFGInfo,
|
|
||||||
frontend,
|
|
||||||
ops::ty_to_valty,
|
|
||||||
Operator,
|
|
||||||
};
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use rayon::prelude::*;
|
use wasmparser::{FuncType, Type};
|
||||||
use wasmparser::{FuncType, SectionReader, Type};
|
|
||||||
|
|
||||||
pub type SignatureId = usize;
|
pub type SignatureId = usize;
|
||||||
pub type FuncId = usize;
|
pub type FuncId = usize;
|
||||||
|
@ -465,135 +458,6 @@ impl<'a> Module<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_wasm_bytes(&self) -> Vec<u8> {
|
pub fn to_wasm_bytes(&self) -> Vec<u8> {
|
||||||
// Do most of the compilation in parallel: up to the
|
todo!("use Binaryen")
|
||||||
// generation of the function that we emit into the final code
|
|
||||||
// seciton in order. Only the "final parts assembly" needs to
|
|
||||||
// be serialized.
|
|
||||||
let compiled: Vec<(u32, wasm_encoder::Function)> = self
|
|
||||||
.funcs
|
|
||||||
.par_iter()
|
|
||||||
.filter_map(|func| match func {
|
|
||||||
&FuncDecl::Body(sig, ref body) => {
|
|
||||||
let cfg = CFGInfo::new(body);
|
|
||||||
let loopnest = LoopNest::compute(&cfg);
|
|
||||||
let regions = WasmRegion::compute(&cfg, &loopnest);
|
|
||||||
let blockorder = BlockOrder::compute(body, &cfg, ®ions);
|
|
||||||
let serialized = SerializedBody::compute(body, &cfg, &blockorder);
|
|
||||||
log::trace!("serialized: {:?}", serialized);
|
|
||||||
let locations = Locations::compute(body, &serialized);
|
|
||||||
log::trace!("locations: {:?}", locations);
|
|
||||||
let func_body = produce_func_wasm(body, &serialized, &locations);
|
|
||||||
log::trace!("body: {:?}", func_body);
|
|
||||||
|
|
||||||
let mut locals: Vec<(u32, wasm_encoder::ValType)> = vec![];
|
|
||||||
for local_ty in func_body.locals {
|
|
||||||
if locals.len() > 0 && locals.last().unwrap().1 == local_ty {
|
|
||||||
locals.last_mut().unwrap().0 += 1;
|
|
||||||
} else {
|
|
||||||
locals.push((1, local_ty));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let mut func = wasm_encoder::Function::new(locals);
|
|
||||||
|
|
||||||
for inst in func_body.operators {
|
|
||||||
func.instruction(&inst);
|
|
||||||
}
|
|
||||||
|
|
||||||
Some((sig as u32, func))
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// Build the final code section and function-type section.
|
|
||||||
let mut code_section = wasm_encoder::CodeSection::new();
|
|
||||||
let mut func_section = wasm_encoder::FunctionSection::new();
|
|
||||||
for (sig, func) in compiled {
|
|
||||||
func_section.function(sig as u32);
|
|
||||||
code_section.function(&func);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the final function-signature (type) section.
|
|
||||||
let mut type_section = wasm_encoder::TypeSection::new();
|
|
||||||
for sig in &self.signatures {
|
|
||||||
let params: Vec<wasm_encoder::ValType> =
|
|
||||||
sig.params.iter().map(|&ty| ty_to_valty(ty)).collect();
|
|
||||||
let returns: Vec<wasm_encoder::ValType> =
|
|
||||||
sig.returns.iter().map(|&ty| ty_to_valty(ty)).collect();
|
|
||||||
type_section.function(params, returns);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now do a final pass over the original bytes with
|
|
||||||
// wasmparser, replacing the type section, function section,
|
|
||||||
// and code section. (TODO: allow new imports to be added
|
|
||||||
// too?)
|
|
||||||
let parser = wasmparser::Parser::new(0);
|
|
||||||
let mut module = wasm_encoder::Module::new();
|
|
||||||
for payload in parser.parse_all(self.orig_bytes) {
|
|
||||||
match payload.unwrap() {
|
|
||||||
wasmparser::Payload::TypeSection(..) => {
|
|
||||||
module.section(&type_section);
|
|
||||||
}
|
|
||||||
wasmparser::Payload::FunctionSection(..) => {
|
|
||||||
module.section(&func_section);
|
|
||||||
}
|
|
||||||
wasmparser::Payload::CodeSectionStart { .. } => {
|
|
||||||
module.section(&code_section);
|
|
||||||
}
|
|
||||||
wasmparser::Payload::CodeSectionEntry(..) => {}
|
|
||||||
wasmparser::Payload::ImportSection(reader) => {
|
|
||||||
let range = reader.range();
|
|
||||||
let bytes = &self.orig_bytes[range.start..range.end];
|
|
||||||
module.section(&wasm_encoder::RawSection { id: 2, data: bytes });
|
|
||||||
}
|
|
||||||
wasmparser::Payload::TableSection(reader) => {
|
|
||||||
let range = reader.range();
|
|
||||||
let bytes = &self.orig_bytes[range.start..range.end];
|
|
||||||
module.section(&wasm_encoder::RawSection { id: 4, data: bytes });
|
|
||||||
}
|
|
||||||
wasmparser::Payload::MemorySection(reader) => {
|
|
||||||
let range = reader.range();
|
|
||||||
let bytes = &self.orig_bytes[range.start..range.end];
|
|
||||||
module.section(&wasm_encoder::RawSection { id: 5, data: bytes });
|
|
||||||
}
|
|
||||||
wasmparser::Payload::GlobalSection(reader) => {
|
|
||||||
let range = reader.range();
|
|
||||||
let bytes = &self.orig_bytes[range.start..range.end];
|
|
||||||
module.section(&wasm_encoder::RawSection { id: 6, data: bytes });
|
|
||||||
}
|
|
||||||
wasmparser::Payload::ExportSection(reader) => {
|
|
||||||
let range = reader.range();
|
|
||||||
let bytes = &self.orig_bytes[range.start..range.end];
|
|
||||||
module.section(&wasm_encoder::RawSection { id: 7, data: bytes });
|
|
||||||
}
|
|
||||||
wasmparser::Payload::StartSection { range, .. } => {
|
|
||||||
let bytes = &self.orig_bytes[range.start..range.end];
|
|
||||||
module.section(&wasm_encoder::RawSection { id: 8, data: bytes });
|
|
||||||
}
|
|
||||||
wasmparser::Payload::ElementSection(reader) => {
|
|
||||||
let range = reader.range();
|
|
||||||
let bytes = &self.orig_bytes[range.start..range.end];
|
|
||||||
module.section(&wasm_encoder::RawSection { id: 9, data: bytes });
|
|
||||||
}
|
|
||||||
wasmparser::Payload::DataSection(reader) => {
|
|
||||||
let range = reader.range();
|
|
||||||
let bytes = &self.orig_bytes[range.start..range.end];
|
|
||||||
module.section(&wasm_encoder::RawSection {
|
|
||||||
id: 11,
|
|
||||||
data: bytes,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
wasmparser::Payload::DataCountSection { range, .. } => {
|
|
||||||
let bytes = &self.orig_bytes[range.start..range.end];
|
|
||||||
module.section(&wasm_encoder::RawSection {
|
|
||||||
id: 12,
|
|
||||||
data: bytes,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.finish()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,7 @@
|
||||||
|
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
// Re-export wasmparser and wasmencoder for easier use of the right
|
// Re-export wasmparser for easier use of the right version by our embedders.
|
||||||
// version by our embedders.
|
|
||||||
pub use wasm_encoder;
|
|
||||||
pub use wasmparser;
|
pub use wasmparser;
|
||||||
|
|
||||||
mod backend;
|
mod backend;
|
||||||
|
|
243
src/ops.rs
243
src/ops.rs
|
@ -468,229 +468,6 @@ impl<'a, 'b> std::convert::TryFrom<&'b wasmparser::Operator<'a>> for Operator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> std::convert::Into<wasm_encoder::Instruction<'static>> for Operator {
|
|
||||||
fn into(self) -> wasm_encoder::Instruction<'static> {
|
|
||||||
match &self {
|
|
||||||
&Operator::Unreachable => wasm_encoder::Instruction::Unreachable,
|
|
||||||
&Operator::Nop => wasm_encoder::Instruction::Nop,
|
|
||||||
&Operator::Call { function_index } => {
|
|
||||||
wasm_encoder::Instruction::Call(function_index as u32)
|
|
||||||
}
|
|
||||||
&Operator::CallIndirect { index, table_index } => {
|
|
||||||
wasm_encoder::Instruction::CallIndirect {
|
|
||||||
ty: index as u32,
|
|
||||||
table: table_index as u32,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&Operator::Return => wasm_encoder::Instruction::Return,
|
|
||||||
&Operator::LocalSet { local_index } => wasm_encoder::Instruction::LocalSet(local_index),
|
|
||||||
&Operator::LocalTee { local_index } => wasm_encoder::Instruction::LocalTee(local_index),
|
|
||||||
&Operator::LocalGet { local_index } => wasm_encoder::Instruction::LocalGet(local_index),
|
|
||||||
&Operator::Select => wasm_encoder::Instruction::Select,
|
|
||||||
&Operator::TypedSelect { ty } => {
|
|
||||||
wasm_encoder::Instruction::TypedSelect(ty_to_valty(ty))
|
|
||||||
}
|
|
||||||
&Operator::GlobalGet { global_index } => {
|
|
||||||
wasm_encoder::Instruction::GlobalGet(global_index)
|
|
||||||
}
|
|
||||||
&Operator::GlobalSet { global_index } => {
|
|
||||||
wasm_encoder::Instruction::GlobalSet(global_index)
|
|
||||||
}
|
|
||||||
&Operator::I32Load { memory } => wasm_encoder::Instruction::I32Load(memory.into()),
|
|
||||||
&Operator::I64Load { memory } => wasm_encoder::Instruction::I64Load(memory.into()),
|
|
||||||
&Operator::F32Load { memory } => wasm_encoder::Instruction::F32Load(memory.into()),
|
|
||||||
&Operator::F64Load { memory } => wasm_encoder::Instruction::F64Load(memory.into()),
|
|
||||||
&Operator::I32Load8S { memory } => wasm_encoder::Instruction::I32Load8_S(memory.into()),
|
|
||||||
&Operator::I32Load8U { memory } => wasm_encoder::Instruction::I32Load8_U(memory.into()),
|
|
||||||
&Operator::I32Load16S { memory } => {
|
|
||||||
wasm_encoder::Instruction::I32Load16_S(memory.into())
|
|
||||||
}
|
|
||||||
&Operator::I32Load16U { memory } => {
|
|
||||||
wasm_encoder::Instruction::I32Load16_U(memory.into())
|
|
||||||
}
|
|
||||||
&Operator::I64Load8S { memory } => wasm_encoder::Instruction::I64Load8_S(memory.into()),
|
|
||||||
&Operator::I64Load8U { memory } => wasm_encoder::Instruction::I64Load8_U(memory.into()),
|
|
||||||
&Operator::I64Load16S { memory } => {
|
|
||||||
wasm_encoder::Instruction::I64Load16_S(memory.into())
|
|
||||||
}
|
|
||||||
&Operator::I64Load16U { memory } => {
|
|
||||||
wasm_encoder::Instruction::I64Load16_U(memory.into())
|
|
||||||
}
|
|
||||||
&Operator::I64Load32S { memory } => {
|
|
||||||
wasm_encoder::Instruction::I64Load32_S(memory.into())
|
|
||||||
}
|
|
||||||
&Operator::I64Load32U { memory } => {
|
|
||||||
wasm_encoder::Instruction::I64Load32_U(memory.into())
|
|
||||||
}
|
|
||||||
&Operator::I32Store { memory } => wasm_encoder::Instruction::I32Store(memory.into()),
|
|
||||||
&Operator::I64Store { memory } => wasm_encoder::Instruction::I64Store(memory.into()),
|
|
||||||
&Operator::F32Store { memory } => wasm_encoder::Instruction::F32Store(memory.into()),
|
|
||||||
&Operator::F64Store { memory } => wasm_encoder::Instruction::F64Store(memory.into()),
|
|
||||||
&Operator::I32Store8 { memory } => wasm_encoder::Instruction::I32Store8(memory.into()),
|
|
||||||
&Operator::I32Store16 { memory } => {
|
|
||||||
wasm_encoder::Instruction::I32Store16(memory.into())
|
|
||||||
}
|
|
||||||
&Operator::I64Store8 { memory } => wasm_encoder::Instruction::I64Store8(memory.into()),
|
|
||||||
&Operator::I64Store16 { memory } => {
|
|
||||||
wasm_encoder::Instruction::I64Store16(memory.into())
|
|
||||||
}
|
|
||||||
&Operator::I64Store32 { memory } => {
|
|
||||||
wasm_encoder::Instruction::I64Store32(memory.into())
|
|
||||||
}
|
|
||||||
&Operator::I32Const { value } => wasm_encoder::Instruction::I32Const(value),
|
|
||||||
&Operator::I64Const { value } => wasm_encoder::Instruction::I64Const(value),
|
|
||||||
&Operator::F32Const { value } => {
|
|
||||||
wasm_encoder::Instruction::F32Const(f32::from_bits(value.bits()))
|
|
||||||
}
|
|
||||||
&Operator::F64Const { value } => {
|
|
||||||
wasm_encoder::Instruction::F64Const(f64::from_bits(value.bits()))
|
|
||||||
}
|
|
||||||
&Operator::I32Eqz => wasm_encoder::Instruction::I32Eqz,
|
|
||||||
&Operator::I32Eq => wasm_encoder::Instruction::I32Eq,
|
|
||||||
&Operator::I32Ne => wasm_encoder::Instruction::I32Neq,
|
|
||||||
&Operator::I32LtS => wasm_encoder::Instruction::I32LtS,
|
|
||||||
&Operator::I32LtU => wasm_encoder::Instruction::I32LtU,
|
|
||||||
&Operator::I32GtS => wasm_encoder::Instruction::I32GtS,
|
|
||||||
&Operator::I32GtU => wasm_encoder::Instruction::I32GtU,
|
|
||||||
&Operator::I32LeS => wasm_encoder::Instruction::I32LeS,
|
|
||||||
&Operator::I32LeU => wasm_encoder::Instruction::I32LeU,
|
|
||||||
&Operator::I32GeS => wasm_encoder::Instruction::I32GeS,
|
|
||||||
&Operator::I32GeU => wasm_encoder::Instruction::I32GeU,
|
|
||||||
&Operator::I64Eqz => wasm_encoder::Instruction::I64Eqz,
|
|
||||||
&Operator::I64Eq => wasm_encoder::Instruction::I64Eq,
|
|
||||||
&Operator::I64Ne => wasm_encoder::Instruction::I64Neq,
|
|
||||||
&Operator::I64LtS => wasm_encoder::Instruction::I64LtS,
|
|
||||||
&Operator::I64LtU => wasm_encoder::Instruction::I64LtU,
|
|
||||||
&Operator::I64GtU => wasm_encoder::Instruction::I64GtU,
|
|
||||||
&Operator::I64GtS => wasm_encoder::Instruction::I64GtS,
|
|
||||||
&Operator::I64LeS => wasm_encoder::Instruction::I64LeS,
|
|
||||||
&Operator::I64LeU => wasm_encoder::Instruction::I64LeU,
|
|
||||||
&Operator::I64GeS => wasm_encoder::Instruction::I64GeS,
|
|
||||||
&Operator::I64GeU => wasm_encoder::Instruction::I64GeU,
|
|
||||||
&Operator::F32Eq => wasm_encoder::Instruction::F32Eq,
|
|
||||||
&Operator::F32Ne => wasm_encoder::Instruction::F32Neq,
|
|
||||||
&Operator::F32Lt => wasm_encoder::Instruction::F32Lt,
|
|
||||||
&Operator::F32Gt => wasm_encoder::Instruction::F32Gt,
|
|
||||||
&Operator::F32Le => wasm_encoder::Instruction::F32Le,
|
|
||||||
&Operator::F32Ge => wasm_encoder::Instruction::F32Ge,
|
|
||||||
&Operator::F64Eq => wasm_encoder::Instruction::F64Eq,
|
|
||||||
&Operator::F64Ne => wasm_encoder::Instruction::F64Neq,
|
|
||||||
&Operator::F64Lt => wasm_encoder::Instruction::F64Lt,
|
|
||||||
&Operator::F64Gt => wasm_encoder::Instruction::F64Gt,
|
|
||||||
&Operator::F64Le => wasm_encoder::Instruction::F64Le,
|
|
||||||
&Operator::F64Ge => wasm_encoder::Instruction::F64Ge,
|
|
||||||
&Operator::I32Clz => wasm_encoder::Instruction::I32Clz,
|
|
||||||
&Operator::I32Ctz => wasm_encoder::Instruction::I32Ctz,
|
|
||||||
&Operator::I32Popcnt => wasm_encoder::Instruction::I32Popcnt,
|
|
||||||
&Operator::I32Add => wasm_encoder::Instruction::I32Add,
|
|
||||||
&Operator::I32Sub => wasm_encoder::Instruction::I32Sub,
|
|
||||||
&Operator::I32Mul => wasm_encoder::Instruction::I32Mul,
|
|
||||||
&Operator::I32DivS => wasm_encoder::Instruction::I32DivS,
|
|
||||||
&Operator::I32DivU => wasm_encoder::Instruction::I32DivU,
|
|
||||||
&Operator::I32RemS => wasm_encoder::Instruction::I32RemS,
|
|
||||||
&Operator::I32RemU => wasm_encoder::Instruction::I32RemU,
|
|
||||||
&Operator::I32And => wasm_encoder::Instruction::I32And,
|
|
||||||
&Operator::I32Or => wasm_encoder::Instruction::I32Or,
|
|
||||||
&Operator::I32Xor => wasm_encoder::Instruction::I32Xor,
|
|
||||||
&Operator::I32Shl => wasm_encoder::Instruction::I32Shl,
|
|
||||||
&Operator::I32ShrS => wasm_encoder::Instruction::I32ShrS,
|
|
||||||
&Operator::I32ShrU => wasm_encoder::Instruction::I32ShrU,
|
|
||||||
&Operator::I32Rotl => wasm_encoder::Instruction::I32Rotl,
|
|
||||||
&Operator::I32Rotr => wasm_encoder::Instruction::I32Rotr,
|
|
||||||
&Operator::I64Clz => wasm_encoder::Instruction::I64Clz,
|
|
||||||
&Operator::I64Ctz => wasm_encoder::Instruction::I64Ctz,
|
|
||||||
&Operator::I64Popcnt => wasm_encoder::Instruction::I64Popcnt,
|
|
||||||
&Operator::I64Add => wasm_encoder::Instruction::I64Add,
|
|
||||||
&Operator::I64Sub => wasm_encoder::Instruction::I64Sub,
|
|
||||||
&Operator::I64Mul => wasm_encoder::Instruction::I64Mul,
|
|
||||||
&Operator::I64DivS => wasm_encoder::Instruction::I64DivS,
|
|
||||||
&Operator::I64DivU => wasm_encoder::Instruction::I64DivU,
|
|
||||||
&Operator::I64RemS => wasm_encoder::Instruction::I64RemS,
|
|
||||||
&Operator::I64RemU => wasm_encoder::Instruction::I64RemU,
|
|
||||||
&Operator::I64And => wasm_encoder::Instruction::I64And,
|
|
||||||
&Operator::I64Or => wasm_encoder::Instruction::I64Or,
|
|
||||||
&Operator::I64Xor => wasm_encoder::Instruction::I64Xor,
|
|
||||||
&Operator::I64Shl => wasm_encoder::Instruction::I64Shl,
|
|
||||||
&Operator::I64ShrS => wasm_encoder::Instruction::I64ShrS,
|
|
||||||
&Operator::I64ShrU => wasm_encoder::Instruction::I64ShrU,
|
|
||||||
&Operator::I64Rotl => wasm_encoder::Instruction::I64Rotl,
|
|
||||||
&Operator::I64Rotr => wasm_encoder::Instruction::I64Rotr,
|
|
||||||
&Operator::F32Abs => wasm_encoder::Instruction::F32Abs,
|
|
||||||
&Operator::F32Neg => wasm_encoder::Instruction::F32Neg,
|
|
||||||
&Operator::F32Ceil => wasm_encoder::Instruction::F32Ceil,
|
|
||||||
&Operator::F32Floor => wasm_encoder::Instruction::F32Floor,
|
|
||||||
&Operator::F32Trunc => wasm_encoder::Instruction::F32Trunc,
|
|
||||||
&Operator::F32Nearest => wasm_encoder::Instruction::F32Nearest,
|
|
||||||
&Operator::F32Sqrt => wasm_encoder::Instruction::F32Sqrt,
|
|
||||||
&Operator::F32Add => wasm_encoder::Instruction::F32Add,
|
|
||||||
&Operator::F32Sub => wasm_encoder::Instruction::F32Sub,
|
|
||||||
&Operator::F32Mul => wasm_encoder::Instruction::F32Mul,
|
|
||||||
&Operator::F32Div => wasm_encoder::Instruction::F32Div,
|
|
||||||
&Operator::F32Min => wasm_encoder::Instruction::F32Min,
|
|
||||||
&Operator::F32Max => wasm_encoder::Instruction::F32Max,
|
|
||||||
&Operator::F32Copysign => wasm_encoder::Instruction::F32Copysign,
|
|
||||||
&Operator::F64Abs => wasm_encoder::Instruction::F64Abs,
|
|
||||||
&Operator::F64Neg => wasm_encoder::Instruction::F64Neg,
|
|
||||||
&Operator::F64Ceil => wasm_encoder::Instruction::F64Ceil,
|
|
||||||
&Operator::F64Floor => wasm_encoder::Instruction::F64Floor,
|
|
||||||
&Operator::F64Trunc => wasm_encoder::Instruction::F64Trunc,
|
|
||||||
&Operator::F64Nearest => wasm_encoder::Instruction::F64Nearest,
|
|
||||||
&Operator::F64Sqrt => wasm_encoder::Instruction::F64Sqrt,
|
|
||||||
&Operator::F64Add => wasm_encoder::Instruction::F64Add,
|
|
||||||
&Operator::F64Sub => wasm_encoder::Instruction::F64Sub,
|
|
||||||
&Operator::F64Mul => wasm_encoder::Instruction::F64Mul,
|
|
||||||
&Operator::F64Div => wasm_encoder::Instruction::F64Div,
|
|
||||||
&Operator::F64Min => wasm_encoder::Instruction::F64Min,
|
|
||||||
&Operator::F64Max => wasm_encoder::Instruction::F64Max,
|
|
||||||
&Operator::F64Copysign => wasm_encoder::Instruction::F64Copysign,
|
|
||||||
&Operator::I32WrapI64 => wasm_encoder::Instruction::I32WrapI64,
|
|
||||||
&Operator::I32TruncF32S => wasm_encoder::Instruction::I32TruncF32S,
|
|
||||||
&Operator::I32TruncF32U => wasm_encoder::Instruction::I32TruncF32U,
|
|
||||||
&Operator::I32TruncF64S => wasm_encoder::Instruction::I32TruncF64S,
|
|
||||||
&Operator::I32TruncF64U => wasm_encoder::Instruction::I32TruncF64U,
|
|
||||||
&Operator::I64ExtendI32S => wasm_encoder::Instruction::I64ExtendI32S,
|
|
||||||
&Operator::I64ExtendI32U => wasm_encoder::Instruction::I64ExtendI32U,
|
|
||||||
&Operator::I64TruncF32S => wasm_encoder::Instruction::I64TruncF32S,
|
|
||||||
&Operator::I64TruncF32U => wasm_encoder::Instruction::I64TruncF32U,
|
|
||||||
&Operator::I64TruncF64S => wasm_encoder::Instruction::I64TruncF64S,
|
|
||||||
&Operator::I64TruncF64U => wasm_encoder::Instruction::I64TruncF64U,
|
|
||||||
&Operator::F32ConvertI32S => wasm_encoder::Instruction::F32ConvertI32S,
|
|
||||||
&Operator::F32ConvertI32U => wasm_encoder::Instruction::F32ConvertI32U,
|
|
||||||
&Operator::F32ConvertI64S => wasm_encoder::Instruction::F32ConvertI64S,
|
|
||||||
&Operator::F32ConvertI64U => wasm_encoder::Instruction::F32ConvertI64U,
|
|
||||||
&Operator::F32DemoteF64 => wasm_encoder::Instruction::F32DemoteF64,
|
|
||||||
&Operator::F64ConvertI32S => wasm_encoder::Instruction::F64ConvertI32S,
|
|
||||||
&Operator::F64ConvertI32U => wasm_encoder::Instruction::F64ConvertI32U,
|
|
||||||
&Operator::F64ConvertI64S => wasm_encoder::Instruction::F64ConvertI64S,
|
|
||||||
&Operator::F64ConvertI64U => wasm_encoder::Instruction::F64ConvertI64U,
|
|
||||||
&Operator::F64PromoteF32 => wasm_encoder::Instruction::F64PromoteF32,
|
|
||||||
&Operator::I32Extend8S => wasm_encoder::Instruction::I32Extend8S,
|
|
||||||
&Operator::I32Extend16S => wasm_encoder::Instruction::I32Extend16S,
|
|
||||||
&Operator::I64Extend8S => wasm_encoder::Instruction::I64Extend8S,
|
|
||||||
&Operator::I64Extend16S => wasm_encoder::Instruction::I64Extend16S,
|
|
||||||
&Operator::I64Extend32S => wasm_encoder::Instruction::I64Extend32S,
|
|
||||||
&Operator::I32TruncSatF32S => wasm_encoder::Instruction::I32TruncSatF32S,
|
|
||||||
&Operator::I32TruncSatF32U => wasm_encoder::Instruction::I32TruncSatF32U,
|
|
||||||
&Operator::I32TruncSatF64S => wasm_encoder::Instruction::I32TruncSatF64S,
|
|
||||||
&Operator::I32TruncSatF64U => wasm_encoder::Instruction::I32TruncSatF64U,
|
|
||||||
&Operator::I64TruncSatF32S => wasm_encoder::Instruction::I64TruncSatF32S,
|
|
||||||
&Operator::I64TruncSatF32U => wasm_encoder::Instruction::I64TruncSatF32U,
|
|
||||||
&Operator::I64TruncSatF64S => wasm_encoder::Instruction::I64TruncSatF64S,
|
|
||||||
&Operator::I64TruncSatF64U => wasm_encoder::Instruction::I64TruncSatF64U,
|
|
||||||
&Operator::F32ReinterpretI32 => wasm_encoder::Instruction::F32ReinterpretI32,
|
|
||||||
&Operator::F64ReinterpretI64 => wasm_encoder::Instruction::F64ReinterpretI64,
|
|
||||||
&Operator::I32ReinterpretF32 => wasm_encoder::Instruction::I32ReinterpretF32,
|
|
||||||
&Operator::I64ReinterpretF64 => wasm_encoder::Instruction::I64ReinterpretF64,
|
|
||||||
&Operator::TableGet { table } => wasm_encoder::Instruction::TableGet { table },
|
|
||||||
&Operator::TableSet { table } => wasm_encoder::Instruction::TableSet { table },
|
|
||||||
&Operator::TableGrow { table } => wasm_encoder::Instruction::TableGrow { table },
|
|
||||||
&Operator::TableSize { table } => wasm_encoder::Instruction::TableSize { table },
|
|
||||||
&Operator::MemorySize { mem } => wasm_encoder::Instruction::MemorySize(mem),
|
|
||||||
&Operator::MemoryGrow { mem } => wasm_encoder::Instruction::MemoryGrow(mem),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::convert::From<MemoryImmediate> for Memory {
|
impl std::convert::From<MemoryImmediate> for Memory {
|
||||||
fn from(value: MemoryImmediate) -> Memory {
|
fn from(value: MemoryImmediate) -> Memory {
|
||||||
Memory {
|
Memory {
|
||||||
|
@ -700,23 +477,3 @@ impl std::convert::From<MemoryImmediate> for Memory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::Into<wasm_encoder::MemArg> for Memory {
|
|
||||||
fn into(self) -> wasm_encoder::MemArg {
|
|
||||||
wasm_encoder::MemArg {
|
|
||||||
align: self.align as u32,
|
|
||||||
offset: self.offset as u64,
|
|
||||||
memory_index: self.memory as u32,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ty_to_valty(ty: Type) -> wasm_encoder::ValType {
|
|
||||||
match ty {
|
|
||||||
Type::I32 => wasm_encoder::ValType::I32,
|
|
||||||
Type::I64 => wasm_encoder::ValType::I64,
|
|
||||||
Type::F32 => wasm_encoder::ValType::F32,
|
|
||||||
Type::F64 => wasm_encoder::ValType::F64,
|
|
||||||
_ => panic!("Unsupported type: {:?}", ty),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue