Get table imports working

This commit is contained in:
Lachlan Sneff
2019-01-29 10:16:39 -08:00
parent 98305c8731
commit 19242a413f
21 changed files with 859 additions and 595 deletions

View File

@ -6,6 +6,7 @@ pub use self::recovery::{call_protected, HandlerData};
use crate::trampoline::Trampolines;
use hashbrown::HashSet;
use std::sync::Arc;
use wasmer_runtime_core::{
backend::{ProtectedCaller, Token},
error::RuntimeResult,
@ -62,11 +63,14 @@ impl ProtectedCaller for Caller {
assert!(self.func_export_set.contains(&func_index));
assert!(
signature.returns.len() <= 1,
signature.returns().len() <= 1,
"multi-value returns not yet supported"
);
assert!(signature.check_sig(params), "incorrect signature");
assert!(
signature.check_param_value_types(params),
"incorrect signature"
);
let param_vec: Vec<u64> = params
.iter()
@ -78,7 +82,7 @@ impl ProtectedCaller for Caller {
})
.collect();
let mut return_vec = vec![0; signature.returns.len()];
let mut return_vec = vec![0; signature.returns().len()];
let trampoline = self
.trampolines
@ -97,7 +101,7 @@ impl ProtectedCaller for Caller {
Ok(return_vec
.iter()
.zip(signature.returns.iter())
.zip(signature.returns().iter())
.map(|(&x, ty)| match ty {
Type::I32 => Value::I32(x as i32),
Type::I64 => Value::I64(x as i64),
@ -108,11 +112,11 @@ impl ProtectedCaller for Caller {
}
}
fn get_func_from_index<'a>(
module: &'a ModuleInner,
fn get_func_from_index(
module: &ModuleInner,
import_backing: &ImportBacking,
func_index: FuncIndex,
) -> (*const vm::Func, Context, &'a FuncSig, SigIndex) {
) -> (*const vm::Func, Context, Arc<FuncSig>, SigIndex) {
let sig_index = *module
.func_assoc
.get(func_index)
@ -137,7 +141,7 @@ fn get_func_from_index<'a>(
}
};
let signature = module.sig_registry.lookup_func_sig(sig_index);
let signature = module.sig_registry.lookup_signature(sig_index);
(func_ptr, ctx, signature, sig_index)
}

View File

@ -25,9 +25,12 @@ impl<'env, 'module, 'isa> FuncEnv<'env, 'module, 'isa> {
}
/// Creates a signature with VMContext as the last param
pub fn generate_signature(&self, sig_index: cranelift_wasm::SignatureIndex) -> ir::Signature {
pub fn generate_signature(
&self,
clif_sig_index: cranelift_wasm::SignatureIndex,
) -> ir::Signature {
// Get signature
let mut signature = self.env.signatures[Converter(sig_index).into()].clone();
let mut signature = self.env.signatures[Converter(clif_sig_index).into()].clone();
// Add the vmctx parameter type to it
signature.params.push(ir::AbiParam::special(
@ -251,7 +254,8 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
let ptr_type = self.pointer_type();
match table_index.local_or_import(self.env.module) {
let (table_struct_ptr_ptr, description) = match table_index.local_or_import(self.env.module)
{
LocalOrImport::Local(local_table_index) => {
let tables_base = func.create_global_value(ir::GlobalValueData::Load {
base: vmctx,
@ -260,88 +264,74 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
readonly: true,
});
let table_struct_offset =
let table_struct_ptr_offset =
local_table_index.index() * vm::LocalTable::size() as usize;
let table_struct_addr = func.create_global_value(ir::GlobalValueData::IAddImm {
let table_struct_ptr_ptr = func.create_global_value(ir::GlobalValueData::IAddImm {
base: tables_base,
offset: (table_struct_offset as i64).into(),
offset: (table_struct_ptr_offset as i64).into(),
global_type: ptr_type,
});
let table_base = func.create_global_value(ir::GlobalValueData::Load {
base: table_struct_addr,
offset: (vm::LocalTable::offset_base() as i32).into(),
global_type: ptr_type,
// we will support growing tables, so this cannot be readonly.
readonly: false,
});
let table_bound = func.create_global_value(ir::GlobalValueData::Load {
base: table_struct_addr,
offset: (vm::LocalTable::offset_current_elements() as i32).into(),
// the number of elements in a table will always fit in an `i32`.
global_type: ir::types::I32,
readonly: false,
});
func.create_table(ir::TableData {
base_gv: table_base,
min_size: (self.env.module.tables[local_table_index].min as u64).into(),
bound_gv: table_bound,
element_size: (vm::Anyfunc::size() as u64).into(),
index_type: ir::types::I32,
})
(
table_struct_ptr_ptr,
self.env.module.tables[local_table_index],
)
}
LocalOrImport::Import(imported_table_index) => {
let imported_tables_base = func.create_global_value(ir::GlobalValueData::Load {
LocalOrImport::Import(import_table_index) => {
let tables_base = func.create_global_value(ir::GlobalValueData::Load {
base: vmctx,
offset: (vm::Ctx::offset_imported_tables() as i32).into(),
global_type: ptr_type,
readonly: true,
});
let imported_table_struct_offset =
imported_table_index.index() * vm::ImportedTable::size() as usize;
let table_struct_ptr_offset =
import_table_index.index() * vm::LocalTable::size() as usize;
let imported_table_struct_addr =
func.create_global_value(ir::GlobalValueData::IAddImm {
base: imported_tables_base,
offset: (imported_table_struct_offset as i64).into(),
global_type: ptr_type,
});
let local_table_struct_addr = func.create_global_value(ir::GlobalValueData::Load {
base: imported_table_struct_addr,
offset: (vm::ImportedTable::offset_table() as i32).into(),
let table_struct_ptr_ptr = func.create_global_value(ir::GlobalValueData::IAddImm {
base: tables_base,
offset: (table_struct_ptr_offset as i64).into(),
global_type: ptr_type,
readonly: true,
});
let local_table_base = func.create_global_value(ir::GlobalValueData::Load {
base: local_table_struct_addr,
offset: (vm::LocalTable::offset_base() as i32).into(),
global_type: ptr_type,
readonly: false,
});
let local_table_bound = func.create_global_value(ir::GlobalValueData::Load {
base: local_table_struct_addr,
offset: (vm::LocalTable::offset_current_elements() as i32).into(),
global_type: ir::types::I32,
readonly: false,
});
func.create_table(ir::TableData {
base_gv: local_table_base,
min_size: (self.env.module.imported_tables[imported_table_index].1.min as u64)
.into(),
bound_gv: local_table_bound,
element_size: (vm::Anyfunc::size() as u64).into(),
index_type: ir::types::I32,
})
(
table_struct_ptr_ptr,
self.env.module.imported_tables[import_table_index].1,
)
}
}
};
let table_struct_ptr = func.create_global_value(ir::GlobalValueData::Load {
base: table_struct_ptr_ptr,
offset: 0.into(),
global_type: ptr_type,
readonly: true,
});
let table_base = func.create_global_value(ir::GlobalValueData::Load {
base: table_struct_ptr,
offset: (vm::LocalTable::offset_base() as i32).into(),
global_type: ptr_type,
// The table can reallocate, so the ptr can't be readonly.
readonly: false,
});
let table_count = func.create_global_value(ir::GlobalValueData::Load {
base: table_struct_ptr,
offset: (vm::LocalTable::offset_count() as i32).into(),
global_type: ptr_type,
// The table length can change, so it can't be readonly.
readonly: false,
});
func.create_table(ir::TableData {
base_gv: table_base,
min_size: (description.min as u64).into(),
bound_gv: table_count,
element_size: (vm::Anyfunc::size() as u64).into(),
index_type: ir::types::I32,
})
}
/// Sets up a signature definition in `func`'s preamble.
@ -351,10 +341,10 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
fn make_indirect_sig(
&mut self,
func: &mut ir::Function,
index: cranelift_wasm::SignatureIndex,
clif_sig_index: cranelift_wasm::SignatureIndex,
) -> ir::SigRef {
// Create a signature reference out of specified signature (with VMContext param added).
func.import_signature(self.generate_signature(index))
func.import_signature(self.generate_signature(clif_sig_index))
}
/// Sets up an external function definition in the preamble of `func` that can be used to
@ -393,7 +383,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
mut pos: FuncCursor,
_table_index: cranelift_wasm::TableIndex,
table: ir::Table,
sig_index: cranelift_wasm::SignatureIndex,
clif_sig_index: cranelift_wasm::SignatureIndex,
sig_ref: ir::SigRef,
callee: ir::Value,
call_args: &[ir::Value],
@ -412,12 +402,25 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
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 vmctx_ptr = {
let loaded_vmctx_ptr = pos.ins().load(
ptr_type,
mflags,
entry_addr,
vm::Anyfunc::offset_vmctx() as i32,
);
let argument_vmctx_ptr = pos
.func
.special_param(ir::ArgumentPurpose::VMContext)
.expect("missing vmctx parameter");
// If the loaded vmctx ptr is zero, use the caller vmctx, else use the callee (loaded) vmctx.
pos.ins()
.select(loaded_vmctx_ptr, loaded_vmctx_ptr, argument_vmctx_ptr)
};
let found_sig = pos.ins().load(
ir::types::I32,
mflags,
@ -427,14 +430,9 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
pos.ins().trapz(func_ptr, ir::TrapCode::IndirectCallToNull);
let deduplicated_sig_index = self
.env
.module
.sig_registry
.lookup_deduplicated_sigindex(Converter(sig_index).into());
let expected_sig = pos
.ins()
.iconst(ir::types::I32, deduplicated_sig_index.index() as i64);
let sig_index = self.env.deduplicated[clif_sig_index];
let expected_sig = pos.ins().iconst(ir::types::I32, sig_index.index() as i64);
let not_equal_flags = pos.ins().ifcmp(found_sig, expected_sig);
pos.ins().trapif(

View File

@ -76,7 +76,7 @@ impl Module {
start_func: None,
func_assoc: Map::new(),
sig_registry: SigRegistry::new(),
sig_registry: SigRegistry,
},
}
}
@ -87,11 +87,11 @@ impl Module {
functions: Map<LocalFuncIndex, ir::Function>,
) -> CompileResult<ModuleInner> {
// we have to deduplicate `module.func_assoc`
let func_assoc = &mut self.module.func_assoc;
let sig_registry = &self.module.sig_registry;
func_assoc.iter_mut().for_each(|(_, sig_index)| {
*sig_index = sig_registry.lookup_deduplicated_sigindex(*sig_index);
});
// let func_assoc = &mut self.module.func_assoc;
// let sig_registry = &self.module.sig_registry;
// func_assoc.iter_mut().for_each(|(_, sig_index)| {
// *sig_index = sig_registry.lookup_deduplicated_sigindex(*sig_index);
// });
let (func_resolver_builder, handler_data) = FuncResolverBuilder::new(isa, functions)?;
self.module.func_resolver = Box::new(func_resolver_builder.finalize()?);
@ -152,20 +152,20 @@ convert_clif_to_runtime_index![
impl<'a> From<Converter<&'a ir::Signature>> for FuncSig {
fn from(signature: Converter<&'a ir::Signature>) -> Self {
FuncSig {
params: signature
FuncSig::new(
signature
.0
.params
.iter()
.map(|param| Converter(param.value_type).into())
.collect(),
returns: signature
.collect::<Vec<_>>(),
signature
.0
.returns
.iter()
.map(|ret| Converter(ret.value_type).into())
.collect(),
}
.collect::<Vec<_>>(),
)
}
}

View File

@ -3,13 +3,15 @@ use crate::{
module::{Converter, Module},
};
use cranelift_codegen::{ir, isa};
use cranelift_entity::PrimaryMap;
use cranelift_wasm::{self, translate_module, FuncTranslator, ModuleEnvironment};
use hashbrown::HashMap;
use wasmer_runtime_core::{
error::{CompileError, CompileResult},
module::{DataInitializer, ExportIndex, ImportName, TableInitializer},
structures::{Map, TypedIndex},
types::{
ElementType, GlobalDesc, GlobalIndex, GlobalInit, Initializer, LocalFuncIndex,
ElementType, FuncSig, GlobalDesc, GlobalIndex, GlobalInit, Initializer, LocalFuncIndex,
LocalOrImport, MemoryDesc, SigIndex, TableDesc, Value,
},
};
@ -20,6 +22,8 @@ pub struct ModuleEnv<'module, 'isa> {
pub signatures: Map<SigIndex, ir::Signature>,
globals: Map<GlobalIndex, cranelift_wasm::Global>,
func_bodies: Map<LocalFuncIndex, ir::Function>,
pub deduplicated: PrimaryMap<cranelift_wasm::SignatureIndex, SigIndex>,
duplicated: HashMap<SigIndex, cranelift_wasm::SignatureIndex>,
}
impl<'module, 'isa> ModuleEnv<'module, 'isa> {
@ -30,6 +34,8 @@ impl<'module, 'isa> ModuleEnv<'module, 'isa> {
signatures: Map::new(),
globals: Map::new(),
func_bodies: Map::new(),
deduplicated: PrimaryMap::new(),
duplicated: HashMap::new(),
}
}
@ -48,23 +54,28 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
/// Declares a function signature to the environment.
fn declare_signature(&mut self, sig: &ir::Signature) {
self.signatures.push(sig.clone());
self.module.sig_registry.register(Converter(sig).into());
let clif_sig_index = self.signatures.push(sig.clone());
let func_sig: FuncSig = Converter(sig).into();
let sig_index = self.module.sig_registry.lookup_sigindex(func_sig);
self.deduplicated.push(sig_index);
self.duplicated
.insert(sig_index, Converter(clif_sig_index).into());
}
/// Return the signature with the given index.
fn get_signature(&self, sig_index: cranelift_wasm::SignatureIndex) -> &ir::Signature {
&self.signatures[Converter(sig_index).into()]
fn get_signature(&self, clif_sig_index: cranelift_wasm::SignatureIndex) -> &ir::Signature {
&self.signatures[Converter(clif_sig_index).into()]
}
/// Declares a function import to the environment.
fn declare_func_import(
&mut self,
sig_index: cranelift_wasm::SignatureIndex,
clif_sig_index: cranelift_wasm::SignatureIndex,
namespace: &'data str,
name: &'data str,
) {
self.module.func_assoc.push(Converter(sig_index).into());
let sig_index = self.deduplicated[clif_sig_index];
self.module.func_assoc.push(sig_index);
// Add import names to list of imported functions
self.module.imported_functions.push(ImportName {
@ -79,8 +90,9 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
}
/// Declares the type (signature) of a local function in the module.
fn declare_func_type(&mut self, sig_index: cranelift_wasm::SignatureIndex) {
self.module.func_assoc.push(Converter(sig_index).into());
fn declare_func_type(&mut self, clif_sig_index: cranelift_wasm::SignatureIndex) {
let sig_index = self.deduplicated[clif_sig_index];
self.module.func_assoc.push(sig_index);
}
/// Return the signature index for the given function index.
@ -88,7 +100,8 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
&self,
func_index: cranelift_wasm::FuncIndex,
) -> cranelift_wasm::SignatureIndex {
Converter(self.module.func_assoc[Converter(func_index).into()]).into()
let sig_index: SigIndex = self.module.func_assoc[Converter(func_index).into()];
self.duplicated[&sig_index]
}
/// Declares a global to the environment.

View File

@ -43,9 +43,9 @@ impl Trampolines {
for exported_func_index in func_index_iter {
let sig_index = module.func_assoc[*exported_func_index];
let func_sig = module.sig_registry.lookup_func_sig(sig_index);
let func_sig = module.sig_registry.lookup_signature(sig_index);
let trampoline_func = generate_func(func_sig);
let trampoline_func = generate_func(&func_sig);
ctx.func = trampoline_func;
@ -128,8 +128,8 @@ fn generate_func(func_sig: &FuncSig) -> ir::Function {
let mut pos = FuncCursor::new(&mut func).at_first_insertion_point(entry_ebb);
let mut args_vec = Vec::with_capacity(func_sig.params.len() + 1);
for (index, wasm_ty) in func_sig.params.iter().enumerate() {
let mut args_vec = Vec::with_capacity(func_sig.params().len() + 1);
for (index, wasm_ty) in func_sig.params().iter().enumerate() {
let mem_flags = ir::MemFlags::trusted();
let val = pos.ins().load(
@ -190,7 +190,7 @@ fn generate_export_signature(func_sig: &FuncSig) -> ir::Signature {
let mut export_clif_sig = ir::Signature::new(isa::CallConv::SystemV);
export_clif_sig.params = func_sig
.params
.params()
.iter()
.map(|wasm_ty| ir::AbiParam {
value_type: wasm_ty_to_clif(*wasm_ty),
@ -207,7 +207,7 @@ fn generate_export_signature(func_sig: &FuncSig) -> ir::Signature {
.collect();
export_clif_sig.returns = func_sig
.returns
.returns()
.iter()
.map(|wasm_ty| ir::AbiParam {
value_type: wasm_ty_to_clif(*wasm_ty),