Skip to content

Commit d9ae790

Browse files
Merge pull request #22104 from ChayimFriedman2/reinit-cache
perf: Do not check solver's cache validity on every access
2 parents adef948 + 3e4c332 commit d9ae790

2 files changed

Lines changed: 38 additions & 8 deletions

File tree

crates/hir-ty/src/next_solver/infer/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,10 @@ impl<'db> InferCtxtBuilder<'db> {
372372
}
373373

374374
pub fn build(&mut self, typing_mode: TypingMode<'db>) -> InferCtxt<'db> {
375+
// We do not allow creating an InferCtxt for an Interner without a crate, because this means
376+
// an interner without a crate cannot access the cache, therefore constructing it doesn't need
377+
// to reinit the cache, and we construct a lot of no-crate interners.
378+
self.interner.expect_crate();
375379
let InferCtxtBuilder { interner } = *self;
376380
InferCtxt {
377381
interner,

crates/hir-ty/src/next_solver/interner.rs

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ unsafe impl Sync for DbInterner<'_> {}
327327
impl<'db> DbInterner<'db> {
328328
// FIXME(next-solver): remove this method
329329
pub fn conjure() -> DbInterner<'db> {
330+
// Here we can not reinit the cache since we do that when we attach the db.
330331
crate::with_attached_db(|db| DbInterner {
331332
db: unsafe { std::mem::transmute::<&dyn HirDatabase, &'db dyn HirDatabase>(db) },
332333
krate: None,
@@ -339,10 +340,13 @@ impl<'db> DbInterner<'db> {
339340
///
340341
/// Elaboration is a special kind: it needs lang items (for `Sized`), therefore it needs `new_with()`.
341342
pub fn new_no_crate(db: &'db dyn HirDatabase) -> Self {
343+
// We do not reinit the cache here, since anything accessing the cache needs an InferCtxt,
344+
// and we panic when trying to construct an InferCtxt for an Interner without a crate.
342345
DbInterner { db, krate: None, lang_items: None }
343346
}
344347

345348
pub fn new_with(db: &'db dyn HirDatabase, krate: Crate) -> DbInterner<'db> {
349+
tls_cache::reinit_cache(db);
346350
DbInterner {
347351
db,
348352
krate: Some(krate),
@@ -1120,7 +1124,8 @@ impl<'db> Interner for DbInterner<'db> {
11201124
self,
11211125
f: impl FnOnce(&mut rustc_type_ir::search_graph::GlobalCache<Self>) -> R,
11221126
) -> R {
1123-
tls_cache::with_cache(self.db, f)
1127+
// We make sure to reinit the cache when constructing the Interner.
1128+
tls_cache::borrow_assume_valid(self.db, f)
11241129
}
11251130

11261131
fn canonical_param_env_cache_get_or_insert<R>(
@@ -2475,6 +2480,7 @@ mod tls_db {
24752480
}
24762481

24772482
let _guard = DbGuard::new(self, db);
2483+
super::tls_cache::reinit_cache(db);
24782484
op()
24792485
}
24802486

@@ -2497,10 +2503,14 @@ mod tls_db {
24972503
#[inline]
24982504
fn drop(&mut self) {
24992505
self.state.database.set(self.prev);
2506+
if let Some(prev) = self.prev {
2507+
super::tls_cache::reinit_cache(unsafe { prev.as_ref() });
2508+
}
25002509
}
25012510
}
25022511

25032512
let _guard = DbGuard::new(self, db);
2513+
super::tls_cache::reinit_cache(db);
25042514
op()
25052515
}
25062516

@@ -2555,22 +2565,38 @@ mod tls_cache {
25552565
static GLOBAL_CACHE: RefCell<Option<Cache>> = const { RefCell::new(None) };
25562566
}
25572567

2558-
pub(super) fn with_cache<'db, T>(
2559-
db: &'db dyn HirDatabase,
2560-
f: impl FnOnce(&mut GlobalCache<DbInterner<'db>>) -> T,
2561-
) -> T {
2568+
pub(super) fn reinit_cache(db: &dyn HirDatabase) {
25622569
GLOBAL_CACHE.with_borrow_mut(|handle| {
25632570
let (db_nonce, revision) = db.nonce_and_revision();
2564-
let handle = match handle {
2571+
match handle {
25652572
Some(handle) => {
25662573
if handle.revision != revision || db_nonce != handle.db_nonce {
25672574
*handle = Cache { cache: GlobalCache::default(), revision, db_nonce };
25682575
}
2569-
handle
25702576
}
2571-
None => handle.insert(Cache { cache: GlobalCache::default(), revision, db_nonce }),
2577+
None => *handle = Some(Cache { cache: GlobalCache::default(), revision, db_nonce }),
2578+
}
2579+
})
2580+
}
2581+
2582+
pub(super) fn borrow_assume_valid<'db, T>(
2583+
db: &'db dyn HirDatabase,
2584+
f: impl FnOnce(&mut GlobalCache<DbInterner<'db>>) -> T,
2585+
) -> T {
2586+
if cfg!(debug_assertions) {
2587+
let get_state = || {
2588+
GLOBAL_CACHE.with_borrow(|handle| {
2589+
handle.as_ref().map(|handle| (handle.db_nonce, handle.revision))
2590+
})
25722591
};
2592+
let old_state = get_state();
2593+
reinit_cache(db);
2594+
let new_state = get_state();
2595+
assert_eq!(old_state, new_state, "you assumed the cache is valid!");
2596+
}
25732597

2598+
GLOBAL_CACHE.with_borrow_mut(|handle| {
2599+
let handle = handle.as_mut().expect("you assumed the cache is valid!");
25742600
// SAFETY: No idea
25752601
f(unsafe {
25762602
std::mem::transmute::<

0 commit comments

Comments
 (0)