2019-01-16 18:26:10 +00:00
|
|
|
use crate::{
|
|
|
|
structures::Map,
|
|
|
|
types::{FuncSig, SigIndex},
|
|
|
|
};
|
2019-08-01 06:17:42 +00:00
|
|
|
use std::collections::HashMap;
|
2019-01-29 18:16:39 +00:00
|
|
|
use lazy_static::lazy_static;
|
|
|
|
use parking_lot::RwLock;
|
|
|
|
use std::sync::Arc;
|
2019-01-08 17:09:47 +00:00
|
|
|
|
2019-01-29 18:16:39 +00:00
|
|
|
lazy_static! {
|
|
|
|
static ref GLOBAL_SIG_REGISTRY: RwLock<GlobalSigRegistry> = {
|
|
|
|
let registry = GlobalSigRegistry {
|
|
|
|
func_table: HashMap::new(),
|
|
|
|
sig_assoc: Map::new(),
|
|
|
|
};
|
|
|
|
|
|
|
|
RwLock::new(registry)
|
|
|
|
};
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
|
2019-01-29 18:16:39 +00:00
|
|
|
struct GlobalSigRegistry {
|
|
|
|
func_table: HashMap<Arc<FuncSig>, SigIndex>,
|
|
|
|
sig_assoc: Map<SigIndex, Arc<FuncSig>>,
|
|
|
|
}
|
|
|
|
|
2019-03-13 21:58:44 +00:00
|
|
|
/// The `SigRegistry` represents a process-global map of function signatures
|
|
|
|
/// to signature indexes and vice versa (the map goes both ways).
|
|
|
|
///
|
|
|
|
/// This exists for two reasons:
|
|
|
|
/// 1. The `call_indirect` wasm instruction can compare two signature indices
|
|
|
|
/// to do signature validation very quickly.
|
|
|
|
/// 2. To intern function signatures, which may be expensive to create.
|
2019-01-29 18:16:39 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct SigRegistry;
|
|
|
|
|
2019-01-08 17:09:47 +00:00
|
|
|
impl SigRegistry {
|
2019-03-13 21:58:44 +00:00
|
|
|
/// Map a `FuncSig` to a global `SigIndex`.
|
2019-01-29 20:49:51 +00:00
|
|
|
pub fn lookup_sig_index<Sig>(&self, func_sig: Sig) -> SigIndex
|
2019-01-29 18:16:39 +00:00
|
|
|
where
|
|
|
|
Sig: Into<Arc<FuncSig>>,
|
|
|
|
{
|
|
|
|
let func_sig = func_sig.into();
|
|
|
|
let mut global = (*GLOBAL_SIG_REGISTRY).write();
|
|
|
|
let global = &mut *global;
|
|
|
|
|
|
|
|
let func_table = &mut global.func_table;
|
|
|
|
let sig_assoc = &mut global.sig_assoc;
|
2019-01-09 02:57:28 +00:00
|
|
|
|
2019-01-10 16:26:52 +00:00
|
|
|
let sig_index = *func_table
|
2019-01-29 18:16:39 +00:00
|
|
|
.entry(Arc::clone(&func_sig))
|
2019-01-10 16:26:52 +00:00
|
|
|
.or_insert_with(|| sig_assoc.push(func_sig));
|
2019-01-08 17:09:47 +00:00
|
|
|
|
2019-01-29 18:16:39 +00:00
|
|
|
sig_index
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
|
2019-03-13 21:58:44 +00:00
|
|
|
/// Map a global `SigIndex` to an interned `FuncSig`.
|
2019-01-29 18:16:39 +00:00
|
|
|
pub fn lookup_signature(&self, sig_index: SigIndex) -> Arc<FuncSig> {
|
|
|
|
let global = (*GLOBAL_SIG_REGISTRY).read();
|
|
|
|
Arc::clone(&global.sig_assoc[sig_index])
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
2019-02-08 22:19:58 +00:00
|
|
|
|
2019-03-13 21:58:44 +00:00
|
|
|
/// Register a function signature with the global signature registry.
|
|
|
|
///
|
|
|
|
/// This will return an interned `FuncSig`.
|
2019-02-08 22:19:58 +00:00
|
|
|
pub fn lookup_signature_ref(&self, func_sig: &FuncSig) -> Arc<FuncSig> {
|
|
|
|
let mut global = (*GLOBAL_SIG_REGISTRY).write();
|
|
|
|
let global = &mut *global;
|
|
|
|
|
|
|
|
let func_table = &mut global.func_table;
|
|
|
|
let sig_assoc = &mut global.sig_assoc;
|
|
|
|
|
|
|
|
if func_table.contains_key(func_sig) {
|
|
|
|
Arc::clone(&sig_assoc[func_table[func_sig]])
|
|
|
|
} else {
|
|
|
|
let arc = Arc::new(func_sig.clone());
|
|
|
|
func_table.insert(Arc::clone(&arc), sig_assoc.push(Arc::clone(&arc)));
|
|
|
|
arc
|
|
|
|
}
|
|
|
|
}
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|