Implement cross-instance indirect calls.
This commit is contained in:
@@ -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.
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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"))]
|
||||||
|
|||||||
@@ -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]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user