Skip to content

Commit e5af0ae

Browse files
authored
Move the Store::signature_cache field (#847)
This commit removes the `signature_cache` field from the `Store` type and performs a few internal changes which are aimed to be a bit forward looking towards #777, making `Store` threadsafe. The changes made here are: * The `SignatureRegistry` internal type now contains the reverse map that `signature_cache` was serving to do. This is populated on calls to `register` automatically and is accompanied by a `lookup` method as well. * The `register_wasmtime_signature` and `lookup_wasmtime_signature` methods were removed from `Store` and now instead work by using the `Compiler::signatures` field. * The `SignatureRegistry` type was updated to have interior mutability. The global `Compiler` type is highly likely to get shared across many threads through `Store`, so it needs some form of lock somewhere for mutation of the registry of signatures and this commit opts to put it inside `SignatureRegistry` which will eventually allow for the removal of most `&mut self` method on `Compiler`.
1 parent 5953215 commit e5af0ae

File tree

7 files changed

+48
-53
lines changed

7 files changed

+48
-53
lines changed

crates/api/src/instance.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ impl Instance {
186186
// HACK ensure all handles, instantiated outside Store, present in
187187
// the store's SignatureRegistry, e.g. WASI instances that are
188188
// imported into this store using the from_handle() method.
189-
let _ = store.register_wasmtime_signature(signature);
189+
store.compiler().signatures().register(signature);
190190
}
191191

192192
// We should support everything supported by wasmtime_runtime, or

crates/api/src/module.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -401,11 +401,5 @@ fn compile(store: &Store, binary: &[u8], module_name: Option<&str>) -> Result<Co
401401
module_name,
402402
store.engine().config().debug_info,
403403
)?;
404-
405-
// Register all module signatures
406-
for signature in compiled_module.module().signatures.values() {
407-
store.register_wasmtime_signature(signature);
408-
}
409-
410404
Ok(compiled_module)
411405
}

crates/api/src/runtime.rs

Lines changed: 5 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
use anyhow::Result;
22
use std::cell::RefCell;
3-
use std::collections::HashMap;
43
use std::rc::Rc;
54
use std::sync::Arc;
6-
use wasmtime_environ::{
7-
ir,
8-
settings::{self, Configurable},
9-
};
5+
use wasmtime_environ::settings::{self, Configurable};
106
use wasmtime_jit::{native, CompilationStrategy, Compiler, Features};
117

128
// Runtime Environment
@@ -342,7 +338,6 @@ pub struct Store {
342338
struct StoreInner {
343339
engine: Engine,
344340
compiler: RefCell<Compiler>,
345-
signature_cache: RefCell<HashMap<wasmtime_runtime::VMSharedSignatureIndex, ir::Signature>>,
346341
}
347342

348343
impl Store {
@@ -354,7 +349,6 @@ impl Store {
354349
inner: Rc::new(StoreInner {
355350
engine: engine.clone(),
356351
compiler: RefCell::new(compiler),
357-
signature_cache: RefCell::new(HashMap::new()),
358352
}),
359353
}
360354
}
@@ -364,34 +358,12 @@ impl Store {
364358
&self.inner.engine
365359
}
366360

367-
pub(crate) fn compiler_mut(&self) -> std::cell::RefMut<'_, Compiler> {
368-
self.inner.compiler.borrow_mut()
369-
}
370-
371-
pub(crate) fn register_wasmtime_signature(
372-
&self,
373-
signature: &ir::Signature,
374-
) -> wasmtime_runtime::VMSharedSignatureIndex {
375-
use std::collections::hash_map::Entry;
376-
let index = self.compiler_mut().signatures().register(signature);
377-
match self.inner.signature_cache.borrow_mut().entry(index) {
378-
Entry::Vacant(v) => {
379-
v.insert(signature.clone());
380-
}
381-
Entry::Occupied(_) => (),
382-
}
383-
index
361+
pub(crate) fn compiler(&self) -> std::cell::Ref<'_, Compiler> {
362+
self.inner.compiler.borrow()
384363
}
385364

386-
pub(crate) fn lookup_wasmtime_signature(
387-
&self,
388-
type_index: wasmtime_runtime::VMSharedSignatureIndex,
389-
) -> Option<ir::Signature> {
390-
self.inner
391-
.signature_cache
392-
.borrow()
393-
.get(&type_index)
394-
.cloned()
365+
pub(crate) fn compiler_mut(&self) -> std::cell::RefMut<'_, Compiler> {
366+
self.inner.compiler.borrow_mut()
395367
}
396368

397369
/// Returns whether the stores `a` and `b` refer to the same underlying

crates/api/src/trampoline/create_handle.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use wasmtime_runtime::{Imports, InstanceHandle, VMFunctionBody};
1212

1313
pub(crate) fn create_handle(
1414
module: Module,
15-
signature_registry: Option<&Store>,
15+
store: Option<&Store>,
1616
finished_functions: PrimaryMap<DefinedFuncIndex, *const VMFunctionBody>,
1717
state: Box<dyn Any>,
1818
) -> Result<InstanceHandle> {
@@ -26,12 +26,12 @@ pub(crate) fn create_handle(
2626
let data_initializers = Vec::new();
2727

2828
// Compute indices into the shared signature table.
29-
let signatures = signature_registry
30-
.map(|signature_registry| {
29+
let signatures = store
30+
.map(|store| {
3131
module
3232
.signatures
3333
.values()
34-
.map(|sig| signature_registry.register_wasmtime_signature(sig))
34+
.map(|sig| store.compiler().signatures().register(sig))
3535
.collect::<PrimaryMap<_, _>>()
3636
})
3737
.unwrap_or_else(PrimaryMap::new);

crates/api/src/values.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ pub(crate) fn into_checked_anyfunc(
205205
} => (*vmctx, *address, signature),
206206
_ => panic!("expected function export"),
207207
};
208-
let type_index = store.register_wasmtime_signature(signature);
208+
let type_index = store.compiler().signatures().register(signature);
209209
wasmtime_runtime::VMCallerCheckedAnyfunc {
210210
func_ptr,
211211
type_index,
@@ -224,7 +224,9 @@ pub(crate) fn from_checked_anyfunc(
224224
return Val::AnyRef(AnyRef::Null);
225225
}
226226
let signature = store
227-
.lookup_wasmtime_signature(item.type_index)
227+
.compiler()
228+
.signatures()
229+
.lookup(item.type_index)
228230
.expect("signature");
229231
let instance_handle = unsafe { wasmtime_runtime::InstanceHandle::from_vmctx(item.vmctx) };
230232
let export = wasmtime_runtime::Export::Function {

crates/jit/src/compiler.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,8 +265,8 @@ impl Compiler {
265265
}
266266

267267
/// Shared signature registry.
268-
pub fn signatures(&mut self) -> &mut SignatureRegistry {
269-
&mut self.signatures
268+
pub fn signatures(&self) -> &SignatureRegistry {
269+
&self.signatures
270270
}
271271
}
272272

crates/runtime/src/sig_registry.rs

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::vmcontext::VMSharedSignatureIndex;
55
use more_asserts::{assert_lt, debug_assert_lt};
66
use std::collections::{hash_map, HashMap};
77
use std::convert::TryFrom;
8+
use std::sync::RwLock;
89
use wasmtime_environ::ir;
910

1011
/// WebAssembly requires that the caller and callee signatures in an indirect
@@ -13,21 +14,33 @@ use wasmtime_environ::ir;
1314
/// index comparison.
1415
#[derive(Debug)]
1516
pub struct SignatureRegistry {
16-
signature_hash: HashMap<ir::Signature, VMSharedSignatureIndex>,
17+
// This structure is stored in a `Compiler` and is intended to be shared
18+
// across many instances. Ideally instances can themselves be sent across
19+
// threads, and ideally we can compile across many threads. As a result we
20+
// use interior mutability here with a lock to avoid having callers to
21+
// externally synchronize calls to compilation.
22+
inner: RwLock<Inner>,
23+
}
24+
25+
#[derive(Debug, Default)]
26+
struct Inner {
27+
signature2index: HashMap<ir::Signature, VMSharedSignatureIndex>,
28+
index2signature: HashMap<VMSharedSignatureIndex, ir::Signature>,
1729
}
1830

1931
impl SignatureRegistry {
2032
/// Create a new `SignatureRegistry`.
2133
pub fn new() -> Self {
2234
Self {
23-
signature_hash: HashMap::new(),
35+
inner: Default::default(),
2436
}
2537
}
2638

2739
/// Register a signature and return its unique index.
28-
pub fn register(&mut self, sig: &ir::Signature) -> VMSharedSignatureIndex {
29-
let len = self.signature_hash.len();
30-
match self.signature_hash.entry(sig.clone()) {
40+
pub fn register(&self, sig: &ir::Signature) -> VMSharedSignatureIndex {
41+
let mut inner = self.inner.write().unwrap();
42+
let len = inner.signature2index.len();
43+
match inner.signature2index.entry(sig.clone()) {
3144
hash_map::Entry::Occupied(entry) => *entry.get(),
3245
hash_map::Entry::Vacant(entry) => {
3346
// Keep `signature_hash` len under 2**32 -- VMSharedSignatureIndex::new(std::u32::MAX)
@@ -39,8 +52,22 @@ impl SignatureRegistry {
3952
);
4053
let sig_id = VMSharedSignatureIndex::new(u32::try_from(len).unwrap());
4154
entry.insert(sig_id);
55+
inner.index2signature.insert(sig_id, sig.clone());
4256
sig_id
4357
}
4458
}
4559
}
60+
61+
/// Looks up a shared signature index within this registry.
62+
///
63+
/// Note that for this operation to be semantically correct the `idx` must
64+
/// have previously come from a call to `register` of this same object.
65+
pub fn lookup(&self, idx: VMSharedSignatureIndex) -> Option<ir::Signature> {
66+
self.inner
67+
.read()
68+
.unwrap()
69+
.index2signature
70+
.get(&idx)
71+
.cloned()
72+
}
4673
}

0 commit comments

Comments
 (0)