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}