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:
Alex Crichton
2020-10-25 15:54:21 -07:00
parent de4af90af6
commit 3887881800
14 changed files with 159 additions and 181 deletions

View File

@@ -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) }

View File

@@ -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,

View File

@@ -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))
}
}

View File

@@ -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 {