Rewrite exports and imports

This commit is contained in:
Lachlan Sneff
2019-01-10 22:59:57 -05:00
parent 1a5ef3aea2
commit 230e43a894
81 changed files with 75027 additions and 16753 deletions

View File

@ -3,8 +3,8 @@ use cranelift_codegen::cursor::FuncCursor;
use cranelift_codegen::ir::immediates::{Offset32, Uimm64};
use cranelift_codegen::ir::types::{self, *};
use cranelift_codegen::ir::{
self, AbiParam, ArgumentPurpose, ExtFuncData, ExternalName, FuncRef, InstBuilder, Signature,
TrapCode, condcodes::IntCC,
self, condcodes::IntCC, AbiParam, ArgumentPurpose, ExtFuncData, ExternalName, FuncRef,
InstBuilder, Signature, TrapCode,
};
use cranelift_codegen::isa::TargetFrontendConfig;
use cranelift_entity::{EntityRef, PrimaryMap};
@ -14,9 +14,13 @@ use cranelift_wasm::{
ReturnMode, SignatureIndex, Table, TableIndex, WasmResult,
};
use hashbrown::HashMap;
use std::mem;
use target_lexicon;
use wasmer_runtime::{
module::{ModuleInner as WasmerModule, DataInitializer, Export, ImportName, TableInitializer},
backend::SigRegistry,
module::{
DataInitializer, ExportIndex, ImportName, ModuleInner as WasmerModule, TableInitializer,
},
types::{
ElementType as WasmerElementType, FuncIndex as WasmerFuncIndex, FuncSig as WasmerSignature,
Global as WasmerGlobal, GlobalDesc as WasmerGlobalDesc, GlobalIndex as WasmerGlobalIndex,
@ -25,7 +29,6 @@ use wasmer_runtime::{
TableIndex as WasmerTableIndex, Type as WasmerType,
},
vm::{self, Ctx as WasmerVMContext},
backend::SigRegistry,
LinearMemory,
};
@ -61,7 +64,11 @@ pub mod converter {
let mut func_assoc: Map<WasmerFuncIndex, WasmerSignatureIndex> =
Map::with_capacity(cranelift_module.functions.len());
for (_, signature_index) in cranelift_module.functions.iter() {
func_assoc.push(cranelift_module.sig_registry.lookup_deduplicated_sigindex(WasmerSignatureIndex::new(signature_index.index())));
func_assoc.push(
cranelift_module.sig_registry.lookup_deduplicated_sigindex(
WasmerSignatureIndex::new(signature_index.index()),
),
);
}
let function_bodies: Vec<_> = cranelift_module
@ -241,7 +248,7 @@ pub struct CraneliftModule {
pub imported_globals: Map<WasmerGlobalIndex, (ImportName, WasmerGlobalDesc)>,
// An hash map holding information about the wasm instance exports.
pub exports: HashMap<String, Export>,
pub exports: HashMap<String, ExportIndex>,
// Data to initialize in memory.
pub data_initializers: Vec<DataInitializer>,
@ -418,28 +425,30 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
/// by `index`.
///
/// The index space covers both imported and locally declared tables.
fn make_table(&mut self, func: &mut ir::Function, index: TableIndex) -> ir::Table {
fn make_table(&mut self, func: &mut ir::Function, table_index: TableIndex) -> ir::Table {
// Only the first table is supported for now.
debug_assert_eq!(index.index(), 0, "non-default tables not supported yet");
debug_assert_eq!(
table_index.index(),
0,
"non-default tables not supported yet"
);
// Create VMContext value.
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
let ptr_size = self.pointer_bytes();
let tables_offset = WasmerVMContext::offset_tables();
// Load value at (vmctx + memories_offset) which is the address at Ctx.tables.
let base = func.create_global_value(ir::GlobalValueData::Load {
base: vmctx,
offset: Offset32::new(tables_offset as i32),
offset: (vm::Ctx::offset_tables() as i32).into(),
global_type: self.pointer_type(),
readonly: true,
});
// *Ctx.tables -> [ {data: *usize, len: usize}, {data: *usize, len: usize}, ... ]
// Based on the index provided, we need to know the offset into tables array.
let table_data_offset = (index.as_u32() as i32) * (ptr_size as i32) * 2;
let table_data_offset = table_index.index() * mem::size_of::<vm::LocalTable>();
let table_data = func.create_global_value(ir::GlobalValueData::IAddImm {
let table_data_struct = func.create_global_value(ir::GlobalValueData::IAddImm {
base,
offset: (table_data_offset as i64).into(),
global_type: self.pointer_type(),
@ -447,16 +456,16 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
// Load value at (base + table_data_offset), i.e. the address at Ctx.tables[index].data
let base_gv = func.create_global_value(ir::GlobalValueData::Load {
base: table_data,
offset: 0.into(),
base: table_data_struct,
offset: (vm::LocalTable::offset_base() as i32).into(),
global_type: self.pointer_type(),
readonly: false,
});
// Load value at (base + table_data_offset), i.e. the value at Ctx.tables[index].len
let bound_gv = func.create_global_value(ir::GlobalValueData::Load {
base,
offset: (self.pointer_bytes() as i32).into(),
base: table_data_struct,
offset: (vm::LocalTable::offset_current_elements() as i32).into(),
global_type: self.pointer_type(),
readonly: false,
});
@ -466,8 +475,8 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
base_gv,
min_size: Uimm64::new(0),
bound_gv,
element_size: Uimm64::new(u64::from(self.pointer_bytes() * 2)),
index_type: self.pointer_type(),
element_size: Uimm64::new(mem::size_of::<vm::Anyfunc>() as u64),
index_type: I32,
})
}
@ -517,44 +526,47 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
callee: ir::Value,
call_args: &[ir::Value],
) -> WasmResult<ir::Inst> {
// Create a VMContext value.
let vmctx = pos
.func
.special_param(ir::ArgumentPurpose::VMContext)
.expect("missing vmctx parameter");
// Get the pointer type based on machine's pointer size.
let ptr_type = self.pointer_type();
// The `callee` value is an index into a table of function pointers.
// Set callee to an appropriate type based on machine's pointer size.
let callee_offset = if ptr_type == I32 {
callee
} else {
pos.ins().uextend(ptr_type, callee)
};
// The `callee` value is an index into a table of function pointers.
let entry_addr = pos.ins().table_addr(ptr_type, table, callee_offset, 0);
let entry_addr = pos.ins().table_addr(ptr_type, table, callee, 0);
let mflags = ir::MemFlags::trusted();
let func_ptr = pos.ins().load(ptr_type, mflags, entry_addr, 0);
let func_ptr = pos.ins().load(
ptr_type,
mflags,
entry_addr,
vm::Anyfunc::offset_func() as i32,
);
let vmctx_ptr = pos.ins().load(
ptr_type,
mflags,
entry_addr,
vm::Anyfunc::offset_vmctx() as i32,
);
let found_sig =
pos.ins()
.load(I32, mflags, entry_addr, vm::Anyfunc::offset_sig_id() as i32);
pos.ins().trapz(func_ptr, TrapCode::IndirectCallToNull);
let found_sig = pos.ins().load(I32, mflags, entry_addr, self.pointer_bytes() as i32);
let deduplicated_sig_index = self.module.sig_registry.lookup_deduplicated_sigindex(WasmerSignatureIndex::new(sig_index.index()));
let deduplicated_sig_index = self
.module
.sig_registry
.lookup_deduplicated_sigindex(WasmerSignatureIndex::new(sig_index.index()));
let expected_sig = pos.ins().iconst(I32, deduplicated_sig_index.index() as i64);
let not_equal_flags = pos.ins().ifcmp(found_sig, expected_sig);
pos.ins().trapif(IntCC::NotEqual, not_equal_flags, TrapCode::BadSignature);
pos.ins()
.trapif(IntCC::NotEqual, not_equal_flags, TrapCode::BadSignature);
// Build a value list for the indirect call instruction containing the call_args
// and the vmctx parameter.
let mut args = Vec::with_capacity(call_args.len() + 1);
args.extend(call_args.iter().cloned());
args.push(vmctx);
args.push(vmctx_ptr);
Ok(pos.ins().call_indirect(sig_ref, func_ptr, &args))
}
@ -569,7 +581,6 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
call_args: &[ir::Value],
) -> WasmResult<ir::Inst> {
// Insert call instructions for `callee`.
if callee_index.index() < self.module.imported_functions.len() {
// this is an imported function
let vmctx = pos.func.create_global_value(ir::GlobalValueData::VMContext);
@ -595,20 +606,25 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
readonly: true,
});
let imported_vmctx_addr = pos.func.create_global_value(ir::GlobalValueData::Load {
base: imported_func_struct_addr,
offset: (vm::ImportedFunc::offset_vmctx() as i32).into(),
global_type: self.pointer_type(),
readonly: true,
});
let imported_func_addr = pos
.ins()
.global_value(self.pointer_type(), imported_func_addr);
let imported_vmctx_addr = pos
.ins()
.global_value(self.pointer_type(), imported_vmctx_addr);
let sig_ref = pos.func.dfg.ext_funcs[callee].signature;
let vmctx = pos
.func
.special_param(ir::ArgumentPurpose::VMContext)
.expect("missing vmctx parameter");
let mut args = Vec::with_capacity(call_args.len() + 1);
args.extend(call_args.iter().cloned());
args.push(vmctx);
args.push(imported_vmctx_addr);
Ok(pos
.ins()
@ -910,28 +926,28 @@ impl<'data> ModuleEnvironment<'data> for CraneliftModule {
fn declare_func_export(&mut self, func_index: FuncIndex, name: &'data str) {
self.exports.insert(
String::from(name),
Export::Func(WasmerFuncIndex::new(func_index.index())),
ExportIndex::Func(WasmerFuncIndex::new(func_index.index())),
);
}
/// Declares a table export to the environment.
fn declare_table_export(&mut self, table_index: TableIndex, name: &'data str) {
self.exports.insert(
String::from(name),
Export::Table(WasmerTableIndex::new(table_index.index())),
ExportIndex::Table(WasmerTableIndex::new(table_index.index())),
);
}
/// Declares a memory export to the environment.
fn declare_memory_export(&mut self, memory_index: MemoryIndex, name: &'data str) {
self.exports.insert(
String::from(name),
Export::Memory(WasmerMemoryIndex::new(memory_index.index())),
ExportIndex::Memory(WasmerMemoryIndex::new(memory_index.index())),
);
}
/// Declares a global export to the environment.
fn declare_global_export(&mut self, global_index: GlobalIndex, name: &'data str) {
self.exports.insert(
String::from(name),
Export::Global(WasmerGlobalIndex::new(global_index.index())),
ExportIndex::Global(WasmerGlobalIndex::new(global_index.index())),
);
}

View File

@ -13,7 +13,7 @@ pub extern "C" fn truncf32(x: f32) -> f32 {
x.trunc()
}
/// `f32.round()` doesn't have the correct behavior. Ideally, we'd use
/// `f32.round()` doesn't have the correct behavior. Ideally, we'd use
/// "https://doc.rust-lang.org/std/intrinsics/fn.nearbyintf32.html" for this,
/// but support for stable compilers is necessary, so we must implement
/// this ourselves.
@ -51,7 +51,7 @@ pub extern "C" fn truncf64(x: f64) -> f64 {
x.trunc()
}
/// `f64.round()` doesn't have the correct behavior. Ideally, we'd use
/// `f64.round()` doesn't have the correct behavior. Ideally, we'd use
/// "https://doc.rust-lang.org/std/intrinsics/fn.nearbyintf64.html" for this,
/// but support for stable compilers is necessary, so we must implement
/// this ourselves.

View File

@ -1,5 +1,6 @@
use crate::libcalls;
use crate::relocation::{Reloc, RelocSink, Relocation, RelocationType, TrapSink};
use byteorder::{ByteOrder, LittleEndian};
use cranelift_codegen::{ir, isa, Context};
use std::mem;
use std::ptr::{write_unaligned, NonNull};
@ -9,7 +10,6 @@ use wasmer_runtime::{
types::{FuncIndex, Map, MapIndex},
vm, vmcalls,
};
use byteorder::{LittleEndian, ByteOrder};
#[allow(dead_code)]
pub struct FuncResolverBuilder {
@ -127,13 +127,11 @@ impl FuncResolverBuilder {
.unwrap();
let empty_space_offset = self.resolver.map[index] + reloc.offset as usize;
let ptr_slice = unsafe {
&mut self.resolver.memory.as_slice_mut()[empty_space_offset..empty_space_offset+8]
&mut self.resolver.memory.as_slice_mut()
[empty_space_offset..empty_space_offset + 8]
};
LittleEndian::write_u64(
ptr_slice,
ptr_to_write,
);
},
LittleEndian::write_u64(ptr_slice, ptr_to_write);
}
Reloc::X86PCRel4 => unsafe {
let reloc_address = func_addr.offset(reloc.offset as isize) as isize;
let reloc_addend = reloc.addend as isize;
@ -177,7 +175,11 @@ impl FuncResolver {
// Implements FuncResolver trait.
impl backend::FuncResolver for FuncResolver {
fn get(&self, _module: &wasmer_runtime::module::Module, index: FuncIndex) -> Option<NonNull<vm::Func>> {
fn get(
&self,
_module: &wasmer_runtime::module::Module,
index: FuncIndex,
) -> Option<NonNull<vm::Func>> {
self.lookup(index)
}
}
@ -185,4 +187,4 @@ impl backend::FuncResolver for FuncResolver {
#[inline]
fn round_up(n: usize, multiple: usize) -> usize {
(n + multiple - 1) & !(multiple - 1)
}
}