This commit is contained in:
Chris Fallin 2022-11-21 22:33:19 -08:00
parent 9e5d2fae26
commit 7b804b02d7
No known key found for this signature in database
GPG key ID: 31649E4FE65EB465
2 changed files with 191 additions and 149 deletions

View file

@ -51,52 +51,6 @@ impl Module {
Ok(Module(ptr)) 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
}
pub fn add_global(&self, ty: ir::Type, mutable: bool, value: Option<u64>) -> ir::Global { pub fn add_global(&self, ty: ir::Type, mutable: bool, value: Option<u64>) -> ir::Global {
let b_ty = Type::from(ty).to_binaryen(); let b_ty = Type::from(ty).to_binaryen();
let value = value.unwrap_or(0); let value = value.unwrap_or(0);
@ -109,7 +63,8 @@ impl Module {
}; };
let num = unsafe { BinaryenGetNumGlobals(self.0) }; let num = unsafe { BinaryenGetNumGlobals(self.0) };
let global = unsafe { BinaryenAddGlobal(self.0, std::ptr::null(), b_ty, mutable, init.1) }; let name = CString::new(format!("global{}", num)).unwrap();
let global = unsafe { BinaryenAddGlobal(self.0, name.as_ptr(), b_ty, mutable, init.1) };
assert!(!global.is_null()); assert!(!global.is_null());
ir::Global::from(num) ir::Global::from(num)
} }
@ -118,10 +73,11 @@ impl Module {
let ty = Type::from(ty).to_binaryen(); let ty = Type::from(ty).to_binaryen();
let num = unsafe { BinaryenGetNumTables(self.0) }; let num = unsafe { BinaryenGetNumTables(self.0) };
let max = max.unwrap_or(0); let max = max.unwrap_or(0);
let name = CString::new(format!("table{}", num)).unwrap();
let table = unsafe { let table = unsafe {
BinaryenAddTable( BinaryenAddTable(
self.0, self.0,
std::ptr::null(), name.as_ptr(),
init as BinaryenIndex, init as BinaryenIndex,
max as BinaryenIndex, max as BinaryenIndex,
ty, ty,
@ -132,25 +88,23 @@ impl Module {
} }
pub fn add_table_elem(&self, table: ir::Table, index: usize, elt: ir::Func) { pub fn add_table_elem(&self, table: ir::Table, index: usize, elt: ir::Func) {
log::trace!("add_table_elem: func {}", elt);
let table_name = unsafe { let table_name = unsafe {
BinaryenTableGetName(BinaryenGetTableByIndex( BinaryenTableGetName(BinaryenGetTableByIndex(
self.0, self.0,
table.index() as BinaryenIndex, table.index() as BinaryenIndex,
)) ))
}; };
let func_name = unsafe { let func_name = compute_func_name(elt);
BinaryenFunctionGetName(BinaryenGetFunctionByIndex( let func_name_ptr = func_name.as_ptr();
self.0,
elt.index() as BinaryenIndex,
))
};
let offset = Expression::const_i32(self, index as i32); let offset = Expression::const_i32(self, index as i32);
let name = CString::new(format!("seg_{}_{}", table.index(), index)).unwrap();
let seg = unsafe { let seg = unsafe {
BinaryenAddActiveElementSegment( BinaryenAddActiveElementSegment(
self.0, self.0,
table_name, table_name,
std::ptr::null(), name.as_ptr(),
&func_name as *const *const c_char, &func_name_ptr as *const *const c_char,
1, 1,
offset.1, offset.1,
) )
@ -218,20 +172,17 @@ impl Module {
params: &[ir::Type], params: &[ir::Type],
results: &[ir::Type], results: &[ir::Type],
) { ) {
let func_name = unsafe { let num = unsafe { BinaryenGetNumFunctions(self.0) } as usize;
BinaryenFunctionGetName(BinaryenGetFunctionByIndex( assert_eq!(num, func.index());
self.0,
func.index() as BinaryenIndex,
))
};
let c_module = std::ffi::CString::new(module).unwrap(); let c_module = std::ffi::CString::new(module).unwrap();
let c_name = std::ffi::CString::new(name).unwrap(); let c_name = std::ffi::CString::new(name).unwrap();
let params = tys_to_binaryen(params.iter().copied()); let params = tys_to_binaryen(params.iter().copied());
let results = tys_to_binaryen(results.iter().copied()); let results = tys_to_binaryen(results.iter().copied());
let internal_name = compute_func_name(func);
unsafe { unsafe {
BinaryenAddFunctionImport( BinaryenAddFunctionImport(
self.0, self.0,
func_name, internal_name.as_ptr(),
c_module.as_ptr(), c_module.as_ptr(),
c_name.as_ptr(), c_name.as_ptr(),
params, params,
@ -268,6 +219,49 @@ impl Module {
); );
} }
} }
pub fn add_table_export(&self, table: ir::Table, name: &str) {
let c_name = CString::new(name).unwrap();
let name = unsafe {
BinaryenTableGetName(BinaryenGetTableByIndex(
self.0,
table.index() as BinaryenIndex,
))
};
unsafe {
BinaryenAddTableExport(self.0, name, c_name.as_ptr());
}
}
pub fn add_func_export(&self, func: ir::Func, name: &str) {
log::trace!("add_func_export: func {}", func);
let c_name = CString::new(name).unwrap();
let name = compute_func_name(func);
unsafe {
BinaryenAddFunctionExport(self.0, name.as_ptr(), c_name.as_ptr());
}
}
pub fn add_global_export(&self, global: ir::Global, name: &str) {
let c_name = CString::new(name).unwrap();
let name = unsafe {
BinaryenGlobalGetName(BinaryenGetGlobalByIndex(
self.0,
global.index() as BinaryenIndex,
))
};
unsafe {
BinaryenAddGlobalExport(self.0, name, c_name.as_ptr());
}
}
pub fn add_memory_export(&self, mem: ir::Memory, name: &str) {
assert_eq!(mem.index(), 0);
let c_name = CString::new(name).unwrap();
unsafe {
BinaryenAddMemoryExport(self.0, std::ptr::null(), c_name.as_ptr());
}
}
} }
impl Drop for Module { impl Drop for Module {
@ -278,6 +272,10 @@ impl Drop for Module {
} }
} }
fn compute_func_name(func: ir::Func) -> CString {
CString::new(format!("func{}", func.index())).unwrap()
}
impl Function { impl Function {
pub fn body(&self) -> Option<Expression> { pub fn body(&self) -> Option<Expression> {
let body = unsafe { BinaryenFunctionGetBody(self.1) }; let body = unsafe { BinaryenFunctionGetBody(self.1) };
@ -309,10 +307,13 @@ impl Function {
let params = tys_to_binaryen(params); let params = tys_to_binaryen(params);
let results = tys_to_binaryen(results); let results = tys_to_binaryen(results);
let locals: Vec<BinaryenType> = locals.map(|ty| Type::from(ty).to_binaryen()).collect(); let locals: Vec<BinaryenType> = locals.map(|ty| Type::from(ty).to_binaryen()).collect();
let num = unsafe { BinaryenGetNumFunctions(module.0) };
let name = compute_func_name(ir::Func::new(num as usize));
log::debug!("creating func {:?}", name);
let ptr = unsafe { let ptr = unsafe {
BinaryenAddFunc( BinaryenAddFunction(
module.0, module.0,
/* name = */ std::ptr::null(), name.as_ptr(),
params, params,
results, results,
locals.as_ptr(), locals.as_ptr(),
@ -338,16 +339,6 @@ impl Export {
let s = unsafe { CStr::from_ptr(BinaryenExportGetValue(self.1)) }; let s = unsafe { CStr::from_ptr(BinaryenExportGetValue(self.1)) };
s.to_str().unwrap() 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 TypeIds { struct TypeIds {
@ -357,6 +348,7 @@ struct TypeIds {
f32_t: BinaryenType, f32_t: BinaryenType,
f64_t: BinaryenType, f64_t: BinaryenType,
v128_t: BinaryenType, v128_t: BinaryenType,
funcref_t: BinaryenType,
} }
impl TypeIds { impl TypeIds {
@ -368,6 +360,7 @@ impl TypeIds {
f32_t: unsafe { BinaryenTypeFloat32() }, f32_t: unsafe { BinaryenTypeFloat32() },
f64_t: unsafe { BinaryenTypeFloat64() }, f64_t: unsafe { BinaryenTypeFloat64() },
v128_t: unsafe { BinaryenTypeVec128() }, v128_t: unsafe { BinaryenTypeVec128() },
funcref_t: unsafe { BinaryenTypeFuncref() },
} }
} }
} }
@ -384,26 +377,10 @@ pub enum Type {
F32, F32,
F64, F64,
V128, V128,
FuncRef,
} }
impl Type { impl Type {
fn from_binaryen(kind: BinaryenType) -> 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
}
}
pub(crate) fn to_binaryen(&self) -> BinaryenType { pub(crate) fn to_binaryen(&self) -> BinaryenType {
let tys = &*TYPE_IDS; let tys = &*TYPE_IDS;
match self { match self {
@ -413,6 +390,7 @@ impl Type {
&Type::F32 => tys.f32_t, &Type::F32 => tys.f32_t,
&Type::F64 => tys.f64_t, &Type::F64 => tys.f64_t,
&Type::V128 => tys.v128_t, &Type::V128 => tys.v128_t,
&Type::FuncRef => tys.funcref_t,
} }
} }
} }
@ -425,7 +403,7 @@ impl From<ir::Type> for Type {
ir::Type::F32 => Type::F32, ir::Type::F32 => Type::F32,
ir::Type::F64 => Type::F64, ir::Type::F64 => Type::F64,
ir::Type::V128 => Type::V128, ir::Type::V128 => Type::V128,
_ => unimplemented!(), ir::Type::FuncRef => Type::FuncRef,
} }
} }
} }
@ -480,19 +458,14 @@ impl Expression {
tys: &[ir::Type], tys: &[ir::Type],
) -> Expression { ) -> Expression {
// Look up the function's name. // Look up the function's name.
let func_name = unsafe { let func_name = compute_func_name(func);
BinaryenFunctionGetName(BinaryenGetFunctionByIndex(
module.0,
func.index() as BinaryenIndex,
))
};
// Create the appropriate type for return. // Create the appropriate type for return.
let ret_tuple_ty = tys_to_binaryen(tys.iter().copied()); let ret_tuple_ty = tys_to_binaryen(tys.iter().copied());
let args = args.iter().map(|expr| expr.1).collect::<Vec<_>>(); let args = args.iter().map(|expr| expr.1).collect::<Vec<_>>();
let expr = unsafe { let expr = unsafe {
BinaryenCall( BinaryenCall(
module.0, module.0,
func_name, func_name.as_ptr(),
args.as_ptr(), args.as_ptr(),
args.len() as BinaryenIndex, args.len() as BinaryenIndex,
ret_tuple_ty, ret_tuple_ty,
@ -976,7 +949,6 @@ extern "C" {
sourceMapUrl: *const c_char, sourceMapUrl: *const c_char,
) -> BinaryenModuleAllocateAndWriteResult; ) -> BinaryenModuleAllocateAndWriteResult;
fn BinaryenGetNumFunctions(ptr: BinaryenModule) -> u32; fn BinaryenGetNumFunctions(ptr: BinaryenModule) -> u32;
fn BinaryenGetFunctionByIndex(ptr: BinaryenModule, index: u32) -> BinaryenFunction;
fn BinaryenGetFunction(ptr: BinaryenModule, name: *const c_char) -> BinaryenFunction; fn BinaryenGetFunction(ptr: BinaryenModule, name: *const c_char) -> BinaryenFunction;
fn BinaryenFunctionGetBody(ptr: BinaryenFunction) -> BinaryenExpression; fn BinaryenFunctionGetBody(ptr: BinaryenFunction) -> BinaryenExpression;
fn BinaryenFunctionSetBody(ptr: BinaryenFunction, body: BinaryenExpression); fn BinaryenFunctionSetBody(ptr: BinaryenFunction, body: BinaryenExpression);
@ -1010,6 +982,7 @@ extern "C" {
fn BinaryenTypeFloat32() -> BinaryenType; fn BinaryenTypeFloat32() -> BinaryenType;
fn BinaryenTypeFloat64() -> BinaryenType; fn BinaryenTypeFloat64() -> BinaryenType;
fn BinaryenTypeVec128() -> BinaryenType; fn BinaryenTypeVec128() -> BinaryenType;
fn BinaryenTypeFuncref() -> BinaryenType;
fn BinaryenTypeCreate(tys: *const BinaryenType, n_tys: BinaryenIndex) -> BinaryenType; fn BinaryenTypeCreate(tys: *const BinaryenType, n_tys: BinaryenIndex) -> BinaryenType;
@ -1130,7 +1103,7 @@ extern "C" {
) -> BinaryenExpression; ) -> BinaryenExpression;
fn BinaryenTableSize(module: BinaryenModule, name: *const c_char) -> BinaryenExpression; fn BinaryenTableSize(module: BinaryenModule, name: *const c_char) -> BinaryenExpression;
fn BinaryenAddFunc( fn BinaryenAddFunction(
module: BinaryenModule, module: BinaryenModule,
name: *const c_char, name: *const c_char,
params: BinaryenType, params: BinaryenType,
@ -1627,6 +1600,27 @@ extern "C" {
fn BinaryenGlobalGetName(global: BinaryenGlobal) -> *const c_char; fn BinaryenGlobalGetName(global: BinaryenGlobal) -> *const c_char;
fn BinaryenGetGlobalByIndex(module: BinaryenModule, index: BinaryenIndex) -> BinaryenGlobal; fn BinaryenGetGlobalByIndex(module: BinaryenModule, index: BinaryenIndex) -> BinaryenGlobal;
fn BinaryenAddTableExport(
module: BinaryenModule,
internal: *const c_char,
external: *const c_char,
);
fn BinaryenAddFunctionExport(
module: BinaryenModule,
internal: *const c_char,
external: *const c_char,
);
fn BinaryenAddGlobalExport(
module: BinaryenModule,
internal: *const c_char,
external: *const c_char,
);
fn BinaryenAddMemoryExport(
module: BinaryenModule,
internal: *const c_char,
external: *const c_char,
);
} }
#[repr(C)] #[repr(C)]

View file

@ -1,66 +1,24 @@
use crate::backend::binaryen; use crate::backend::binaryen;
use crate::entity::EntityRef; use crate::entity::EntityRef;
use crate::ir::ImportKind;
use crate::ir::*; use crate::ir::*;
use crate::ir::{ExportKind, FuncDecl, ImportKind};
use crate::Operator; use crate::Operator;
use anyhow::Result; use anyhow::Result;
use fxhash::FxHashMap; use fxhash::FxHashMap;
use std::collections::BTreeMap; use std::collections::BTreeMap;
pub(crate) fn lower(module: &Module) -> Result<binaryen::Module> { pub(crate) fn lower(module: &Module) -> Result<binaryen::Module> {
let into_mod = binaryen::Module::new()?; let mut into_mod = binaryen::Module::new()?;
// Create globals. log::debug!("creating new module");
for (global, data) in module.globals() {
let new_global = into_mod.add_global(data.ty, data.mutable, data.value);
assert_eq!(new_global, global);
}
// Create tables. // Create imported tables and globals.
for (table, data) in module.tables() {
let new_table = into_mod.add_table(
data.ty,
data.func_elements
.as_ref()
.map(|elems| elems.len())
.unwrap_or(0),
data.max,
);
assert_eq!(new_table, table);
if let Some(elts) = data.func_elements.as_ref() {
for (i, &elt) in elts.iter().enumerate() {
if elt.is_valid() {
into_mod.add_table_elem(new_table, i, elt);
}
}
}
}
// Create memories.
for (mem, data) in module.memories() {
let new_mem = into_mod.add_mem(data.initial_pages, data.maximum_pages, &data.segments[..]);
assert_eq!(new_mem, mem);
}
// Create function bodies.
// Create imports.
for import in module.imports() { for import in module.imports() {
log::debug!("adding import: {:?}", import);
match &import.kind { match &import.kind {
&ImportKind::Table(table) => { &ImportKind::Table(table) => {
into_mod.add_table_import(table, &import.module[..], &import.name[..]); into_mod.add_table_import(table, &import.module[..], &import.name[..]);
} }
&ImportKind::Func(func) => {
let sig = module.func(func).sig();
let sigdata = module.signature(sig);
into_mod.add_func_import(
func,
&import.module[..],
&import.name[..],
&sigdata.params[..],
&sigdata.returns[..],
);
}
&ImportKind::Global(global) => { &ImportKind::Global(global) => {
let globdata = module.global(global); let globdata = module.global(global);
into_mod.add_global_import( into_mod.add_global_import(
@ -71,10 +29,100 @@ pub(crate) fn lower(module: &Module) -> Result<binaryen::Module> {
globdata.mutable, globdata.mutable,
); );
} }
_ => {}
}
}
// Create globals.
for (global, data) in module.globals() {
log::debug!("adding global {}: {:?}", global, data);
let new_global = into_mod.add_global(data.ty, data.mutable, data.value);
assert_eq!(new_global, global);
}
// Create tables.
for (table, data) in module.tables() {
log::debug!("adding table {}: {:?}", table, data);
let new_table = into_mod.add_table(
data.ty,
data.func_elements
.as_ref()
.map(|elems| elems.len())
.unwrap_or(0),
data.max,
);
assert_eq!(new_table, table);
}
// Create memories.
for (mem, data) in module.memories() {
log::debug!("adding mem {}", mem);
let new_mem = into_mod.add_mem(data.initial_pages, data.maximum_pages, &data.segments[..]);
assert_eq!(new_mem, mem);
}
// Create function imports.
for import in module.imports() {
log::debug!("adding import: {:?}", import);
match &import.kind {
&ImportKind::Func(func) => {
let sig = module.func(func).sig();
let sigdata = module.signature(sig);
into_mod.add_func_import(
func,
&import.module[..],
&import.name[..],
&sigdata.params[..],
&sigdata.returns[..],
);
}
_ => {}
}
}
// Create function bodies.
for (func, decl) in module.funcs() {
log::debug!("adding func {}: {:?}", func, decl);
match decl {
&FuncDecl::Body(sig, ref body) => {
let (new_locals, body_expr) = generate_body(module, body, &mut into_mod);
let _func =
create_new_func(module, sig, body, &mut into_mod, body_expr, new_locals);
}
_ => {}
}
}
// Create table contents.
for (table, data) in module.tables() {
if let Some(elts) = data.func_elements.as_ref() {
log::debug!("adding elts to table {}: {:?}", table, elts);
for (i, &elt) in elts.iter().enumerate() {
if elt.is_valid() {
into_mod.add_table_elem(table, i, elt);
}
}
} }
} }
// Create exports. // Create exports.
for export in module.exports() {
log::debug!("adding export {:?}", export);
match &export.kind {
&ExportKind::Table(table) => {
into_mod.add_table_export(table, &export.name[..]);
}
&ExportKind::Func(func) => {
into_mod.add_func_export(func, &export.name[..]);
}
&ExportKind::Global(global) => {
into_mod.add_global_export(global, &export.name[..]);
}
&ExportKind::Memory(memory) => {
into_mod.add_memory_export(memory, &export.name[..]);
}
}
}
Ok(into_mod) Ok(into_mod)
} }