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

View File

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

View File

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

View File

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

View File

@@ -3,53 +3,36 @@
use cast; use cast;
use cranelift_codegen::ir; use cranelift_codegen::ir;
use cranelift_entity::PrimaryMap;
use cranelift_wasm::SignatureIndex;
use std::collections::{hash_map, HashMap}; use std::collections::{hash_map, HashMap};
use vmcontext::VMSharedSignatureIndex; 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)] #[derive(Debug)]
pub struct SignatureRegistry { pub struct SignatureRegistry {
signature_hash: HashMap<ir::Signature, VMSharedSignatureIndex>, signature_hash: HashMap<ir::Signature, VMSharedSignatureIndex>,
shared_signatures: PrimaryMap<SignatureIndex, VMSharedSignatureIndex>,
} }
impl SignatureRegistry { impl SignatureRegistry {
/// Create a new `SignatureRegistry`.
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
signature_hash: HashMap::new(), signature_hash: HashMap::new(),
shared_signatures: PrimaryMap::new(),
} }
} }
pub fn vmshared_signatures(&mut self) -> *mut VMSharedSignatureIndex { /// Register a signature and return its unique index.
self.shared_signatures pub fn register(&mut self, sig: &ir::Signature) -> VMSharedSignatureIndex {
.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;
let len = self.signature_hash.len(); 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::Occupied(entry) => *entry.get(),
hash_map::Entry::Vacant(entry) => { hash_map::Entry::Vacant(entry) => {
let sig_id = VMSharedSignatureIndex::new(cast::u32(len).unwrap()); let sig_id = VMSharedSignatureIndex::new(cast::u32(len).unwrap());
entry.insert(sig_id); entry.insert(sig_id);
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 { impl VMSharedSignatureIndex {
/// Create a new `VMSharedSignatureIndex`.
pub fn new(value: u32) -> Self { pub fn new(value: u32) -> Self {
VMSharedSignatureIndex(value) VMSharedSignatureIndex(value)
} }

View File

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