Skip to content

Commit e935d38

Browse files
committed
Lazy DefPath decoding for incremental compilation
1 parent db79d2f commit e935d38

File tree

11 files changed

+275
-43
lines changed

11 files changed

+275
-43
lines changed

Diff for: compiler/rustc_incremental/src/persist/load.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Code to save/load the dep-graph from files.
22
33
use rustc_data_structures::fx::FxHashMap;
4+
use rustc_hir::definitions::Definitions;
45
use rustc_middle::dep_graph::{PreviousDepGraph, SerializedDepGraph, WorkProduct, WorkProductId};
56
use rustc_middle::ty::query::OnDiskCache;
67
use rustc_middle::ty::TyCtxt;
@@ -204,7 +205,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
204205
/// If we are not in incremental compilation mode, returns `None`.
205206
/// Otherwise, tries to load the query result cache from disk,
206207
/// creating an empty cache if it could not be loaded.
207-
pub fn load_query_result_cache(sess: &Session) -> Option<OnDiskCache<'_>> {
208+
pub fn load_query_result_cache<'a>(sess: &'a Session, definitions: &Definitions) -> Option<OnDiskCache<'a>> {
208209
if sess.opts.incremental.is_none() {
209210
return None;
210211
}
@@ -216,9 +217,7 @@ pub fn load_query_result_cache(sess: &Session) -> Option<OnDiskCache<'_>> {
216217
&query_cache_path(sess),
217218
sess.is_nightly_build(),
218219
) {
219-
LoadResult::Ok { data: (bytes, start_pos) } => {
220-
Some(OnDiskCache::new(sess, bytes, start_pos))
221-
}
220+
LoadResult::Ok { data: (bytes, start_pos) } => Some(OnDiskCache::new(sess, bytes, start_pos, definitions)),
222221
_ => Some(OnDiskCache::new_empty(sess.source_map())),
223222
}
224223
}

Diff for: compiler/rustc_interface/src/passes.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -747,7 +747,7 @@ pub fn create_global_ctxt<'tcx>(
747747
Definitions::new(crate_name, sess.local_crate_disambiguator()),
748748
));
749749

750-
let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess);
750+
let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess, defs);
751751

752752
let codegen_backend = compiler.codegen_backend();
753753
let mut local_providers = *DEFAULT_QUERY_PROVIDERS;

Diff for: compiler/rustc_metadata/src/rmeta/decoder.rs

+52
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ crate struct CrateMetadata {
7777
raw_proc_macros: Option<&'static [ProcMacro]>,
7878
/// Source maps for code from the crate.
7979
source_map_import_info: OnceCell<Vec<ImportedSourceFile>>,
80+
/// For every definition in this crate, maps its `DefPathHash` to its
81+
/// `DefIndex`. See `raw_def_id_to_def_id` for more details about how
82+
/// this is used.
83+
def_path_hash_map: OnceCell<FxHashMap<DefPathHash, DefIndex>>,
8084
/// Used for decoding interpret::AllocIds in a cached & thread-safe manner.
8185
alloc_decoding_state: AllocDecodingState,
8286
/// The `DepNodeIndex` of the `DepNode` representing this upstream crate.
@@ -1556,6 +1560,53 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
15561560
})
15571561
}
15581562

1563+
/// Finds the corresponding `DefId` for the provided `DefPathHash`, if it exists.
1564+
/// This is used by incremental compilation to map a serialized `DefPathHash` to
1565+
/// its `DefId` in the current session.
1566+
/// Normally, only one 'main' crate will change between incremental compilation sessions:
1567+
/// all dependencies will be completely unchanged. In this case, we can avoid
1568+
/// decoding every `DefPathHash` in the crate, since the `DefIndex` from the previous
1569+
/// session will still be valid. If our 'guess' is wrong (the `DefIndex` no longer exists,
1570+
/// or has a different `DefPathHash`, then we need to decode all `DefPathHashes` to determine
1571+
/// the correct mapping).
1572+
fn def_path_hash_to_def_id(
1573+
&self,
1574+
krate: CrateNum,
1575+
index_guess: u32,
1576+
hash: DefPathHash,
1577+
) -> Option<DefId> {
1578+
let def_index_guess = DefIndex::from_u32(index_guess);
1579+
let old_hash = self
1580+
.root
1581+
.tables
1582+
.def_path_hashes
1583+
.get(self, def_index_guess)
1584+
.map(|lazy| lazy.decode(self));
1585+
1586+
// Fast path: the definition and its index is unchanged from the
1587+
// previous compilation session. There is no need to decode anything
1588+
// else
1589+
if old_hash == Some(hash) {
1590+
return Some(DefId { krate, index: def_index_guess });
1591+
}
1592+
1593+
// Slow path: We need to find out the new `DefIndex` of the provided
1594+
// `DefPathHash`, if its still exists. This requires decoding every `DefPathHash`
1595+
// stored in this crate.
1596+
let map = self.cdata.def_path_hash_map.get_or_init(|| {
1597+
let end_id = self.root.tables.def_path_hashes.size() as u32;
1598+
let mut map = FxHashMap::with_capacity_and_hasher(end_id as usize, Default::default());
1599+
for i in 0..end_id {
1600+
let def_index = DefIndex::from_u32(i);
1601+
let hash =
1602+
self.root.tables.def_path_hashes.get(self, def_index).unwrap().decode(self);
1603+
map.insert(hash, def_index);
1604+
}
1605+
map
1606+
});
1607+
map.get(&hash).map(|index| DefId { krate, index: *index })
1608+
}
1609+
15591610
// Returns the path leading to the thing with this `id`.
15601611
fn def_path(&self, id: DefIndex) -> DefPath {
15611612
debug!("def_path(cnum={:?}, id={:?})", self.cnum, id);
@@ -1834,6 +1885,7 @@ impl CrateMetadata {
18341885
trait_impls,
18351886
raw_proc_macros,
18361887
source_map_import_info: OnceCell::new(),
1888+
def_path_hash_map: Default::default(),
18371889
alloc_decoding_state,
18381890
dep_node_index: AtomicCell::new(DepNodeIndex::INVALID),
18391891
cnum,

Diff for: compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs

+10
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,16 @@ impl CrateStore for CStore {
506506
self.get_crate_data(cnum).num_def_ids()
507507
}
508508

509+
// See `CrateMetadataRef::def_path_hash_to_def_id` for more details
510+
fn def_path_hash_to_def_id(
511+
&self,
512+
cnum: CrateNum,
513+
index_guess: u32,
514+
hash: DefPathHash,
515+
) -> Option<DefId> {
516+
self.get_crate_data(cnum).def_path_hash_to_def_id(cnum, index_guess, hash)
517+
}
518+
509519
fn crates_untracked(&self) -> Vec<CrateNum> {
510520
let mut result = vec![];
511521
self.iter_crate_data(|cnum, _| result.push(cnum));

Diff for: compiler/rustc_middle/src/dep_graph/dep_node.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,8 @@ macro_rules! define_dep_nodes {
252252
/// has been removed.
253253
fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> {
254254
if self.kind.can_reconstruct_query_key() {
255-
let def_path_hash = DefPathHash(self.hash.into());
256-
tcx.def_path_hash_to_def_id.as_ref()?.get(&def_path_hash).cloned()
255+
let def_path_hash = DefPathHash(self.hash);
256+
tcx.queries.on_disk_cache.as_ref()?.def_path_hash_to_def_id(tcx, def_path_hash)
257257
} else {
258258
None
259259
}
@@ -320,7 +320,15 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId {
320320
}
321321

322322
fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
323-
tcx.def_path_hash(*self).0
323+
let hash = tcx.def_path_hash(*self);
324+
// If this is a foreign `DefId`, store its current value
325+
// in the incremental cache. When we decode the cache,
326+
// we will use the old DefIndex as an initial guess for
327+
// a lookup into the crate metadata.
328+
if !self.is_local() {
329+
tcx.queries.on_disk_cache.store_foreign_def_id_hash(*self, hash);
330+
}
331+
hash.0
324332
}
325333

326334
fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
@@ -359,7 +367,7 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for CrateNum {
359367

360368
fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
361369
let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX };
362-
tcx.def_path_hash(def_id).0
370+
def_id.to_fingerprint(tcx)
363371
}
364372

365373
fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {

Diff for: compiler/rustc_middle/src/dep_graph/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_data_structures::profiling::SelfProfilerRef;
55
use rustc_data_structures::sync::Lock;
66
use rustc_data_structures::thin_vec::ThinVec;
77
use rustc_errors::Diagnostic;
8-
use rustc_hir::def_id::LocalDefId;
8+
use rustc_hir::def_id::{DefPathHash, LocalDefId};
99

1010
mod dep_node;
1111

@@ -91,6 +91,10 @@ impl<'tcx> DepContext for TyCtxt<'tcx> {
9191
type DepKind = DepKind;
9292
type StableHashingContext = StableHashingContext<'tcx>;
9393

94+
fn register_reused_dep_path_hash(&self, hash: DefPathHash) {
95+
self.queries.on_disk_cache.register_reused_dep_path_hash(hash)
96+
}
97+
9498
fn create_stable_hashing_context(&self) -> Self::StableHashingContext {
9599
TyCtxt::create_stable_hashing_context(*self)
96100
}

Diff for: compiler/rustc_middle/src/middle/cstore.rs

+6
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,12 @@ pub trait CrateStore {
191191
fn def_path_hash(&self, def: DefId) -> DefPathHash;
192192
fn all_def_path_hashes_and_def_ids(&self, cnum: CrateNum) -> Vec<(DefPathHash, DefId)>;
193193
fn num_def_ids(&self, cnum: CrateNum) -> usize;
194+
fn def_path_hash_to_def_id(
195+
&self,
196+
cnum: CrateNum,
197+
index_guess: u32,
198+
hash: DefPathHash,
199+
) -> Option<DefId>;
194200

195201
// "queries" used in resolve that aren't tracked for incremental compilation
196202
fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol;

Diff for: compiler/rustc_middle/src/ty/context.rs

+6-25
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Type context book-keeping.
22
33
use crate::arena::Arena;
4-
use crate::dep_graph::{self, DepConstructor, DepGraph};
4+
use crate::dep_graph::{self, DepGraph, DepKind, DepNode, DepNodeExt};
55
use crate::hir::exports::ExportMap;
66
use crate::ich::{NodeIdHashingMode, StableHashingContext};
77
use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
@@ -34,12 +34,12 @@ use rustc_data_structures::stable_hasher::{
3434
};
3535
use rustc_data_structures::steal::Steal;
3636
use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal};
37-
use rustc_data_structures::unhash::UnhashMap;
3837
use rustc_errors::ErrorReported;
3938
use rustc_hir as hir;
4039
use rustc_hir::def::{DefKind, Res};
41-
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
42-
use rustc_hir::definitions::{DefPathHash, Definitions};
40+
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId};
41+
use rustc_hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE};
42+
use rustc_hir::definitions::Definitions;
4343
use rustc_hir::intravisit::Visitor;
4444
use rustc_hir::lang_items::LangItem;
4545
use rustc_hir::{
@@ -945,10 +945,6 @@ pub struct GlobalCtxt<'tcx> {
945945
pub(crate) untracked_crate: &'tcx hir::Crate<'tcx>,
946946
pub(crate) definitions: &'tcx Definitions,
947947

948-
/// A map from `DefPathHash` -> `DefId`. Includes `DefId`s from the local crate
949-
/// as well as all upstream crates. Only populated in incremental mode.
950-
pub def_path_hash_to_def_id: Option<UnhashMap<DefPathHash, DefId>>,
951-
952948
pub queries: query::Queries<'tcx>,
953949

954950
maybe_unused_trait_imports: FxHashSet<LocalDefId>,
@@ -1113,21 +1109,6 @@ impl<'tcx> TyCtxt<'tcx> {
11131109
let mut providers = IndexVec::from_elem_n(extern_providers, max_cnum + 1);
11141110
providers[LOCAL_CRATE] = local_providers;
11151111

1116-
let def_path_hash_to_def_id = if s.opts.build_dep_graph() {
1117-
let capacity = definitions.def_path_table().num_def_ids()
1118-
+ crates.iter().map(|cnum| cstore.num_def_ids(*cnum)).sum::<usize>();
1119-
let mut map = UnhashMap::with_capacity_and_hasher(capacity, Default::default());
1120-
1121-
map.extend(definitions.def_path_table().all_def_path_hashes_and_def_ids(LOCAL_CRATE));
1122-
for cnum in &crates {
1123-
map.extend(cstore.all_def_path_hashes_and_def_ids(*cnum).into_iter());
1124-
}
1125-
1126-
Some(map)
1127-
} else {
1128-
None
1129-
};
1130-
11311112
let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default();
11321113
for (hir_id, v) in krate.trait_map.iter() {
11331114
let map = trait_map.entry(hir_id.owner).or_default();
@@ -1155,7 +1136,6 @@ impl<'tcx> TyCtxt<'tcx> {
11551136
extern_prelude: resolutions.extern_prelude,
11561137
untracked_crate: krate,
11571138
definitions,
1158-
def_path_hash_to_def_id,
11591139
queries: query::Queries::new(providers, extern_providers, on_disk_query_result_cache),
11601140
ty_rcache: Default::default(),
11611141
pred_rcache: Default::default(),
@@ -1329,7 +1309,8 @@ impl<'tcx> TyCtxt<'tcx> {
13291309
// We cannot use the query versions of crates() and crate_hash(), since
13301310
// those would need the DepNodes that we are allocating here.
13311311
for cnum in self.cstore.crates_untracked() {
1332-
let dep_node = DepConstructor::CrateMetadata(self, cnum);
1312+
let def_path_hash = self.def_path_hash(DefId { krate: cnum, index: CRATE_DEF_INDEX });
1313+
let dep_node = DepNode::from_def_path_hash(def_path_hash, DepKind::CrateMetadata);
13331314
let crate_hash = self.cstore.crate_hash_untracked(cnum);
13341315
self.dep_graph.with_task(
13351316
dep_node,

0 commit comments

Comments
 (0)