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

@@ -10,7 +10,6 @@ use crate::object::ObjectUnwindInfo;
use object::File as ObjectFile; use object::File as ObjectFile;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::any::Any; use std::any::Any;
use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use thiserror::Error; use thiserror::Error;
use wasmtime_debug::create_gdbjit_image; use wasmtime_debug::create_gdbjit_image;
@@ -24,8 +23,8 @@ use wasmtime_environ::{
use wasmtime_profiling::ProfilingAgent; use wasmtime_profiling::ProfilingAgent;
use wasmtime_runtime::{ use wasmtime_runtime::{
GdbJitImageRegistration, Imports, InstanceHandle, InstantiationError, RuntimeMemoryCreator, GdbJitImageRegistration, Imports, InstanceHandle, InstantiationError, RuntimeMemoryCreator,
SignatureRegistry, StackMapRegistry, VMExternRefActivationsTable, VMFunctionBody, VMInterrupts, StackMapRegistry, VMExternRefActivationsTable, VMFunctionBody, VMInterrupts,
VMTrampoline, VMSharedSignatureIndex, VMTrampoline,
}; };
/// An error condition while setting up a wasm instance, be it validation, /// An error condition while setting up a wasm instance, be it validation,
@@ -248,37 +247,20 @@ impl CompiledModule {
pub unsafe fn instantiate( pub unsafe fn instantiate(
&self, &self,
imports: Imports<'_>, imports: Imports<'_>,
signature_registry: &mut SignatureRegistry, lookup_shared_signature: &dyn Fn(SignatureIndex) -> VMSharedSignatureIndex,
mem_creator: Option<&dyn RuntimeMemoryCreator>, mem_creator: Option<&dyn RuntimeMemoryCreator>,
interrupts: *const VMInterrupts, interrupts: *const VMInterrupts,
host_state: Box<dyn Any>, host_state: Box<dyn Any>,
externref_activations_table: *mut VMExternRefActivationsTable, externref_activations_table: *mut VMExternRefActivationsTable,
stack_map_registry: *mut StackMapRegistry, stack_map_registry: *mut StackMapRegistry,
) -> Result<InstanceHandle, InstantiationError> { ) -> Result<InstanceHandle, InstantiationError> {
// Compute indices into the shared signature table.
let signatures = {
self.module
.signatures
.values()
.map(|(wasm_sig, native)| {
signature_registry.register(wasm_sig.clone(), native.clone())
})
.collect::<PrimaryMap<_, _>>()
};
let mut trampolines = HashMap::new();
for (i, trampoline) in self.trampolines.iter() {
trampolines.insert(signatures[i], trampoline.clone());
}
InstanceHandle::new( InstanceHandle::new(
self.module.clone(), self.module.clone(),
self.code.clone(), self.code.clone(),
&self.finished_functions.0, &self.finished_functions.0,
trampolines,
imports, imports,
mem_creator, mem_creator,
signatures.into_boxed_slice(), lookup_shared_signature,
host_state, host_state,
interrupts, interrupts,
externref_activations_table, externref_activations_table,
@@ -312,6 +294,11 @@ impl CompiledModule {
&self.finished_functions.0 &self.finished_functions.0
} }
/// Returns the per-signature trampolines for this module.
pub fn trampolines(&self) -> &PrimaryMap<SignatureIndex, VMTrampoline> {
&self.trampolines
}
/// Returns the stack map information for all functions defined in this /// Returns the stack map information for all functions defined in this
/// module. /// module.
/// ///

View File

@@ -11,7 +11,7 @@ use crate::traphandlers::Trap;
use crate::vmcontext::{ use crate::vmcontext::{
VMBuiltinFunctionsArray, VMCallerCheckedAnyfunc, VMContext, VMFunctionBody, VMFunctionImport, VMBuiltinFunctionsArray, VMCallerCheckedAnyfunc, VMContext, VMFunctionBody, VMFunctionImport,
VMGlobalDefinition, VMGlobalImport, VMInterrupts, VMMemoryDefinition, VMMemoryImport, VMGlobalDefinition, VMGlobalImport, VMInterrupts, VMMemoryDefinition, VMMemoryImport,
VMSharedSignatureIndex, VMTableDefinition, VMTableImport, VMTrampoline, VMSharedSignatureIndex, VMTableDefinition, VMTableImport,
}; };
use crate::{ExportFunction, ExportGlobal, ExportMemory, ExportTable}; use crate::{ExportFunction, ExportGlobal, ExportMemory, ExportTable};
use memoffset::offset_of; use memoffset::offset_of;
@@ -62,9 +62,6 @@ pub(crate) struct Instance {
/// get removed. A missing entry is considered equivalent to an empty slice. /// get removed. A missing entry is considered equivalent to an empty slice.
passive_data: RefCell<HashMap<DataIndex, Arc<[u8]>>>, 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. /// Hosts can store arbitrary per-instance information here.
host_state: Box<dyn Any>, host_state: Box<dyn Any>,
@@ -815,10 +812,9 @@ impl InstanceHandle {
module: Arc<Module>, module: Arc<Module>,
code: Arc<dyn Any>, code: Arc<dyn Any>,
finished_functions: &PrimaryMap<DefinedFuncIndex, *mut [VMFunctionBody]>, finished_functions: &PrimaryMap<DefinedFuncIndex, *mut [VMFunctionBody]>,
trampolines: HashMap<VMSharedSignatureIndex, VMTrampoline>,
imports: Imports, imports: Imports,
mem_creator: Option<&dyn RuntimeMemoryCreator>, mem_creator: Option<&dyn RuntimeMemoryCreator>,
vmshared_signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>, lookup_shared_signature: &dyn Fn(SignatureIndex) -> VMSharedSignatureIndex,
host_state: Box<dyn Any>, host_state: Box<dyn Any>,
interrupts: *const VMInterrupts, interrupts: *const VMInterrupts,
externref_activations_table: *mut VMExternRefActivationsTable, externref_activations_table: *mut VMExternRefActivationsTable,
@@ -857,7 +853,6 @@ impl InstanceHandle {
tables, tables,
passive_elements: Default::default(), passive_elements: Default::default(),
passive_data, passive_data,
trampolines,
host_state, host_state,
vmctx: VMContext {}, vmctx: VMContext {},
}; };
@@ -873,12 +868,12 @@ impl InstanceHandle {
}; };
let instance = handle.instance(); let instance = handle.instance();
debug_assert_eq!(vmshared_signatures.len(), handle.module().signatures.len()); let mut ptr = instance.signature_ids_ptr();
ptr::copy( for (signature, _) in handle.module().signatures.iter() {
vmshared_signatures.values().as_slice().as_ptr(), *ptr = lookup_shared_signature(signature);
instance.signature_ids_ptr() as *mut VMSharedSignatureIndex, ptr = ptr.add(1);
vmshared_signatures.len(), }
);
debug_assert_eq!(imports.functions.len(), handle.module().num_imported_funcs); debug_assert_eq!(imports.functions.len(), handle.module().num_imported_funcs);
ptr::copy( ptr::copy(
imports.functions.as_ptr(), imports.functions.as_ptr(),
@@ -1128,11 +1123,6 @@ impl InstanceHandle {
self.instance().get_defined_table(index) 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`. /// Return a reference to the contained `Instance`.
pub(crate) fn instance(&self) -> &Instance { pub(crate) fn instance(&self) -> &Instance {
unsafe { &*(self.instance as *const Instance) } unsafe { &*(self.instance as *const Instance) }

View File

@@ -28,7 +28,6 @@ mod instance;
mod jit_int; mod jit_int;
mod memory; mod memory;
mod mmap; mod mmap;
mod sig_registry;
mod table; mod table;
mod traphandlers; mod traphandlers;
mod vmcontext; mod vmcontext;
@@ -43,7 +42,6 @@ pub use crate::instance::{InstanceHandle, InstantiationError, LinkError};
pub use crate::jit_int::GdbJitImageRegistration; pub use crate::jit_int::GdbJitImageRegistration;
pub use crate::memory::{RuntimeLinearMemory, RuntimeMemoryCreator}; pub use crate::memory::{RuntimeLinearMemory, RuntimeMemoryCreator};
pub use crate::mmap::Mmap; pub use crate::mmap::Mmap;
pub use crate::sig_registry::SignatureRegistry;
pub use crate::table::{Table, TableElement}; pub use crate::table::{Table, TableElement};
pub use crate::traphandlers::{ pub use crate::traphandlers::{
catch_traps, init_traps, raise_lib_trap, raise_user_trap, resume_panic, SignalHandler, Trap, catch_traps, init_traps, raise_lib_trap, raise_user_trap, resume_panic, SignalHandler, Trap,

View File

@@ -492,6 +492,11 @@ impl VMSharedSignatureIndex {
pub fn new(value: u32) -> Self { pub fn new(value: u32) -> Self {
Self(value) Self(value)
} }
/// Returns the underlying bits of the index.
pub fn bits(&self) -> u32 {
self.0
}
} }
impl Default for VMSharedSignatureIndex { impl Default for VMSharedSignatureIndex {

View File

@@ -540,7 +540,10 @@ impl Func {
pub fn ty(&self) -> FuncType { pub fn ty(&self) -> FuncType {
// Signatures should always be registered in the store's registry of // Signatures should always be registered in the store's registry of
// shared signatures, so we should be able to unwrap safely here. // shared signatures, so we should be able to unwrap safely here.
let wft = self.instance.store.lookup_signature(self.sig_index()); let signatures = self.instance.store.signatures().borrow();
let (wft, _, _) = signatures
.lookup_shared(self.sig_index())
.expect("signature should be registered");
// This is only called with `Export::Function`, and since it's coming // This is only called with `Export::Function`, and since it's coming
// from wasmtime_runtime itself we should support all the types coming // from wasmtime_runtime itself we should support all the types coming
@@ -550,19 +553,19 @@ impl Func {
/// Returns the number of parameters that this function takes. /// Returns the number of parameters that this function takes.
pub fn param_arity(&self) -> usize { pub fn param_arity(&self) -> usize {
let sig = self let signatures = self.instance.store.signatures().borrow();
.instance let (sig, _, _) = signatures
.store .lookup_shared(self.sig_index())
.lookup_signature(unsafe { self.export.anyfunc.as_ref().type_index }); .expect("signature should be registered");
sig.params.len() sig.params.len()
} }
/// Returns the number of results this function produces. /// Returns the number of results this function produces.
pub fn result_arity(&self) -> usize { pub fn result_arity(&self) -> usize {
let sig = self let signatures = self.instance.store.signatures().borrow();
.instance let (sig, _, _) = signatures
.store .lookup_shared(self.sig_index())
.lookup_signature(unsafe { self.export.anyfunc.as_ref().type_index }); .expect("signature should be registered");
sig.returns.len() sig.returns.len()
} }
@@ -649,8 +652,12 @@ impl Func {
// on that module as well, so unwrap the result here since otherwise // on that module as well, so unwrap the result here since otherwise
// it's a bug in wasmtime. // it's a bug in wasmtime.
let trampoline = instance let trampoline = instance
.trampoline(unsafe { export.anyfunc.as_ref().type_index }) .store
.expect("failed to retrieve trampoline from module"); .signatures()
.borrow()
.lookup_shared(unsafe { export.anyfunc.as_ref().type_index })
.expect("failed to retrieve trampoline from module")
.2;
Func { Func {
instance, instance,

View File

@@ -20,7 +20,7 @@ fn instantiate(
let instance = unsafe { let instance = unsafe {
let instance = compiled_module.instantiate( let instance = compiled_module.instantiate(
imports, imports,
&mut store.signatures_mut(), &store.lookup_shared_signature(compiled_module.module()),
config.memory_creator.as_ref().map(|a| a as _), config.memory_creator.as_ref().map(|a| a as _),
store.interrupts(), store.interrupts(),
host, host,
@@ -161,12 +161,8 @@ impl Instance {
bail!("cross-`Engine` instantiation is not currently supported"); bail!("cross-`Engine` instantiation is not currently supported");
} }
let host_info = Box::new({ store.register_module(&module);
let frame_info_registration = module.register_frame_info(); let host_info = Box::new(module.register_frame_info());
store.register_jit_code(&module);
store.register_stack_maps(&module);
frame_info_registration
});
let handle = with_imports(store, module.compiled_module(), imports, |imports| { let handle = with_imports(store, module.compiled_module(), imports, |imports| {
instantiate(store, module.compiled_module(), imports, host_info) instantiate(store, module.compiled_module(), imports, host_info)
@@ -295,7 +291,8 @@ fn with_imports<R>(
// functions registered with that type, so `func` is guaranteed // functions registered with that type, so `func` is guaranteed
// to not match. // to not match.
let ty = store let ty = store
.signatures_mut() .signatures()
.borrow()
.lookup(&m.signatures[m.functions[i]].0) .lookup(&m.signatures[m.functions[i]].0)
.ok_or_else(|| anyhow!("function types incompatible"))?; .ok_or_else(|| anyhow!("function types incompatible"))?;
if !func.matches_expected(ty) { if !func.matches_expected(ty) {

View File

@@ -242,6 +242,7 @@ mod linker;
mod module; mod module;
mod r#ref; mod r#ref;
mod runtime; mod runtime;
mod sig_registry;
mod trampoline; mod trampoline;
mod trap; mod trap;
mod types; mod types;

View File

@@ -1,4 +1,5 @@
use crate::externals::MemoryCreator; use crate::externals::MemoryCreator;
use crate::sig_registry::SignatureRegistry;
use crate::trampoline::{MemoryCreatorProxy, StoreInstanceHandle}; use crate::trampoline::{MemoryCreatorProxy, StoreInstanceHandle};
use crate::Module; use crate::Module;
use anyhow::{bail, Result}; use anyhow::{bail, Result};
@@ -16,13 +17,12 @@ use wasmparser::WasmFeatures;
#[cfg(feature = "cache")] #[cfg(feature = "cache")]
use wasmtime_cache::CacheConfig; use wasmtime_cache::CacheConfig;
use wasmtime_environ::settings::{self, Configurable, SetError}; use wasmtime_environ::settings::{self, Configurable, SetError};
use wasmtime_environ::{ir, isa, isa::TargetIsa, wasm, Tunables}; use wasmtime_environ::{isa, isa::TargetIsa, wasm, Tunables};
use wasmtime_jit::{native, CompilationStrategy, Compiler}; use wasmtime_jit::{native, CompilationStrategy, Compiler};
use wasmtime_profiling::{JitDumpAgent, NullProfilerAgent, ProfilingAgent, VTuneAgent}; use wasmtime_profiling::{JitDumpAgent, NullProfilerAgent, ProfilingAgent, VTuneAgent};
use wasmtime_runtime::{ use wasmtime_runtime::{
debug_builtins, InstanceHandle, RuntimeMemoryCreator, SignalHandler, SignatureRegistry, debug_builtins, InstanceHandle, RuntimeMemoryCreator, SignalHandler, StackMapRegistry,
StackMapRegistry, VMExternRef, VMExternRefActivationsTable, VMInterrupts, VMExternRef, VMExternRefActivationsTable, VMInterrupts, VMSharedSignatureIndex,
VMSharedSignatureIndex,
}; };
// Runtime Environment // Runtime Environment
@@ -915,38 +915,21 @@ impl Store {
.map(|x| x as _) .map(|x| x as _)
} }
pub(crate) fn lookup_signature(&self, sig_index: VMSharedSignatureIndex) -> wasm::WasmFuncType { pub(crate) fn signatures(&self) -> &RefCell<SignatureRegistry> {
self.inner &self.inner.signatures
.signatures }
pub(crate) fn lookup_shared_signature<'a>(
&'a self,
module: &'a wasmtime_environ::Module,
) -> impl Fn(wasm::SignatureIndex) -> VMSharedSignatureIndex + 'a {
move |index| {
let (wasm, _native) = &module.signatures[index];
self.signatures()
.borrow() .borrow()
.lookup_wasm(sig_index) .lookup(wasm)
.expect("failed to lookup signature") .expect("signature not previously registered")
} }
pub(crate) fn lookup_wasm_and_native_signatures(
&self,
sig_index: VMSharedSignatureIndex,
) -> (wasm::WasmFuncType, ir::Signature) {
self.inner
.signatures
.borrow()
.lookup_wasm_and_native_signatures(sig_index)
.expect("failed to lookup signature")
}
pub(crate) fn register_signature(
&self,
wasm_sig: wasm::WasmFuncType,
native: ir::Signature,
) -> VMSharedSignatureIndex {
self.inner
.signatures
.borrow_mut()
.register(wasm_sig, native)
}
pub(crate) fn signatures_mut(&self) -> std::cell::RefMut<'_, SignatureRegistry> {
self.inner.signatures.borrow_mut()
} }
/// Returns whether or not the given address falls within the JIT code /// Returns whether or not the given address falls within the JIT code
@@ -959,7 +942,32 @@ impl Store {
.any(|(start, end)| *start <= addr && addr < *end) .any(|(start, end)| *start <= addr && addr < *end)
} }
pub(crate) fn register_jit_code(&self, module: &Module) { pub(crate) fn register_module(&self, module: &Module) {
// All modules register their JIT code in a store for two reasons
// currently:
//
// * First we only catch signals/traps if the program counter falls
// within the jit code of an instantiated wasm module. This ensures
// we don't catch accidental Rust/host segfaults.
//
// * Second when generating a backtrace we'll use this mapping to
// only generate wasm frames for instruction pointers that fall
// within jit code.
self.register_jit_code(module);
// We need to know about all the stack maps of all instantiated modules
// so when performing a GC we know about all wasm frames that we find
// on the stack.
self.register_stack_maps(module);
// Signatures are loaded into our `SignatureRegistry` here
// once-per-module (and once-per-signature). This allows us to create
// a `Func` wrapper for any function in the module, which requires that
// we know about the signature and trampoline for all instances.
self.register_signatures(module);
}
fn register_jit_code(&self, module: &Module) {
let mut ranges = module.compiled_module().jit_code_ranges(); let mut ranges = module.compiled_module().jit_code_ranges();
// Checking of we already registered JIT code ranges by searching // Checking of we already registered JIT code ranges by searching
// first range start. // first range start.
@@ -977,7 +985,7 @@ impl Store {
} }
} }
pub(crate) fn register_stack_maps(&self, module: &Module) { fn register_stack_maps(&self, module: &Module) {
let module = &module.compiled_module(); let module = &module.compiled_module();
self.stack_map_registry() self.stack_map_registry()
.register_stack_maps(module.stack_maps().map(|(func, stack_maps)| unsafe { .register_stack_maps(module.stack_maps().map(|(func, stack_maps)| unsafe {
@@ -990,6 +998,15 @@ impl Store {
})); }));
} }
fn register_signatures(&self, module: &Module) {
let trampolines = module.compiled_module().trampolines();
let module = module.compiled_module().module();
let mut signatures = self.signatures().borrow_mut();
for (index, (wasm, native)) in module.signatures.iter() {
signatures.register(wasm, native, trampolines[index]);
}
}
pub(crate) unsafe fn add_instance(&self, handle: InstanceHandle) -> StoreInstanceHandle { pub(crate) unsafe fn add_instance(&self, handle: InstanceHandle) -> StoreInstanceHandle {
self.inner.instances.borrow_mut().push(handle.clone()); self.inner.instances.borrow_mut().push(handle.clone());
StoreInstanceHandle { StoreInstanceHandle {

View File

@@ -1,11 +1,10 @@
//! Implement a registry of function signatures, for fast indirect call //! Implement a registry of function signatures, for fast indirect call
//! signature checking. //! signature checking.
use crate::vmcontext::VMSharedSignatureIndex;
use more_asserts::assert_lt;
use std::collections::{hash_map, HashMap}; use std::collections::{hash_map, HashMap};
use std::convert::TryFrom; use std::convert::TryFrom;
use wasmtime_environ::{ir, wasm::WasmFuncType}; use wasmtime_environ::{ir, wasm::WasmFuncType};
use wasmtime_runtime::{VMSharedSignatureIndex, VMTrampoline};
/// WebAssembly requires that the caller and callee signatures in an indirect /// WebAssembly requires that the caller and callee signatures in an indirect
/// call must match. To implement this efficiently, keep a registry of all /// call must match. To implement this efficiently, keep a registry of all
@@ -13,21 +12,35 @@ use wasmtime_environ::{ir, wasm::WasmFuncType};
/// index comparison. /// index comparison.
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct SignatureRegistry { pub struct SignatureRegistry {
// Map from a wasm actual function type to the index that it is assigned,
// shared amongst all wasm modules.
wasm2index: HashMap<WasmFuncType, VMSharedSignatureIndex>, wasm2index: HashMap<WasmFuncType, VMSharedSignatureIndex>,
// Maps the index to the original Wasm signature. // Map of all known wasm function signatures in this registry. This is
index2wasm: HashMap<VMSharedSignatureIndex, WasmFuncType>, // keyed by `VMSharedSignatureIndex` above.
index_map: Vec<Entry>,
}
// Maps the index to the native signature. #[derive(Debug)]
index2native: HashMap<VMSharedSignatureIndex, ir::Signature>, struct Entry {
// The WebAssembly type signature, using wasm types.
wasm: WasmFuncType,
// The native signature we're using for this wasm type signature.
native: ir::Signature,
// The native trampoline used to invoke this type signature from `Func`.
// Note that the code memory for this trampoline is not owned by this
// type, but instead it's expected to be owned by the store that this
// registry lives within.
trampoline: VMTrampoline,
} }
impl SignatureRegistry { impl SignatureRegistry {
/// Register a signature and return its unique index. /// Register a signature and return its unique index.
pub fn register( pub fn register(
&mut self, &mut self,
wasm: WasmFuncType, wasm: &WasmFuncType,
native: ir::Signature, native: &ir::Signature,
trampoline: VMTrampoline,
) -> VMSharedSignatureIndex { ) -> VMSharedSignatureIndex {
let len = self.wasm2index.len(); let len = self.wasm2index.len();
@@ -36,15 +49,18 @@ impl SignatureRegistry {
hash_map::Entry::Vacant(entry) => { hash_map::Entry::Vacant(entry) => {
// Keep `signature_hash` len under 2**32 -- VMSharedSignatureIndex::new(std::u32::MAX) // Keep `signature_hash` len under 2**32 -- VMSharedSignatureIndex::new(std::u32::MAX)
// is reserved for VMSharedSignatureIndex::default(). // is reserved for VMSharedSignatureIndex::default().
assert_lt!( assert!(
len, len < std::u32::MAX as usize,
std::u32::MAX as usize,
"Invariant check: signature_hash.len() < std::u32::MAX" "Invariant check: signature_hash.len() < std::u32::MAX"
); );
debug_assert_eq!(len, self.index_map.len());
let index = VMSharedSignatureIndex::new(u32::try_from(len).unwrap()); let index = VMSharedSignatureIndex::new(u32::try_from(len).unwrap());
self.index_map.push(Entry {
wasm: wasm.clone(),
native: native.clone(),
trampoline,
});
entry.insert(index); entry.insert(index);
self.index2wasm.insert(index, wasm);
self.index2native.insert(index, native);
index index
} }
} }
@@ -55,33 +71,16 @@ impl SignatureRegistry {
self.wasm2index.get(wasm).cloned() self.wasm2index.get(wasm).cloned()
} }
/// Looks up a shared native signature within this registry. /// Looks up information known about a shared signature index.
/// ///
/// Note that for this operation to be semantically correct the `idx` must /// Note that for this operation to be semantically correct the `idx` must
/// have previously come from a call to `register` of this same object. /// have previously come from a call to `register` of this same object.
pub fn lookup_native(&self, idx: VMSharedSignatureIndex) -> Option<ir::Signature> { pub fn lookup_shared(
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, &self,
idx: VMSharedSignatureIndex, idx: VMSharedSignatureIndex,
) -> Option<(WasmFuncType, ir::Signature)> { ) -> Option<(&WasmFuncType, &ir::Signature, VMTrampoline)> {
let wasm = self.lookup_wasm(idx)?; self.index_map
let native = self.lookup_native(idx)?; .get(idx.bits() as usize)
Some((wasm, native)) .map(|e| (&e.wasm, &e.native, e.trampoline))
} }
} }

View File

@@ -4,43 +4,35 @@ use crate::trampoline::StoreInstanceHandle;
use crate::Store; use crate::Store;
use anyhow::Result; use anyhow::Result;
use std::any::Any; use std::any::Any;
use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use wasmtime_environ::entity::PrimaryMap; use wasmtime_environ::entity::PrimaryMap;
use wasmtime_environ::wasm::DefinedFuncIndex; use wasmtime_environ::wasm::DefinedFuncIndex;
use wasmtime_environ::Module; use wasmtime_environ::Module;
use wasmtime_runtime::{ use wasmtime_runtime::{
Imports, InstanceHandle, StackMapRegistry, VMExternRefActivationsTable, VMFunctionBody, Imports, InstanceHandle, StackMapRegistry, VMExternRefActivationsTable, VMFunctionBody,
VMFunctionImport, VMSharedSignatureIndex, VMTrampoline, VMFunctionImport,
}; };
pub(crate) fn create_handle( pub(crate) fn create_handle(
module: Module, module: Module,
store: &Store, store: &Store,
finished_functions: PrimaryMap<DefinedFuncIndex, *mut [VMFunctionBody]>, finished_functions: PrimaryMap<DefinedFuncIndex, *mut [VMFunctionBody]>,
trampolines: HashMap<VMSharedSignatureIndex, VMTrampoline>,
state: Box<dyn Any>, state: Box<dyn Any>,
func_imports: &[VMFunctionImport], func_imports: &[VMFunctionImport],
) -> Result<StoreInstanceHandle> { ) -> Result<StoreInstanceHandle> {
let mut imports = Imports::default(); let mut imports = Imports::default();
imports.functions = func_imports; imports.functions = func_imports;
let module = Arc::new(module);
// Compute indices into the shared signature table. let module2 = module.clone();
let signatures = module
.signatures
.values()
.map(|(wasm, native)| store.register_signature(wasm.clone(), native.clone()))
.collect::<PrimaryMap<_, _>>();
unsafe { unsafe {
let handle = InstanceHandle::new( let handle = InstanceHandle::new(
Arc::new(module), module,
Arc::new(()), Arc::new(()),
&finished_functions, &finished_functions,
trampolines,
imports, imports,
store.memory_creator(), store.memory_creator(),
signatures.into_boxed_slice(), &store.lookup_shared_signature(&module2),
state, state,
store.interrupts(), store.interrupts(),
store.externref_activations_table() as *const VMExternRefActivationsTable as *mut _, store.externref_activations_table() as *const VMExternRefActivationsTable as *mut _,

View File

@@ -6,7 +6,6 @@ use crate::{FuncType, Store, Trap};
use anyhow::Result; use anyhow::Result;
use std::any::Any; use std::any::Any;
use std::cmp; use std::cmp;
use std::collections::HashMap;
use std::mem; use std::mem;
use std::panic::{self, AssertUnwindSafe}; use std::panic::{self, AssertUnwindSafe};
use wasmtime_environ::entity::PrimaryMap; use wasmtime_environ::entity::PrimaryMap;
@@ -215,18 +214,16 @@ pub fn create_handle_with_function(
let pointer_type = isa.pointer_type(); let pointer_type = isa.pointer_type();
let sig = ft.get_wasmtime_signature(pointer_type); let sig = ft.get_wasmtime_signature(pointer_type);
let wft = ft.to_wasm_func_type();
let mut fn_builder_ctx = FunctionBuilderContext::new(); let mut fn_builder_ctx = FunctionBuilderContext::new();
let mut module = Module::new(); let mut module = Module::new();
let mut finished_functions = PrimaryMap::new(); let mut finished_functions = PrimaryMap::new();
let mut trampolines = HashMap::new();
let mut code_memory = CodeMemory::new(); let mut code_memory = CodeMemory::new();
// First up we manufacture a trampoline which has the ABI specified by `ft` // First up we manufacture a trampoline which has the ABI specified by `ft`
// and calls into `stub_fn`... // and calls into `stub_fn`...
let sig_id = module let sig_id = module.signatures.push((wft.clone(), sig.clone()));
.signatures
.push((ft.to_wasm_func_type(), sig.clone()));
let func_id = module.functions.push(sig_id); let func_id = module.functions.push(sig_id);
module module
.exports .exports
@@ -244,8 +241,10 @@ pub fn create_handle_with_function(
&sig, &sig,
mem::size_of::<u128>(), mem::size_of::<u128>(),
)?; )?;
let sig_id = store.register_signature(ft.to_wasm_func_type(), sig); store
trampolines.insert(sig_id, trampoline); .signatures()
.borrow_mut()
.register(&wft, &sig, trampoline);
// Next up we wrap everything up into an `InstanceHandle` by publishing our // Next up we wrap everything up into an `InstanceHandle` by publishing our
// code memory (makes it executable) and ensuring all our various bits of // code memory (makes it executable) and ensuring all our various bits of
@@ -256,7 +255,6 @@ pub fn create_handle_with_function(
module, module,
store, store,
finished_functions, finished_functions,
trampolines,
Box::new(trampoline_state), Box::new(trampoline_state),
&[], &[],
) )
@@ -272,21 +270,21 @@ pub unsafe fn create_handle_with_raw_function(
) -> Result<StoreInstanceHandle> { ) -> Result<StoreInstanceHandle> {
let pointer_type = store.engine().compiler().isa().pointer_type(); let pointer_type = store.engine().compiler().isa().pointer_type();
let sig = ft.get_wasmtime_signature(pointer_type); let sig = ft.get_wasmtime_signature(pointer_type);
let wft = ft.to_wasm_func_type();
let mut module = Module::new(); let mut module = Module::new();
let mut finished_functions = PrimaryMap::new(); let mut finished_functions = PrimaryMap::new();
let mut trampolines = HashMap::new();
let sig_id = module let sig_id = module.signatures.push((wft.clone(), sig.clone()));
.signatures
.push((ft.to_wasm_func_type(), sig.clone()));
let func_id = module.functions.push(sig_id); let func_id = module.functions.push(sig_id);
module module
.exports .exports
.insert(String::new(), EntityIndex::Function(func_id)); .insert(String::new(), EntityIndex::Function(func_id));
finished_functions.push(func); finished_functions.push(func);
let sig_id = store.register_signature(ft.to_wasm_func_type(), sig); store
trampolines.insert(sig_id, trampoline); .signatures()
.borrow_mut()
.register(&wft, &sig, trampoline);
create_handle(module, store, finished_functions, trampolines, state, &[]) create_handle(module, store, finished_functions, state, &[])
} }

View File

@@ -35,10 +35,12 @@ pub fn create_global(store: &Store, gt: &GlobalType, val: Val) -> Result<StoreIn
Val::FuncRef(Some(f)) => { Val::FuncRef(Some(f)) => {
// Add a function import to the stub module, and then initialize // Add a function import to the stub module, and then initialize
// our global with a `ref.func` to grab that imported function. // our global with a `ref.func` to grab that imported function.
let signatures = store.signatures().borrow();
let shared_sig_index = f.sig_index(); let shared_sig_index = f.sig_index();
let local_sig_index = module let (wasm, native, _) = signatures
.signatures .lookup_shared(shared_sig_index)
.push(store.lookup_wasm_and_native_signatures(shared_sig_index)); .expect("signature not registered");
let local_sig_index = module.signatures.push((wasm.clone(), native.clone()));
let func_index = module.functions.push(local_sig_index); let func_index = module.functions.push(local_sig_index);
module.num_imported_funcs = 1; module.num_imported_funcs = 1;
module module
@@ -66,7 +68,6 @@ pub fn create_global(store: &Store, gt: &GlobalType, val: Val) -> Result<StoreIn
module, module,
store, store,
PrimaryMap::new(), PrimaryMap::new(),
Default::default(),
Box::new(()), Box::new(()),
&func_imports, &func_imports,
)?; )?;

View File

@@ -29,14 +29,7 @@ pub fn create_handle_with_memory(
.exports .exports
.insert(String::new(), EntityIndex::Memory(memory_id)); .insert(String::new(), EntityIndex::Memory(memory_id));
create_handle( create_handle(module, store, PrimaryMap::new(), Box::new(()), &[])
module,
store,
PrimaryMap::new(),
Default::default(),
Box::new(()),
&[],
)
} }
struct LinearMemoryProxy { struct LinearMemoryProxy {

View File

@@ -27,12 +27,5 @@ pub fn create_handle_with_table(store: &Store, table: &TableType) -> Result<Stor
.exports .exports
.insert(String::new(), EntityIndex::Table(table_id)); .insert(String::new(), EntityIndex::Table(table_id));
create_handle( create_handle(module, store, PrimaryMap::new(), Box::new(()), &[])
module,
store,
PrimaryMap::new(),
Default::default(),
Box::new(()),
&[],
)
} }