Implement cross-instance indirect calls.
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"))]
|
||||
|
||||
@@ -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]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,6 +403,7 @@ mod test_vmshared_signature_index {
|
||||
}
|
||||
|
||||
impl VMSharedSignatureIndex {
|
||||
/// Create a new `VMSharedSignatureIndex`.
|
||||
pub fn new(value: u32) -> Self {
|
||||
VMSharedSignatureIndex(value)
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user