wasmer_vm/sig_registry.rs
1// This file contains code from external sources.
2// Attributions: https://github.com/wasmerio/wasmer/blob/main/docs/ATTRIBUTIONS.md
3
4//! Implement a registry of function signatures, for fast indirect call
5//! signature checking.
6
7use crate::vmcontext::VMSignatureHash;
8use std::collections::HashMap;
9use std::sync::RwLock;
10use wasmer_types::{FunctionType, SignatureHash};
11
12/// WebAssembly requires that the caller and callee signatures in an indirect
13/// call must match. To implement this efficiently, keep a registry of all
14/// signatures, shared by all instances, so that call sites can just do an
15/// index comparison.
16#[derive(Debug, Default)]
17pub struct SignatureRegistry {
18 // This structure is stored in an `Engine` and is intended to be shared
19 // across many instances. Ideally instances can themselves be sent across
20 // threads, and ideally we can compile across many threads. As a result we
21 // use interior mutability here with a lock to avoid having callers to
22 // externally synchronize calls to compilation.
23 inner: RwLock<Inner>,
24}
25
26#[derive(Debug, Default)]
27struct Inner {
28 signature_to_hash: HashMap<FunctionType, VMSignatureHash>,
29 hash_to_signature: HashMap<VMSignatureHash, FunctionType>,
30}
31
32impl SignatureRegistry {
33 /// Create a new `SignatureRegistry`.
34 pub fn new() -> Self {
35 Default::default()
36 }
37
38 /// Register a signature and return its unique hash.
39 pub fn register(&self, sig: &FunctionType, hash: SignatureHash) -> VMSignatureHash {
40 let mut inner = self.inner.write().unwrap();
41
42 if let Some(sig_hash) = inner.signature_to_hash.get(sig) {
43 return *sig_hash;
44 }
45
46 let sig_hash = VMSignatureHash::new(hash.0);
47 if inner.hash_to_signature.contains_key(&sig_hash) {
48 // In theory, two WebAssembly modules (for example, shared libraries) could define different function types
49 // that end up with the same hash. We could propagate this information via `Result`, but that would be
50 // a breaking change for APIs such as `new_with_env`.
51 unreachable!("type signature collision");
52 }
53
54 inner.hash_to_signature.insert(sig_hash, sig.clone());
55 inner.signature_to_hash.insert(sig.clone(), sig_hash);
56 sig_hash
57 }
58
59 /// Looks up a registered signature by its hash.
60 pub fn lookup_signature(&self, sig_hash: VMSignatureHash) -> Option<FunctionType> {
61 self.inner
62 .read()
63 .unwrap()
64 .hash_to_signature
65 .get(&sig_hash)
66 .cloned()
67 }
68}