dev: caching static function signature analysis (#692)

This commit is contained in:
Myriad-Dreamin 2024-10-16 22:34:45 +08:00 committed by GitHub
parent 02bbdbf8d9
commit 4d23b57785
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 62 additions and 64 deletions

View file

@ -84,9 +84,9 @@ pub struct AnalysisGlobalCaches {
clear_lifetime: AtomicU64,
def_use: FxDashMap<u128, (u64, Option<Arc<DefUseInfo>>)>,
type_check: FxDashMap<u128, (u64, Option<Arc<TypeScheme>>)>,
static_signatures: FxDashMap<u128, (u64, Source, usize, Signature)>,
static_signatures: FxDashMap<u128, (u64, Source, usize, Option<Signature>)>,
docstrings: FxDashMap<u128, Option<Arc<DocString>>>,
signatures: FxDashMap<u128, (u64, foundations::Func, Signature)>,
signatures: FxDashMap<u128, (u64, foundations::Func, Option<Signature>)>,
}
/// A cache for all level of analysis results of a module.
@ -465,8 +465,59 @@ impl<'w> AnalysisContext<'w> {
analyze_signature(self, SignatureTarget::Runtime(func)).unwrap()
}
/// Compute the signature of a function.
pub fn compute_signature(
&mut self,
func: SignatureTarget,
compute: impl FnOnce(&mut Self) -> Option<Signature>,
) -> Option<Signature> {
if let Some(sig) = self.get_signature(&func) {
return Some(sig);
}
let res = compute(self);
match func {
SignatureTarget::Def(source, r) => {
let cache_key = (source, r.range.start);
let h = hash128(&cache_key);
let slot = self.analysis.caches.static_signatures.entry(h);
let slot = slot.or_insert_with(|| (self.lifetime, cache_key.0, cache_key.1, res));
slot.3.clone()
}
SignatureTarget::SyntaxFast(source, node) => {
let cache_key = (source, node.offset(), true);
self.analysis
.caches
.static_signatures
.entry(hash128(&cache_key))
.or_insert_with(|| (self.lifetime, cache_key.0, cache_key.1, res))
.3
.clone()
}
SignatureTarget::Syntax(source, node) => {
let cache_key = (source, node.offset());
self.analysis
.caches
.static_signatures
.entry(hash128(&cache_key))
.or_insert_with(|| (self.lifetime, cache_key.0, cache_key.1, res))
.3
.clone()
}
SignatureTarget::Runtime(rt) => {
let key = hash128(&rt);
self.analysis
.caches
.signatures
.entry(key)
.or_insert_with(|| (self.lifetime, rt, res))
.2
.clone()
}
}
}
/// Get the signature of a function.
pub fn get_signature(&self, func: &SignatureTarget) -> Option<Signature> {
fn get_signature(&self, func: &SignatureTarget) -> Option<Signature> {
match func {
SignatureTarget::Def(source, r) => {
// todo: check performance on peeking signature source frequently
@ -502,56 +553,7 @@ impl<'w> AnalysisContext<'w> {
.get(&hash128(rt))
.and_then(|slot| (rt == &slot.1).then_some(slot.2.clone())),
}
}
/// Compute the signature of a function.
pub fn compute_signature(
&self,
func: SignatureTarget,
compute: impl FnOnce() -> Signature,
) -> Signature {
match func {
SignatureTarget::Def(source, r) => {
let cache_key = (source, r.range.start);
let h = hash128(&cache_key);
let slot = self.analysis.caches.static_signatures.entry(h);
let slot = slot.or_insert_with(|| {
let sig = compute();
(self.lifetime, cache_key.0, cache_key.1, sig)
});
slot.3.clone()
}
SignatureTarget::SyntaxFast(source, node) => {
let cache_key = (source, node.offset(), true);
self.analysis
.caches
.static_signatures
.entry(hash128(&cache_key))
.or_insert_with(|| (self.lifetime, cache_key.0, cache_key.1, compute()))
.3
.clone()
}
SignatureTarget::Syntax(source, node) => {
let cache_key = (source, node.offset());
self.analysis
.caches
.static_signatures
.entry(hash128(&cache_key))
.or_insert_with(|| (self.lifetime, cache_key.0, cache_key.1, compute()))
.3
.clone()
}
SignatureTarget::Runtime(rt) => {
let key = hash128(&rt);
self.analysis
.caches
.signatures
.entry(key)
.or_insert_with(|| (self.lifetime, rt, compute()))
.2
.clone()
}
}
.flatten()
}
pub(crate) fn signature_docs(

View file

@ -211,6 +211,7 @@ pub struct PartialSignature {
}
/// The language object that the signature is being analyzed for.
#[derive(Debug, Clone)]
pub enum SignatureTarget<'a> {
/// A static node without knowing the function at runtime.
Def(Source, IdentRef),
@ -226,11 +227,11 @@ pub(crate) fn analyze_signature(
ctx: &mut AnalysisContext,
callee_node: SignatureTarget,
) -> Option<Signature> {
if let Some(sig) = ctx.get_signature(&callee_node) {
return Some(sig);
}
analyze_type_signature(ctx, &callee_node).or_else(|| analyze_dyn_signature(ctx, &callee_node))
ctx.compute_signature(callee_node.clone(), |ctx| {
log::debug!("analyzing signature for {callee_node:?}");
analyze_type_signature(ctx, &callee_node)
.or_else(|| analyze_dyn_signature(ctx, &callee_node))
})
}
fn analyze_type_signature(
@ -355,12 +356,7 @@ fn analyze_dyn_signature(
func = f.0.clone();
}
let signature = ctx
.compute_signature(SignatureTarget::Runtime(func.clone()), || {
Signature::Primary(analyze_dyn_signature_inner(func))
})
.primary()
.clone();
let signature = analyze_dyn_signature_inner(func);
log::trace!("got signature {signature:?}");
if with_stack.is_empty() {