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:
@@ -10,7 +10,6 @@ use crate::object::ObjectUnwindInfo;
|
||||
use object::File as ObjectFile;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::any::Any;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
use wasmtime_debug::create_gdbjit_image;
|
||||
@@ -24,8 +23,8 @@ use wasmtime_environ::{
|
||||
use wasmtime_profiling::ProfilingAgent;
|
||||
use wasmtime_runtime::{
|
||||
GdbJitImageRegistration, Imports, InstanceHandle, InstantiationError, RuntimeMemoryCreator,
|
||||
SignatureRegistry, StackMapRegistry, VMExternRefActivationsTable, VMFunctionBody, VMInterrupts,
|
||||
VMTrampoline,
|
||||
StackMapRegistry, VMExternRefActivationsTable, VMFunctionBody, VMInterrupts,
|
||||
VMSharedSignatureIndex, VMTrampoline,
|
||||
};
|
||||
|
||||
/// An error condition while setting up a wasm instance, be it validation,
|
||||
@@ -248,37 +247,20 @@ impl CompiledModule {
|
||||
pub unsafe fn instantiate(
|
||||
&self,
|
||||
imports: Imports<'_>,
|
||||
signature_registry: &mut SignatureRegistry,
|
||||
lookup_shared_signature: &dyn Fn(SignatureIndex) -> VMSharedSignatureIndex,
|
||||
mem_creator: Option<&dyn RuntimeMemoryCreator>,
|
||||
interrupts: *const VMInterrupts,
|
||||
host_state: Box<dyn Any>,
|
||||
externref_activations_table: *mut VMExternRefActivationsTable,
|
||||
stack_map_registry: *mut StackMapRegistry,
|
||||
) -> 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(
|
||||
self.module.clone(),
|
||||
self.code.clone(),
|
||||
&self.finished_functions.0,
|
||||
trampolines,
|
||||
imports,
|
||||
mem_creator,
|
||||
signatures.into_boxed_slice(),
|
||||
lookup_shared_signature,
|
||||
host_state,
|
||||
interrupts,
|
||||
externref_activations_table,
|
||||
@@ -312,6 +294,11 @@ impl CompiledModule {
|
||||
&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
|
||||
/// module.
|
||||
///
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -540,7 +540,10 @@ impl Func {
|
||||
pub fn ty(&self) -> FuncType {
|
||||
// Signatures should always be registered in the store's registry of
|
||||
// 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
|
||||
// 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.
|
||||
pub fn param_arity(&self) -> usize {
|
||||
let sig = self
|
||||
.instance
|
||||
.store
|
||||
.lookup_signature(unsafe { self.export.anyfunc.as_ref().type_index });
|
||||
let signatures = self.instance.store.signatures().borrow();
|
||||
let (sig, _, _) = signatures
|
||||
.lookup_shared(self.sig_index())
|
||||
.expect("signature should be registered");
|
||||
sig.params.len()
|
||||
}
|
||||
|
||||
/// Returns the number of results this function produces.
|
||||
pub fn result_arity(&self) -> usize {
|
||||
let sig = self
|
||||
.instance
|
||||
.store
|
||||
.lookup_signature(unsafe { self.export.anyfunc.as_ref().type_index });
|
||||
let signatures = self.instance.store.signatures().borrow();
|
||||
let (sig, _, _) = signatures
|
||||
.lookup_shared(self.sig_index())
|
||||
.expect("signature should be registered");
|
||||
sig.returns.len()
|
||||
}
|
||||
|
||||
@@ -649,8 +652,12 @@ impl Func {
|
||||
// on that module as well, so unwrap the result here since otherwise
|
||||
// it's a bug in wasmtime.
|
||||
let trampoline = instance
|
||||
.trampoline(unsafe { export.anyfunc.as_ref().type_index })
|
||||
.expect("failed to retrieve trampoline from module");
|
||||
.store
|
||||
.signatures()
|
||||
.borrow()
|
||||
.lookup_shared(unsafe { export.anyfunc.as_ref().type_index })
|
||||
.expect("failed to retrieve trampoline from module")
|
||||
.2;
|
||||
|
||||
Func {
|
||||
instance,
|
||||
|
||||
@@ -20,7 +20,7 @@ fn instantiate(
|
||||
let instance = unsafe {
|
||||
let instance = compiled_module.instantiate(
|
||||
imports,
|
||||
&mut store.signatures_mut(),
|
||||
&store.lookup_shared_signature(compiled_module.module()),
|
||||
config.memory_creator.as_ref().map(|a| a as _),
|
||||
store.interrupts(),
|
||||
host,
|
||||
@@ -161,12 +161,8 @@ impl Instance {
|
||||
bail!("cross-`Engine` instantiation is not currently supported");
|
||||
}
|
||||
|
||||
let host_info = Box::new({
|
||||
let frame_info_registration = module.register_frame_info();
|
||||
store.register_jit_code(&module);
|
||||
store.register_stack_maps(&module);
|
||||
frame_info_registration
|
||||
});
|
||||
store.register_module(&module);
|
||||
let host_info = Box::new(module.register_frame_info());
|
||||
|
||||
let handle = with_imports(store, module.compiled_module(), imports, |imports| {
|
||||
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
|
||||
// to not match.
|
||||
let ty = store
|
||||
.signatures_mut()
|
||||
.signatures()
|
||||
.borrow()
|
||||
.lookup(&m.signatures[m.functions[i]].0)
|
||||
.ok_or_else(|| anyhow!("function types incompatible"))?;
|
||||
if !func.matches_expected(ty) {
|
||||
|
||||
@@ -242,6 +242,7 @@ mod linker;
|
||||
mod module;
|
||||
mod r#ref;
|
||||
mod runtime;
|
||||
mod sig_registry;
|
||||
mod trampoline;
|
||||
mod trap;
|
||||
mod types;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::externals::MemoryCreator;
|
||||
use crate::sig_registry::SignatureRegistry;
|
||||
use crate::trampoline::{MemoryCreatorProxy, StoreInstanceHandle};
|
||||
use crate::Module;
|
||||
use anyhow::{bail, Result};
|
||||
@@ -16,13 +17,12 @@ use wasmparser::WasmFeatures;
|
||||
#[cfg(feature = "cache")]
|
||||
use wasmtime_cache::CacheConfig;
|
||||
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_profiling::{JitDumpAgent, NullProfilerAgent, ProfilingAgent, VTuneAgent};
|
||||
use wasmtime_runtime::{
|
||||
debug_builtins, InstanceHandle, RuntimeMemoryCreator, SignalHandler, SignatureRegistry,
|
||||
StackMapRegistry, VMExternRef, VMExternRefActivationsTable, VMInterrupts,
|
||||
VMSharedSignatureIndex,
|
||||
debug_builtins, InstanceHandle, RuntimeMemoryCreator, SignalHandler, StackMapRegistry,
|
||||
VMExternRef, VMExternRefActivationsTable, VMInterrupts, VMSharedSignatureIndex,
|
||||
};
|
||||
|
||||
// Runtime Environment
|
||||
@@ -915,38 +915,21 @@ impl Store {
|
||||
.map(|x| x as _)
|
||||
}
|
||||
|
||||
pub(crate) fn lookup_signature(&self, sig_index: VMSharedSignatureIndex) -> wasm::WasmFuncType {
|
||||
self.inner
|
||||
.signatures
|
||||
pub(crate) fn signatures(&self) -> &RefCell<SignatureRegistry> {
|
||||
&self.inner.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()
|
||||
.lookup_wasm(sig_index)
|
||||
.expect("failed to lookup signature")
|
||||
.lookup(wasm)
|
||||
.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
|
||||
@@ -959,7 +942,32 @@ impl Store {
|
||||
.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();
|
||||
// Checking of we already registered JIT code ranges by searching
|
||||
// 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();
|
||||
self.stack_map_registry()
|
||||
.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 {
|
||||
self.inner.instances.borrow_mut().push(handle.clone());
|
||||
StoreInstanceHandle {
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
//! 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};
|
||||
use wasmtime_runtime::{VMSharedSignatureIndex, VMTrampoline};
|
||||
|
||||
/// WebAssembly requires that the caller and callee signatures in an indirect
|
||||
/// call must match. To implement this efficiently, keep a registry of all
|
||||
@@ -13,21 +12,35 @@ use wasmtime_environ::{ir, wasm::WasmFuncType};
|
||||
/// index comparison.
|
||||
#[derive(Debug, Default)]
|
||||
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>,
|
||||
|
||||
// Maps the index to the original Wasm signature.
|
||||
index2wasm: HashMap<VMSharedSignatureIndex, WasmFuncType>,
|
||||
// Map of all known wasm function signatures in this registry. This is
|
||||
// keyed by `VMSharedSignatureIndex` above.
|
||||
index_map: Vec<Entry>,
|
||||
}
|
||||
|
||||
// Maps the index to the native signature.
|
||||
index2native: HashMap<VMSharedSignatureIndex, ir::Signature>,
|
||||
#[derive(Debug)]
|
||||
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 {
|
||||
/// Register a signature and return its unique index.
|
||||
pub fn register(
|
||||
&mut self,
|
||||
wasm: WasmFuncType,
|
||||
native: ir::Signature,
|
||||
wasm: &WasmFuncType,
|
||||
native: &ir::Signature,
|
||||
trampoline: VMTrampoline,
|
||||
) -> VMSharedSignatureIndex {
|
||||
let len = self.wasm2index.len();
|
||||
|
||||
@@ -36,15 +49,18 @@ impl SignatureRegistry {
|
||||
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,
|
||||
assert!(
|
||||
len < std::u32::MAX as usize,
|
||||
"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());
|
||||
self.index_map.push(Entry {
|
||||
wasm: wasm.clone(),
|
||||
native: native.clone(),
|
||||
trampoline,
|
||||
});
|
||||
entry.insert(index);
|
||||
self.index2wasm.insert(index, wasm);
|
||||
self.index2native.insert(index, native);
|
||||
index
|
||||
}
|
||||
}
|
||||
@@ -55,33 +71,16 @@ impl SignatureRegistry {
|
||||
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
|
||||
/// 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(
|
||||
pub fn lookup_shared(
|
||||
&self,
|
||||
idx: VMSharedSignatureIndex,
|
||||
) -> Option<(WasmFuncType, ir::Signature)> {
|
||||
let wasm = self.lookup_wasm(idx)?;
|
||||
let native = self.lookup_native(idx)?;
|
||||
Some((wasm, native))
|
||||
) -> Option<(&WasmFuncType, &ir::Signature, VMTrampoline)> {
|
||||
self.index_map
|
||||
.get(idx.bits() as usize)
|
||||
.map(|e| (&e.wasm, &e.native, e.trampoline))
|
||||
}
|
||||
}
|
||||
@@ -4,43 +4,35 @@ use crate::trampoline::StoreInstanceHandle;
|
||||
use crate::Store;
|
||||
use anyhow::Result;
|
||||
use std::any::Any;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use wasmtime_environ::entity::PrimaryMap;
|
||||
use wasmtime_environ::wasm::DefinedFuncIndex;
|
||||
use wasmtime_environ::Module;
|
||||
use wasmtime_runtime::{
|
||||
Imports, InstanceHandle, StackMapRegistry, VMExternRefActivationsTable, VMFunctionBody,
|
||||
VMFunctionImport, VMSharedSignatureIndex, VMTrampoline,
|
||||
VMFunctionImport,
|
||||
};
|
||||
|
||||
pub(crate) fn create_handle(
|
||||
module: Module,
|
||||
store: &Store,
|
||||
finished_functions: PrimaryMap<DefinedFuncIndex, *mut [VMFunctionBody]>,
|
||||
trampolines: HashMap<VMSharedSignatureIndex, VMTrampoline>,
|
||||
state: Box<dyn Any>,
|
||||
func_imports: &[VMFunctionImport],
|
||||
) -> Result<StoreInstanceHandle> {
|
||||
let mut imports = Imports::default();
|
||||
imports.functions = func_imports;
|
||||
|
||||
// Compute indices into the shared signature table.
|
||||
let signatures = module
|
||||
.signatures
|
||||
.values()
|
||||
.map(|(wasm, native)| store.register_signature(wasm.clone(), native.clone()))
|
||||
.collect::<PrimaryMap<_, _>>();
|
||||
let module = Arc::new(module);
|
||||
let module2 = module.clone();
|
||||
|
||||
unsafe {
|
||||
let handle = InstanceHandle::new(
|
||||
Arc::new(module),
|
||||
module,
|
||||
Arc::new(()),
|
||||
&finished_functions,
|
||||
trampolines,
|
||||
imports,
|
||||
store.memory_creator(),
|
||||
signatures.into_boxed_slice(),
|
||||
&store.lookup_shared_signature(&module2),
|
||||
state,
|
||||
store.interrupts(),
|
||||
store.externref_activations_table() as *const VMExternRefActivationsTable as *mut _,
|
||||
|
||||
@@ -6,7 +6,6 @@ use crate::{FuncType, Store, Trap};
|
||||
use anyhow::Result;
|
||||
use std::any::Any;
|
||||
use std::cmp;
|
||||
use std::collections::HashMap;
|
||||
use std::mem;
|
||||
use std::panic::{self, AssertUnwindSafe};
|
||||
use wasmtime_environ::entity::PrimaryMap;
|
||||
@@ -215,18 +214,16 @@ pub fn create_handle_with_function(
|
||||
|
||||
let pointer_type = isa.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 module = Module::new();
|
||||
let mut finished_functions = PrimaryMap::new();
|
||||
let mut trampolines = HashMap::new();
|
||||
let mut code_memory = CodeMemory::new();
|
||||
|
||||
// First up we manufacture a trampoline which has the ABI specified by `ft`
|
||||
// and calls into `stub_fn`...
|
||||
let sig_id = module
|
||||
.signatures
|
||||
.push((ft.to_wasm_func_type(), sig.clone()));
|
||||
let sig_id = module.signatures.push((wft.clone(), sig.clone()));
|
||||
let func_id = module.functions.push(sig_id);
|
||||
module
|
||||
.exports
|
||||
@@ -244,8 +241,10 @@ pub fn create_handle_with_function(
|
||||
&sig,
|
||||
mem::size_of::<u128>(),
|
||||
)?;
|
||||
let sig_id = store.register_signature(ft.to_wasm_func_type(), sig);
|
||||
trampolines.insert(sig_id, trampoline);
|
||||
store
|
||||
.signatures()
|
||||
.borrow_mut()
|
||||
.register(&wft, &sig, trampoline);
|
||||
|
||||
// Next up we wrap everything up into an `InstanceHandle` by publishing our
|
||||
// code memory (makes it executable) and ensuring all our various bits of
|
||||
@@ -256,7 +255,6 @@ pub fn create_handle_with_function(
|
||||
module,
|
||||
store,
|
||||
finished_functions,
|
||||
trampolines,
|
||||
Box::new(trampoline_state),
|
||||
&[],
|
||||
)
|
||||
@@ -272,21 +270,21 @@ pub unsafe fn create_handle_with_raw_function(
|
||||
) -> Result<StoreInstanceHandle> {
|
||||
let pointer_type = store.engine().compiler().isa().pointer_type();
|
||||
let sig = ft.get_wasmtime_signature(pointer_type);
|
||||
let wft = ft.to_wasm_func_type();
|
||||
|
||||
let mut module = Module::new();
|
||||
let mut finished_functions = PrimaryMap::new();
|
||||
let mut trampolines = HashMap::new();
|
||||
|
||||
let sig_id = module
|
||||
.signatures
|
||||
.push((ft.to_wasm_func_type(), sig.clone()));
|
||||
let sig_id = module.signatures.push((wft.clone(), sig.clone()));
|
||||
let func_id = module.functions.push(sig_id);
|
||||
module
|
||||
.exports
|
||||
.insert(String::new(), EntityIndex::Function(func_id));
|
||||
finished_functions.push(func);
|
||||
let sig_id = store.register_signature(ft.to_wasm_func_type(), sig);
|
||||
trampolines.insert(sig_id, trampoline);
|
||||
store
|
||||
.signatures()
|
||||
.borrow_mut()
|
||||
.register(&wft, &sig, trampoline);
|
||||
|
||||
create_handle(module, store, finished_functions, trampolines, state, &[])
|
||||
create_handle(module, store, finished_functions, state, &[])
|
||||
}
|
||||
|
||||
@@ -35,10 +35,12 @@ pub fn create_global(store: &Store, gt: &GlobalType, val: Val) -> Result<StoreIn
|
||||
Val::FuncRef(Some(f)) => {
|
||||
// Add a function import to the stub module, and then initialize
|
||||
// our global with a `ref.func` to grab that imported function.
|
||||
let signatures = store.signatures().borrow();
|
||||
let shared_sig_index = f.sig_index();
|
||||
let local_sig_index = module
|
||||
.signatures
|
||||
.push(store.lookup_wasm_and_native_signatures(shared_sig_index));
|
||||
let (wasm, native, _) = signatures
|
||||
.lookup_shared(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);
|
||||
module.num_imported_funcs = 1;
|
||||
module
|
||||
@@ -66,7 +68,6 @@ pub fn create_global(store: &Store, gt: &GlobalType, val: Val) -> Result<StoreIn
|
||||
module,
|
||||
store,
|
||||
PrimaryMap::new(),
|
||||
Default::default(),
|
||||
Box::new(()),
|
||||
&func_imports,
|
||||
)?;
|
||||
|
||||
@@ -29,14 +29,7 @@ pub fn create_handle_with_memory(
|
||||
.exports
|
||||
.insert(String::new(), EntityIndex::Memory(memory_id));
|
||||
|
||||
create_handle(
|
||||
module,
|
||||
store,
|
||||
PrimaryMap::new(),
|
||||
Default::default(),
|
||||
Box::new(()),
|
||||
&[],
|
||||
)
|
||||
create_handle(module, store, PrimaryMap::new(), Box::new(()), &[])
|
||||
}
|
||||
|
||||
struct LinearMemoryProxy {
|
||||
|
||||
@@ -27,12 +27,5 @@ pub fn create_handle_with_table(store: &Store, table: &TableType) -> Result<Stor
|
||||
.exports
|
||||
.insert(String::new(), EntityIndex::Table(table_id));
|
||||
|
||||
create_handle(
|
||||
module,
|
||||
store,
|
||||
PrimaryMap::new(),
|
||||
Default::default(),
|
||||
Box::new(()),
|
||||
&[],
|
||||
)
|
||||
create_handle(module, store, PrimaryMap::new(), Box::new(()), &[])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user