Refactor how signatures/trampolines are stored in Store
This commit refactors where trampolines and signature information is stored within a `Store`, namely moving them from `wasmtime_runtime::Instance` instead to `Store` itself. The goal here is to remove an allocation inside of an `Instance` and make them a bit cheaper to create. Additionally this should open up future possibilities like not creating duplicate trampolines for signatures already in the `Store` when using `Func::new`.
This commit is contained in:
@@ -11,7 +11,7 @@ use crate::traphandlers::Trap;
|
||||
use crate::vmcontext::{
|
||||
VMBuiltinFunctionsArray, VMCallerCheckedAnyfunc, VMContext, VMFunctionBody, VMFunctionImport,
|
||||
VMGlobalDefinition, VMGlobalImport, VMInterrupts, VMMemoryDefinition, VMMemoryImport,
|
||||
VMSharedSignatureIndex, VMTableDefinition, VMTableImport, VMTrampoline,
|
||||
VMSharedSignatureIndex, VMTableDefinition, VMTableImport,
|
||||
};
|
||||
use crate::{ExportFunction, ExportGlobal, ExportMemory, ExportTable};
|
||||
use memoffset::offset_of;
|
||||
@@ -62,9 +62,6 @@ pub(crate) struct Instance {
|
||||
/// get removed. A missing entry is considered equivalent to an empty slice.
|
||||
passive_data: RefCell<HashMap<DataIndex, Arc<[u8]>>>,
|
||||
|
||||
/// Pointers to trampoline functions used to enter particular signatures
|
||||
trampolines: HashMap<VMSharedSignatureIndex, VMTrampoline>,
|
||||
|
||||
/// Hosts can store arbitrary per-instance information here.
|
||||
host_state: Box<dyn Any>,
|
||||
|
||||
@@ -815,10 +812,9 @@ impl InstanceHandle {
|
||||
module: Arc<Module>,
|
||||
code: Arc<dyn Any>,
|
||||
finished_functions: &PrimaryMap<DefinedFuncIndex, *mut [VMFunctionBody]>,
|
||||
trampolines: HashMap<VMSharedSignatureIndex, VMTrampoline>,
|
||||
imports: Imports,
|
||||
mem_creator: Option<&dyn RuntimeMemoryCreator>,
|
||||
vmshared_signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
|
||||
lookup_shared_signature: &dyn Fn(SignatureIndex) -> VMSharedSignatureIndex,
|
||||
host_state: Box<dyn Any>,
|
||||
interrupts: *const VMInterrupts,
|
||||
externref_activations_table: *mut VMExternRefActivationsTable,
|
||||
@@ -857,7 +853,6 @@ impl InstanceHandle {
|
||||
tables,
|
||||
passive_elements: Default::default(),
|
||||
passive_data,
|
||||
trampolines,
|
||||
host_state,
|
||||
vmctx: VMContext {},
|
||||
};
|
||||
@@ -873,12 +868,12 @@ impl InstanceHandle {
|
||||
};
|
||||
let instance = handle.instance();
|
||||
|
||||
debug_assert_eq!(vmshared_signatures.len(), handle.module().signatures.len());
|
||||
ptr::copy(
|
||||
vmshared_signatures.values().as_slice().as_ptr(),
|
||||
instance.signature_ids_ptr() as *mut VMSharedSignatureIndex,
|
||||
vmshared_signatures.len(),
|
||||
);
|
||||
let mut ptr = instance.signature_ids_ptr();
|
||||
for (signature, _) in handle.module().signatures.iter() {
|
||||
*ptr = lookup_shared_signature(signature);
|
||||
ptr = ptr.add(1);
|
||||
}
|
||||
|
||||
debug_assert_eq!(imports.functions.len(), handle.module().num_imported_funcs);
|
||||
ptr::copy(
|
||||
imports.functions.as_ptr(),
|
||||
@@ -1128,11 +1123,6 @@ impl InstanceHandle {
|
||||
self.instance().get_defined_table(index)
|
||||
}
|
||||
|
||||
/// Gets the trampoline pre-registered for a particular signature
|
||||
pub fn trampoline(&self, sig: VMSharedSignatureIndex) -> Option<VMTrampoline> {
|
||||
self.instance().trampolines.get(&sig).cloned()
|
||||
}
|
||||
|
||||
/// Return a reference to the contained `Instance`.
|
||||
pub(crate) fn instance(&self) -> &Instance {
|
||||
unsafe { &*(self.instance as *const Instance) }
|
||||
|
||||
@@ -28,7 +28,6 @@ mod instance;
|
||||
mod jit_int;
|
||||
mod memory;
|
||||
mod mmap;
|
||||
mod sig_registry;
|
||||
mod table;
|
||||
mod traphandlers;
|
||||
mod vmcontext;
|
||||
@@ -43,7 +42,6 @@ pub use crate::instance::{InstanceHandle, InstantiationError, LinkError};
|
||||
pub use crate::jit_int::GdbJitImageRegistration;
|
||||
pub use crate::memory::{RuntimeLinearMemory, RuntimeMemoryCreator};
|
||||
pub use crate::mmap::Mmap;
|
||||
pub use crate::sig_registry::SignatureRegistry;
|
||||
pub use crate::table::{Table, TableElement};
|
||||
pub use crate::traphandlers::{
|
||||
catch_traps, init_traps, raise_lib_trap, raise_user_trap, resume_panic, SignalHandler, Trap,
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
//! Implement a registry of function signatures, for fast indirect call
|
||||
//! signature checking.
|
||||
|
||||
use crate::vmcontext::VMSharedSignatureIndex;
|
||||
use more_asserts::assert_lt;
|
||||
use std::collections::{hash_map, HashMap};
|
||||
use std::convert::TryFrom;
|
||||
use wasmtime_environ::{ir, wasm::WasmFuncType};
|
||||
|
||||
/// 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, Default)]
|
||||
pub struct SignatureRegistry {
|
||||
wasm2index: HashMap<WasmFuncType, VMSharedSignatureIndex>,
|
||||
|
||||
// Maps the index to the original Wasm signature.
|
||||
index2wasm: HashMap<VMSharedSignatureIndex, WasmFuncType>,
|
||||
|
||||
// Maps the index to the native signature.
|
||||
index2native: HashMap<VMSharedSignatureIndex, ir::Signature>,
|
||||
}
|
||||
|
||||
impl SignatureRegistry {
|
||||
/// Register a signature and return its unique index.
|
||||
pub fn register(
|
||||
&mut self,
|
||||
wasm: WasmFuncType,
|
||||
native: ir::Signature,
|
||||
) -> VMSharedSignatureIndex {
|
||||
let len = self.wasm2index.len();
|
||||
|
||||
match self.wasm2index.entry(wasm.clone()) {
|
||||
hash_map::Entry::Occupied(entry) => *entry.get(),
|
||||
hash_map::Entry::Vacant(entry) => {
|
||||
// Keep `signature_hash` len under 2**32 -- VMSharedSignatureIndex::new(std::u32::MAX)
|
||||
// is reserved for VMSharedSignatureIndex::default().
|
||||
assert_lt!(
|
||||
len,
|
||||
std::u32::MAX as usize,
|
||||
"Invariant check: signature_hash.len() < std::u32::MAX"
|
||||
);
|
||||
let index = VMSharedSignatureIndex::new(u32::try_from(len).unwrap());
|
||||
entry.insert(index);
|
||||
self.index2wasm.insert(index, wasm);
|
||||
self.index2native.insert(index, native);
|
||||
index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Looks up a shared index from the wasm signature itself.
|
||||
pub fn lookup(&self, wasm: &WasmFuncType) -> Option<VMSharedSignatureIndex> {
|
||||
self.wasm2index.get(wasm).cloned()
|
||||
}
|
||||
|
||||
/// Looks up a shared native signature within this registry.
|
||||
///
|
||||
/// Note that for this operation to be semantically correct the `idx` must
|
||||
/// have previously come from a call to `register` of this same object.
|
||||
pub fn lookup_native(&self, idx: VMSharedSignatureIndex) -> Option<ir::Signature> {
|
||||
self.index2native.get(&idx).cloned()
|
||||
}
|
||||
|
||||
/// Looks up a shared Wasm signature within this registry.
|
||||
///
|
||||
/// Note that for this operation to be semantically correct the `idx` must
|
||||
/// have previously come from a call to `register` of this same object.
|
||||
pub fn lookup_wasm(&self, idx: VMSharedSignatureIndex) -> Option<WasmFuncType> {
|
||||
self.index2wasm.get(&idx).cloned()
|
||||
}
|
||||
|
||||
/// Looks up both a shared Wasm function signature and its associated native
|
||||
/// `ir::Signature` within this registry.
|
||||
///
|
||||
/// Note that for this operation to be semantically correct the `idx` must
|
||||
/// have previously come from a call to `register` of this same object.
|
||||
pub fn lookup_wasm_and_native_signatures(
|
||||
&self,
|
||||
idx: VMSharedSignatureIndex,
|
||||
) -> Option<(WasmFuncType, ir::Signature)> {
|
||||
let wasm = self.lookup_wasm(idx)?;
|
||||
let native = self.lookup_native(idx)?;
|
||||
Some((wasm, native))
|
||||
}
|
||||
}
|
||||
@@ -492,6 +492,11 @@ impl VMSharedSignatureIndex {
|
||||
pub fn new(value: u32) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
|
||||
/// Returns the underlying bits of the index.
|
||||
pub fn bits(&self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for VMSharedSignatureIndex {
|
||||
|
||||
Reference in New Issue
Block a user