mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 11:20:54 +00:00
Merge pull request #20527 from ChayimFriedman2/cache-next-solver
perf: Cache trait solving across queries in the same revision
This commit is contained in:
commit
1d90205a98
@ -7,7 +7,12 @@ pub use salsa_macros;
|
||||
mod change;
|
||||
mod input;
|
||||
|
||||
use std::{cell::RefCell, hash::BuildHasherDefault, panic, sync::Once};
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
hash::BuildHasherDefault,
|
||||
panic,
|
||||
sync::{Once, atomic::AtomicUsize},
|
||||
};
|
||||
|
||||
pub use crate::{
|
||||
change::FileChange,
|
||||
@ -328,6 +333,27 @@ pub trait SourceDatabase: salsa::Database {
|
||||
|
||||
#[doc(hidden)]
|
||||
fn crates_map(&self) -> Arc<CratesMap>;
|
||||
|
||||
fn nonce_and_revision(&self) -> (Nonce, salsa::Revision);
|
||||
}
|
||||
|
||||
static NEXT_NONCE: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct Nonce(usize);
|
||||
|
||||
impl Default for Nonce {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Nonce::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Nonce {
|
||||
#[inline]
|
||||
pub fn new() -> Nonce {
|
||||
Nonce(NEXT_NONCE.fetch_add(1, std::sync::atomic::Ordering::SeqCst))
|
||||
}
|
||||
}
|
||||
|
||||
/// Crate related data shared by the whole workspace.
|
||||
|
@ -3,7 +3,7 @@
|
||||
use std::{fmt, panic, sync::Mutex};
|
||||
|
||||
use base_db::{
|
||||
Crate, CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, RootQueryDb,
|
||||
Crate, CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, Nonce, RootQueryDb,
|
||||
SourceDatabase, SourceRoot, SourceRootId, SourceRootInput,
|
||||
};
|
||||
use hir_expand::{InFile, files::FilePosition};
|
||||
@ -20,12 +20,12 @@ use crate::{
|
||||
};
|
||||
|
||||
#[salsa_macros::db]
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct TestDB {
|
||||
storage: salsa::Storage<Self>,
|
||||
files: Arc<base_db::Files>,
|
||||
crates_map: Arc<CratesMap>,
|
||||
events: Arc<Mutex<Option<Vec<salsa::Event>>>>,
|
||||
nonce: Nonce,
|
||||
}
|
||||
|
||||
impl Default for TestDB {
|
||||
@ -44,6 +44,7 @@ impl Default for TestDB {
|
||||
events,
|
||||
files: Default::default(),
|
||||
crates_map: Default::default(),
|
||||
nonce: Nonce::new(),
|
||||
};
|
||||
this.set_expand_proc_attr_macros_with_durability(true, Durability::HIGH);
|
||||
// This needs to be here otherwise `CrateGraphBuilder` panics.
|
||||
@ -53,6 +54,18 @@ impl Default for TestDB {
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for TestDB {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
storage: self.storage.clone(),
|
||||
files: self.files.clone(),
|
||||
crates_map: self.crates_map.clone(),
|
||||
events: self.events.clone(),
|
||||
nonce: Nonce::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa_macros::db]
|
||||
impl salsa::Database for TestDB {}
|
||||
|
||||
@ -117,6 +130,10 @@ impl SourceDatabase for TestDB {
|
||||
fn crates_map(&self) -> Arc<CratesMap> {
|
||||
self.crates_map.clone()
|
||||
}
|
||||
|
||||
fn nonce_and_revision(&self) -> (Nonce, salsa::Revision) {
|
||||
(self.nonce, salsa::plumbing::ZalsaDatabase::zalsa(self).current_revision())
|
||||
}
|
||||
}
|
||||
|
||||
impl TestDB {
|
||||
|
@ -88,54 +88,52 @@ pub(crate) use closure::{CaptureKind, CapturedItem, CapturedItemWithoutTy};
|
||||
|
||||
/// The entry point of type inference.
|
||||
pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> {
|
||||
crate::next_solver::with_new_cache(|| {
|
||||
let _p = tracing::info_span!("infer_query").entered();
|
||||
let resolver = def.resolver(db);
|
||||
let body = db.body(def);
|
||||
let mut ctx = InferenceContext::new(db, def, &body, resolver);
|
||||
let _p = tracing::info_span!("infer_query").entered();
|
||||
let resolver = def.resolver(db);
|
||||
let body = db.body(def);
|
||||
let mut ctx = InferenceContext::new(db, def, &body, resolver);
|
||||
|
||||
match def {
|
||||
DefWithBodyId::FunctionId(f) => {
|
||||
ctx.collect_fn(f);
|
||||
}
|
||||
DefWithBodyId::ConstId(c) => ctx.collect_const(c, &db.const_signature(c)),
|
||||
DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_signature(s)),
|
||||
DefWithBodyId::VariantId(v) => {
|
||||
ctx.return_ty = TyBuilder::builtin(
|
||||
match db.enum_signature(v.lookup(db).parent).variant_body_type() {
|
||||
hir_def::layout::IntegerType::Pointer(signed) => match signed {
|
||||
true => BuiltinType::Int(BuiltinInt::Isize),
|
||||
false => BuiltinType::Uint(BuiltinUint::Usize),
|
||||
},
|
||||
hir_def::layout::IntegerType::Fixed(size, signed) => match signed {
|
||||
true => BuiltinType::Int(match size {
|
||||
Integer::I8 => BuiltinInt::I8,
|
||||
Integer::I16 => BuiltinInt::I16,
|
||||
Integer::I32 => BuiltinInt::I32,
|
||||
Integer::I64 => BuiltinInt::I64,
|
||||
Integer::I128 => BuiltinInt::I128,
|
||||
}),
|
||||
false => BuiltinType::Uint(match size {
|
||||
Integer::I8 => BuiltinUint::U8,
|
||||
Integer::I16 => BuiltinUint::U16,
|
||||
Integer::I32 => BuiltinUint::U32,
|
||||
Integer::I64 => BuiltinUint::U64,
|
||||
Integer::I128 => BuiltinUint::U128,
|
||||
}),
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
match def {
|
||||
DefWithBodyId::FunctionId(f) => {
|
||||
ctx.collect_fn(f);
|
||||
}
|
||||
DefWithBodyId::ConstId(c) => ctx.collect_const(c, &db.const_signature(c)),
|
||||
DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_signature(s)),
|
||||
DefWithBodyId::VariantId(v) => {
|
||||
ctx.return_ty = TyBuilder::builtin(
|
||||
match db.enum_signature(v.lookup(db).parent).variant_body_type() {
|
||||
hir_def::layout::IntegerType::Pointer(signed) => match signed {
|
||||
true => BuiltinType::Int(BuiltinInt::Isize),
|
||||
false => BuiltinType::Uint(BuiltinUint::Usize),
|
||||
},
|
||||
hir_def::layout::IntegerType::Fixed(size, signed) => match signed {
|
||||
true => BuiltinType::Int(match size {
|
||||
Integer::I8 => BuiltinInt::I8,
|
||||
Integer::I16 => BuiltinInt::I16,
|
||||
Integer::I32 => BuiltinInt::I32,
|
||||
Integer::I64 => BuiltinInt::I64,
|
||||
Integer::I128 => BuiltinInt::I128,
|
||||
}),
|
||||
false => BuiltinType::Uint(match size {
|
||||
Integer::I8 => BuiltinUint::U8,
|
||||
Integer::I16 => BuiltinUint::U16,
|
||||
Integer::I32 => BuiltinUint::U32,
|
||||
Integer::I64 => BuiltinUint::U64,
|
||||
Integer::I128 => BuiltinUint::U128,
|
||||
}),
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ctx.infer_body();
|
||||
ctx.infer_body();
|
||||
|
||||
ctx.infer_mut_body();
|
||||
ctx.infer_mut_body();
|
||||
|
||||
ctx.infer_closures();
|
||||
ctx.infer_closures();
|
||||
|
||||
Arc::new(ctx.resolve_all())
|
||||
})
|
||||
Arc::new(ctx.resolve_all())
|
||||
}
|
||||
|
||||
pub(crate) fn infer_cycle_result(_: &dyn HirDatabase, _: DefWithBodyId) -> Arc<InferenceResult> {
|
||||
|
@ -2168,9 +2168,7 @@ pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result<Arc<Mi
|
||||
let _p = tracing::info_span!("mir_body_query", ?detail).entered();
|
||||
let body = db.body(def);
|
||||
let infer = db.infer(def);
|
||||
let mut result = crate::next_solver::with_new_cache(|| {
|
||||
lower_to_mir(db, def, &body, &infer, body.body_expr)
|
||||
})?;
|
||||
let mut result = lower_to_mir(db, def, &body, &infer, body.body_expr)?;
|
||||
result.shrink_to_fit();
|
||||
Ok(Arc::new(result))
|
||||
}
|
||||
|
@ -2148,37 +2148,48 @@ TrivialTypeTraversalImpls! {
|
||||
Placeholder<BoundVar>,
|
||||
}
|
||||
|
||||
pub(crate) use tls_cache::with_new_cache;
|
||||
mod tls_cache {
|
||||
use crate::db::HirDatabase;
|
||||
|
||||
use super::DbInterner;
|
||||
use base_db::Nonce;
|
||||
use rustc_type_ir::search_graph::GlobalCache;
|
||||
use salsa::Revision;
|
||||
use std::cell::RefCell;
|
||||
|
||||
scoped_tls::scoped_thread_local!(static GLOBAL_CACHE: RefCell<rustc_type_ir::search_graph::GlobalCache<DbInterner<'static>>>);
|
||||
struct Cache {
|
||||
cache: GlobalCache<DbInterner<'static>>,
|
||||
revision: Revision,
|
||||
db_nonce: Nonce,
|
||||
}
|
||||
|
||||
pub(crate) fn with_new_cache<T>(f: impl FnOnce() -> T) -> T {
|
||||
GLOBAL_CACHE.set(&RefCell::new(GlobalCache::default()), f)
|
||||
thread_local! {
|
||||
static GLOBAL_CACHE: RefCell<Option<Cache>> = const { RefCell::new(None) };
|
||||
}
|
||||
|
||||
pub(super) fn with_cache<'db, T>(
|
||||
_db: &'db dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
f: impl FnOnce(&mut GlobalCache<DbInterner<'db>>) -> T,
|
||||
) -> T {
|
||||
// SAFETY: No idea
|
||||
let call = move |slot: &RefCell<_>| {
|
||||
GLOBAL_CACHE.with_borrow_mut(|handle| {
|
||||
let (db_nonce, revision) = db.nonce_and_revision();
|
||||
let handle = match handle {
|
||||
Some(handle) => {
|
||||
if handle.revision != revision || db_nonce != handle.db_nonce {
|
||||
*handle = Cache { cache: GlobalCache::default(), revision, db_nonce };
|
||||
}
|
||||
handle
|
||||
}
|
||||
None => handle.insert(Cache { cache: GlobalCache::default(), revision, db_nonce }),
|
||||
};
|
||||
|
||||
// SAFETY: No idea
|
||||
f(unsafe {
|
||||
std::mem::transmute::<
|
||||
&mut GlobalCache<DbInterner<'static>>,
|
||||
&mut GlobalCache<DbInterner<'db>>,
|
||||
>(&mut *slot.borrow_mut())
|
||||
>(&mut handle.cache)
|
||||
})
|
||||
};
|
||||
if GLOBAL_CACHE.is_set() {
|
||||
GLOBAL_CACHE.with(call)
|
||||
} else {
|
||||
GLOBAL_CACHE.set(&RefCell::new(GlobalCache::default()), || GLOBAL_CACHE.with(call))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,8 @@
|
||||
use std::{fmt, panic, sync::Mutex};
|
||||
|
||||
use base_db::{
|
||||
CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, RootQueryDb, SourceDatabase,
|
||||
SourceRoot, SourceRootId, SourceRootInput,
|
||||
CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, Nonce, RootQueryDb,
|
||||
SourceDatabase, SourceRoot, SourceRootId, SourceRootInput,
|
||||
};
|
||||
|
||||
use hir_def::{ModuleId, db::DefDatabase, nameres::crate_def_map};
|
||||
@ -17,12 +17,12 @@ use test_utils::extract_annotations;
|
||||
use triomphe::Arc;
|
||||
|
||||
#[salsa_macros::db]
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct TestDB {
|
||||
storage: salsa::Storage<Self>,
|
||||
files: Arc<base_db::Files>,
|
||||
crates_map: Arc<CratesMap>,
|
||||
events: Arc<Mutex<Option<Vec<salsa::Event>>>>,
|
||||
nonce: Nonce,
|
||||
}
|
||||
|
||||
impl Default for TestDB {
|
||||
@ -41,6 +41,7 @@ impl Default for TestDB {
|
||||
events,
|
||||
files: Default::default(),
|
||||
crates_map: Default::default(),
|
||||
nonce: Nonce::new(),
|
||||
};
|
||||
this.set_expand_proc_attr_macros_with_durability(true, Durability::HIGH);
|
||||
// This needs to be here otherwise `CrateGraphBuilder` panics.
|
||||
@ -50,6 +51,18 @@ impl Default for TestDB {
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for TestDB {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
storage: self.storage.clone(),
|
||||
files: self.files.clone(),
|
||||
crates_map: self.crates_map.clone(),
|
||||
events: self.events.clone(),
|
||||
nonce: Nonce::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for TestDB {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("TestDB").finish()
|
||||
@ -109,6 +122,10 @@ impl SourceDatabase for TestDB {
|
||||
fn crates_map(&self) -> Arc<CratesMap> {
|
||||
self.crates_map.clone()
|
||||
}
|
||||
|
||||
fn nonce_and_revision(&self) -> (Nonce, salsa::Revision) {
|
||||
(self.nonce, salsa::plumbing::ZalsaDatabase::zalsa(self).current_revision())
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa_macros::db]
|
||||
|
@ -51,7 +51,7 @@ use salsa::Durability;
|
||||
use std::{fmt, mem::ManuallyDrop};
|
||||
|
||||
use base_db::{
|
||||
CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, Files, RootQueryDb,
|
||||
CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, Files, Nonce, RootQueryDb,
|
||||
SourceDatabase, SourceRoot, SourceRootId, SourceRootInput, query_group,
|
||||
};
|
||||
use hir::{
|
||||
@ -83,6 +83,7 @@ pub struct RootDatabase {
|
||||
storage: ManuallyDrop<salsa::Storage<Self>>,
|
||||
files: Arc<Files>,
|
||||
crates_map: Arc<CratesMap>,
|
||||
nonce: Nonce,
|
||||
}
|
||||
|
||||
impl std::panic::RefUnwindSafe for RootDatabase {}
|
||||
@ -102,6 +103,7 @@ impl Clone for RootDatabase {
|
||||
storage: self.storage.clone(),
|
||||
files: self.files.clone(),
|
||||
crates_map: self.crates_map.clone(),
|
||||
nonce: Nonce::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -165,6 +167,10 @@ impl SourceDatabase for RootDatabase {
|
||||
fn crates_map(&self) -> Arc<CratesMap> {
|
||||
self.crates_map.clone()
|
||||
}
|
||||
|
||||
fn nonce_and_revision(&self) -> (Nonce, salsa::Revision) {
|
||||
(self.nonce, salsa::plumbing::ZalsaDatabase::zalsa(self).current_revision())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for RootDatabase {
|
||||
@ -179,6 +185,7 @@ impl RootDatabase {
|
||||
storage: ManuallyDrop::new(salsa::Storage::default()),
|
||||
files: Default::default(),
|
||||
crates_map: Default::default(),
|
||||
nonce: Nonce::new(),
|
||||
};
|
||||
// This needs to be here otherwise `CrateGraphBuilder` will panic.
|
||||
db.set_all_crates(Arc::new(Box::new([])));
|
||||
|
Loading…
x
Reference in New Issue
Block a user