Implement cross-instance indirect calls.

This commit is contained in:
Dan Gohman
2019-01-03 08:31:03 -08:00
parent b646f9b4e0
commit 087b5b4dff
7 changed files with 51 additions and 46 deletions

View File

@@ -16,7 +16,7 @@ use std::vec::Vec;
use target_tunables::target_tunables;
use wasmtime_environ::cranelift;
use wasmtime_environ::{Compilation, CompileError, Module, Relocations, Tunables};
use wasmtime_runtime::{InstantiationError, VMFunctionBody};
use wasmtime_runtime::{InstantiationError, SignatureRegistry, VMFunctionBody};
/// A WebAssembly code JIT compiler.
///
@@ -31,6 +31,7 @@ pub struct Compiler {
code_memory: CodeMemory,
trampoline_park: HashMap<*const VMFunctionBody, *const VMFunctionBody>,
signatures: SignatureRegistry,
/// The `FunctionBuilderContext`, shared between trampline function compilations.
fn_builder_ctx: FunctionBuilderContext,
@@ -43,6 +44,7 @@ impl Compiler {
isa,
code_memory: CodeMemory::new(),
trampoline_park: HashMap::new(),
signatures: SignatureRegistry::new(),
fn_builder_ctx: FunctionBuilderContext::new(),
}
}
@@ -115,6 +117,10 @@ impl Compiler {
pub(crate) fn publish_compiled_code(&mut self) {
self.code_memory.publish();
}
pub(crate) fn signatures(&mut self) -> &mut SignatureRegistry {
&mut self.signatures
}
}
/// Create a trampoline for invoking a function.

View File

@@ -5,7 +5,7 @@
use compiler::Compiler;
use cranelift_entity::{BoxedSlice, PrimaryMap};
use cranelift_wasm::DefinedFuncIndex;
use cranelift_wasm::{DefinedFuncIndex, SignatureIndex};
use link::link_module;
use resolver::Resolver;
use std::boxed::Box;
@@ -15,7 +15,9 @@ use std::vec::Vec;
use wasmtime_environ::{
CompileError, DataInitializer, DataInitializerLocation, Module, ModuleEnvironment,
};
use wasmtime_runtime::{Imports, Instance, InstantiationError, VMFunctionBody};
use wasmtime_runtime::{
Imports, Instance, InstantiationError, VMFunctionBody, VMSharedSignatureIndex,
};
/// An error condition while setting up a wasm instance, be it validation,
/// compilation, or instantiation.
@@ -42,6 +44,7 @@ struct RawCompiledModule<'data> {
finished_functions: BoxedSlice<DefinedFuncIndex, *const VMFunctionBody>,
imports: Imports,
data_initializers: Box<[DataInitializer<'data>]>,
signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
}
impl<'data> RawCompiledModule<'data> {
@@ -79,6 +82,16 @@ impl<'data> RawCompiledModule<'data> {
.collect::<PrimaryMap<_, _>>()
.into_boxed_slice();
// Compute indices into the shared signature table.
let signatures = {
let signature_registry = compiler.signatures();
let mut signatures = PrimaryMap::new();
for sig in translation.module.signatures.values() {
signatures.push(signature_registry.register(sig));
}
signatures
};
// Make all code compiled thus far executable.
compiler.publish_compiled_code();
@@ -87,6 +100,7 @@ impl<'data> RawCompiledModule<'data> {
finished_functions,
imports,
data_initializers: translation.data_initializers.into_boxed_slice(),
signatures: signatures.into_boxed_slice(),
})
}
}
@@ -97,6 +111,7 @@ pub struct CompiledModule {
finished_functions: BoxedSlice<DefinedFuncIndex, *const VMFunctionBody>,
imports: Imports,
data_initializers: Box<[OwnedDataInitializer]>,
signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
}
impl CompiledModule {
@@ -118,6 +133,7 @@ impl CompiledModule {
.map(OwnedDataInitializer::new)
.collect::<Vec<_>>()
.into_boxed_slice(),
signatures: raw.signatures.clone(),
})
}
@@ -127,12 +143,14 @@ impl CompiledModule {
finished_functions: BoxedSlice<DefinedFuncIndex, *const VMFunctionBody>,
imports: Imports,
data_initializers: Box<[OwnedDataInitializer]>,
signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
) -> Self {
Self {
module: Rc::new(module),
finished_functions,
imports,
data_initializers,
signatures,
}
}
@@ -155,6 +173,7 @@ impl CompiledModule {
self.finished_functions.clone(),
self.imports.clone(),
&data_initializers,
self.signatures.clone(),
)
}
}
@@ -194,6 +213,7 @@ pub fn instantiate(
raw.finished_functions,
raw.imports,
&*raw.data_initializers,
raw.signatures,
)
.map_err(SetupError::Instantiate)
}

View File

@@ -5,11 +5,11 @@ use cranelift_entity::EntityRef;
use cranelift_entity::{BoxedSlice, PrimaryMap};
use cranelift_wasm::{
DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, GlobalInit,
SignatureIndex,
};
use export::Export;
use imports::Imports;
use memory::LinearMemory;
use sig_registry::SignatureRegistry;
use signalhandlers::{wasmtime_init_eager, wasmtime_init_finish};
use std::rc::Rc;
use std::slice;
@@ -18,7 +18,7 @@ use table::Table;
use traphandlers::wasmtime_call;
use vmcontext::{
VMCallerCheckedAnyfunc, VMContext, VMFunctionBody, VMGlobalDefinition, VMMemoryDefinition,
VMTableDefinition,
VMSharedSignatureIndex, VMTableDefinition,
};
use wasmtime_environ::{DataInitializer, Module};
@@ -38,8 +38,7 @@ pub struct Instance {
tables: BoxedSlice<DefinedTableIndex, Table>,
/// Function Signature IDs.
/// FIXME: This should be shared across instances rather than per-Instance.
sig_registry: SignatureRegistry,
vmshared_signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
/// Resolved imports.
vmctx_imports: Imports,
@@ -67,8 +66,8 @@ impl Instance {
finished_functions: BoxedSlice<DefinedFuncIndex, *const VMFunctionBody>,
mut vmctx_imports: Imports,
data_initializers: &[DataInitializer],
mut vmshared_signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
) -> Result<Box<Self>, InstantiationError> {
let mut sig_registry = create_and_initialize_signatures(&module);
let mut tables = create_tables(&module);
let mut memories = create_memories(&module)?;
@@ -102,13 +101,14 @@ impl Instance {
let vmctx_tables_ptr = vmctx_tables.values_mut().into_slice().as_mut_ptr();
let vmctx_memories_ptr = vmctx_memories.values_mut().into_slice().as_mut_ptr();
let vmctx_globals_ptr = vmctx_globals.values_mut().into_slice().as_mut_ptr();
let vmctx_shared_signatures_ptr = sig_registry.vmshared_signatures();
let vmctx_shared_signatures_ptr =
vmshared_signatures.values_mut().into_slice().as_mut_ptr();
let mut result = Box::new(Self {
module,
memories,
tables,
sig_registry,
vmshared_signatures,
vmctx_imports,
finished_functions,
vmctx_tables,
@@ -399,14 +399,6 @@ fn check_memory_init_bounds(
Ok(())
}
fn create_and_initialize_signatures(module: &Module) -> SignatureRegistry {
let mut sig_registry = SignatureRegistry::new();
for (sig_index, sig) in module.signatures.iter() {
sig_registry.register(sig_index, sig);
}
sig_registry
}
/// Allocate memory for just the tables of the current module.
fn create_tables(module: &Module) -> BoxedSlice<DefinedTableIndex, Table> {
let num_imports = module.imported_tables.len();
@@ -453,7 +445,7 @@ fn initialize_tables(instance: &mut Instance) -> Result<(), InstantiationError>
let imported_func = &instance.vmctx_imports.functions[*func_idx];
(imported_func.body, imported_func.vmctx)
};
let type_index = instance.sig_registry.lookup(callee_sig);
let type_index = instance.vmshared_signatures[callee_sig];
subslice[i] = VMCallerCheckedAnyfunc {
func_ptr: callee_ptr,
type_index,

View File

@@ -62,11 +62,12 @@ pub use export::Export;
pub use imports::Imports;
pub use instance::{Instance, InstantiationError, LinkError};
pub use mmap::Mmap;
pub use sig_registry::SignatureRegistry;
pub use signalhandlers::{wasmtime_init_eager, wasmtime_init_finish};
pub use traphandlers::{wasmtime_call, wasmtime_call_trampoline};
pub use vmcontext::{
VMContext, VMFunctionBody, VMFunctionImport, VMGlobalDefinition, VMGlobalImport,
VMMemoryDefinition, VMMemoryImport, VMTableDefinition, VMTableImport,
VMMemoryDefinition, VMMemoryImport, VMSharedSignatureIndex, VMTableDefinition, VMTableImport,
};
#[cfg(not(feature = "std"))]

View File

@@ -3,53 +3,36 @@
use cast;
use cranelift_codegen::ir;
use cranelift_entity::PrimaryMap;
use cranelift_wasm::SignatureIndex;
use std::collections::{hash_map, HashMap};
use vmcontext::VMSharedSignatureIndex;
/// WebAssembly requires that the caller and callee signatures in an indirect
/// call must match. To implement this efficiently, keep a registry of all
/// signatures, shared by all instances, so that call sites can just do an
/// index comparison.
#[derive(Debug)]
pub struct SignatureRegistry {
signature_hash: HashMap<ir::Signature, VMSharedSignatureIndex>,
shared_signatures: PrimaryMap<SignatureIndex, VMSharedSignatureIndex>,
}
impl SignatureRegistry {
/// Create a new `SignatureRegistry`.
pub fn new() -> Self {
Self {
signature_hash: HashMap::new(),
shared_signatures: PrimaryMap::new(),
}
}
pub fn vmshared_signatures(&mut self) -> *mut VMSharedSignatureIndex {
self.shared_signatures
.values_mut()
.into_slice()
.as_mut_ptr()
}
/// Register the given signature.
pub fn register(&mut self, sig_index: SignatureIndex, sig: &ir::Signature) {
// TODO: Refactor this interface so that we're not passing in redundant
// information.
debug_assert_eq!(sig_index.index(), self.shared_signatures.len());
use cranelift_entity::EntityRef;
/// Register a signature and return its unique index.
pub fn register(&mut self, sig: &ir::Signature) -> VMSharedSignatureIndex {
let len = self.signature_hash.len();
let sig_id = match self.signature_hash.entry(sig.clone()) {
match self.signature_hash.entry(sig.clone()) {
hash_map::Entry::Occupied(entry) => *entry.get(),
hash_map::Entry::Vacant(entry) => {
let sig_id = VMSharedSignatureIndex::new(cast::u32(len).unwrap());
entry.insert(sig_id);
sig_id
}
};
self.shared_signatures.push(sig_id);
}
/// Return the identifying runtime index for the given signature.
pub fn lookup(&mut self, sig_index: SignatureIndex) -> VMSharedSignatureIndex {
self.shared_signatures[sig_index]
}
}

View File

@@ -403,6 +403,7 @@ mod test_vmshared_signature_index {
}
impl VMSharedSignatureIndex {
/// Create a new `VMSharedSignatureIndex`.
pub fn new(value: u32) -> Self {
VMSharedSignatureIndex(value)
}

View File

@@ -216,12 +216,14 @@ pub fn instantiate_spectest() -> Result<Box<Instance>, InstantiationError> {
let imports = Imports::none();
let data_initializers = Vec::new();
let signatures = PrimaryMap::new();
CompiledModule::from_parts(
module,
finished_functions.into_boxed_slice(),
imports,
data_initializers.into_boxed_slice(),
signatures.into_boxed_slice(),
)
.instantiate()
}