diff --git a/crates/api/src/instance.rs b/crates/api/src/instance.rs index 672b62380d..27846fcba1 100644 --- a/crates/api/src/instance.rs +++ b/crates/api/src/instance.rs @@ -186,7 +186,7 @@ impl Instance { // HACK ensure all handles, instantiated outside Store, present in // the store's SignatureRegistry, e.g. WASI instances that are // imported into this store using the from_handle() method. - let _ = store.register_wasmtime_signature(signature); + store.compiler().signatures().register(signature); } // We should support everything supported by wasmtime_runtime, or diff --git a/crates/api/src/module.rs b/crates/api/src/module.rs index 43edc21acf..e57ae65199 100644 --- a/crates/api/src/module.rs +++ b/crates/api/src/module.rs @@ -401,11 +401,5 @@ fn compile(store: &Store, binary: &[u8], module_name: Option<&str>) -> Result, - signature_cache: RefCell>, } impl Store { @@ -354,7 +349,6 @@ impl Store { inner: Rc::new(StoreInner { engine: engine.clone(), compiler: RefCell::new(compiler), - signature_cache: RefCell::new(HashMap::new()), }), } } @@ -364,36 +358,14 @@ impl Store { &self.inner.engine } + pub(crate) fn compiler(&self) -> std::cell::Ref<'_, Compiler> { + self.inner.compiler.borrow() + } + pub(crate) fn compiler_mut(&self) -> std::cell::RefMut<'_, Compiler> { self.inner.compiler.borrow_mut() } - pub(crate) fn register_wasmtime_signature( - &self, - signature: &ir::Signature, - ) -> wasmtime_runtime::VMSharedSignatureIndex { - use std::collections::hash_map::Entry; - let index = self.compiler_mut().signatures().register(signature); - match self.inner.signature_cache.borrow_mut().entry(index) { - Entry::Vacant(v) => { - v.insert(signature.clone()); - } - Entry::Occupied(_) => (), - } - index - } - - pub(crate) fn lookup_wasmtime_signature( - &self, - type_index: wasmtime_runtime::VMSharedSignatureIndex, - ) -> Option { - self.inner - .signature_cache - .borrow() - .get(&type_index) - .cloned() - } - /// Returns whether the stores `a` and `b` refer to the same underlying /// `Store`. /// diff --git a/crates/api/src/trampoline/create_handle.rs b/crates/api/src/trampoline/create_handle.rs index 3b3834d57b..5f3df54794 100644 --- a/crates/api/src/trampoline/create_handle.rs +++ b/crates/api/src/trampoline/create_handle.rs @@ -12,7 +12,7 @@ use wasmtime_runtime::{Imports, InstanceHandle, VMFunctionBody}; pub(crate) fn create_handle( module: Module, - signature_registry: Option<&Store>, + store: Option<&Store>, finished_functions: PrimaryMap, state: Box, ) -> Result { @@ -26,12 +26,12 @@ pub(crate) fn create_handle( let data_initializers = Vec::new(); // Compute indices into the shared signature table. - let signatures = signature_registry - .map(|signature_registry| { + let signatures = store + .map(|store| { module .signatures .values() - .map(|sig| signature_registry.register_wasmtime_signature(sig)) + .map(|sig| store.compiler().signatures().register(sig)) .collect::>() }) .unwrap_or_else(PrimaryMap::new); diff --git a/crates/api/src/values.rs b/crates/api/src/values.rs index 2dbc5f74c2..03db7bd07a 100644 --- a/crates/api/src/values.rs +++ b/crates/api/src/values.rs @@ -205,7 +205,7 @@ pub(crate) fn into_checked_anyfunc( } => (*vmctx, *address, signature), _ => panic!("expected function export"), }; - let type_index = store.register_wasmtime_signature(signature); + let type_index = store.compiler().signatures().register(signature); wasmtime_runtime::VMCallerCheckedAnyfunc { func_ptr, type_index, @@ -224,7 +224,9 @@ pub(crate) fn from_checked_anyfunc( return Val::AnyRef(AnyRef::Null); } let signature = store - .lookup_wasmtime_signature(item.type_index) + .compiler() + .signatures() + .lookup(item.type_index) .expect("signature"); let instance_handle = unsafe { wasmtime_runtime::InstanceHandle::from_vmctx(item.vmctx) }; let export = wasmtime_runtime::Export::Function { diff --git a/crates/jit/src/compiler.rs b/crates/jit/src/compiler.rs index c03687827b..5eaf90dd4b 100644 --- a/crates/jit/src/compiler.rs +++ b/crates/jit/src/compiler.rs @@ -265,8 +265,8 @@ impl Compiler { } /// Shared signature registry. - pub fn signatures(&mut self) -> &mut SignatureRegistry { - &mut self.signatures + pub fn signatures(&self) -> &SignatureRegistry { + &self.signatures } } diff --git a/crates/runtime/src/sig_registry.rs b/crates/runtime/src/sig_registry.rs index 70277ebe88..7ad66149ac 100644 --- a/crates/runtime/src/sig_registry.rs +++ b/crates/runtime/src/sig_registry.rs @@ -5,6 +5,7 @@ use crate::vmcontext::VMSharedSignatureIndex; use more_asserts::{assert_lt, debug_assert_lt}; use std::collections::{hash_map, HashMap}; use std::convert::TryFrom; +use std::sync::RwLock; use wasmtime_environ::ir; /// WebAssembly requires that the caller and callee signatures in an indirect @@ -13,21 +14,33 @@ use wasmtime_environ::ir; /// index comparison. #[derive(Debug)] pub struct SignatureRegistry { - signature_hash: HashMap, + // This structure is stored in a `Compiler` and is intended to be shared + // across many instances. Ideally instances can themselves be sent across + // threads, and ideally we can compile across many threads. As a result we + // use interior mutability here with a lock to avoid having callers to + // externally synchronize calls to compilation. + inner: RwLock, +} + +#[derive(Debug, Default)] +struct Inner { + signature2index: HashMap, + index2signature: HashMap, } impl SignatureRegistry { /// Create a new `SignatureRegistry`. pub fn new() -> Self { Self { - signature_hash: HashMap::new(), + inner: Default::default(), } } /// Register a signature and return its unique index. - pub fn register(&mut self, sig: &ir::Signature) -> VMSharedSignatureIndex { - let len = self.signature_hash.len(); - match self.signature_hash.entry(sig.clone()) { + pub fn register(&self, sig: &ir::Signature) -> VMSharedSignatureIndex { + let mut inner = self.inner.write().unwrap(); + let len = inner.signature2index.len(); + match inner.signature2index.entry(sig.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) @@ -39,8 +52,22 @@ impl SignatureRegistry { ); let sig_id = VMSharedSignatureIndex::new(u32::try_from(len).unwrap()); entry.insert(sig_id); + inner.index2signature.insert(sig_id, sig.clone()); sig_id } } } + + /// Looks up a shared signature index 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(&self, idx: VMSharedSignatureIndex) -> Option { + self.inner + .read() + .unwrap() + .index2signature + .get(&idx) + .cloned() + } }