Skip to content

Commit 4cbda82

Browse files
committed
Auto merge of #74967 - Aaron1011:feature/incr-def-path-table, r=pnkfelix
Implement lazy decoding of DefPathTable during incremental compilation PR rust-lang/rust#75813 implemented lazy decoding of the `DefPathTable` from crate metadata. However, it requires decoding the entire `DefPathTable` when incremental compilation is active, so that we can map a decoded `DefPathHash` to a `DefId` from an arbitrary crate. This PR adds support for lazy decoding of dependency `DefPathTable`s when incremental compilation si active. When we load the incremental cache and dep graph, we need the ability to map a `DefPathHash` to a `DefId` in the current compilation session (if the corresponding definition still exists). This is accomplished by storing the old `DefId` (that is, the `DefId` from the previous compilation session) for each `DefPathHash` we need to remap. Since a `DefPathHash` includes the owning crate, the old crate is guaranteed to be the right one (if the definition still exists). We then use the old `DefIndex` as an initial guess, which we validate by comparing the expected and actual `DefPathHash`es. In most cases, foreign crates will be completely unchanged, which means that we our guess will be correct. If our guess is wrong, we fall back to decoding the entire `DefPathTable` for the foreign crate. This still represents an improvement over the status quo, since we can skip decoding the entire `DefPathTable` for other crates (where all of our guesses were correct).
2 parents b2dd829 + 7a9aa4f commit 4cbda82

File tree

11 files changed

+289
-40
lines changed

11 files changed

+289
-40
lines changed

compiler/rustc_incremental/src/persist/load.rs

+6-2
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,10 @@ 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>(
209+
sess: &'a Session,
210+
definitions: &Definitions,
211+
) -> Option<OnDiskCache<'a>> {
208212
if sess.opts.incremental.is_none() {
209213
return None;
210214
}
@@ -217,7 +221,7 @@ pub fn load_query_result_cache(sess: &Session) -> Option<OnDiskCache<'_>> {
217221
sess.is_nightly_build(),
218222
) {
219223
LoadResult::Ok { data: (bytes, start_pos) } => {
220-
Some(OnDiskCache::new(sess, bytes, start_pos))
224+
Some(OnDiskCache::new(sess, bytes, start_pos, definitions))
221225
}
222226
_ => Some(OnDiskCache::new_empty(sess.source_map())),
223227
}

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;

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.
@@ -1519,6 +1523,53 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
15191523
.or_insert_with(|| self.root.tables.def_keys.get(self, index).unwrap().decode(self))
15201524
}
15211525

1526+
/// Finds the corresponding `DefId` for the provided `DefPathHash`, if it exists.
1527+
/// This is used by incremental compilation to map a serialized `DefPathHash` to
1528+
/// its `DefId` in the current session.
1529+
/// Normally, only one 'main' crate will change between incremental compilation sessions:
1530+
/// all dependencies will be completely unchanged. In this case, we can avoid
1531+
/// decoding every `DefPathHash` in the crate, since the `DefIndex` from the previous
1532+
/// session will still be valid. If our 'guess' is wrong (the `DefIndex` no longer exists,
1533+
/// or has a different `DefPathHash`, then we need to decode all `DefPathHashes` to determine
1534+
/// the correct mapping).
1535+
fn def_path_hash_to_def_id(
1536+
&self,
1537+
krate: CrateNum,
1538+
index_guess: u32,
1539+
hash: DefPathHash,
1540+
) -> Option<DefId> {
1541+
let def_index_guess = DefIndex::from_u32(index_guess);
1542+
let old_hash = self
1543+
.root
1544+
.tables
1545+
.def_path_hashes
1546+
.get(self, def_index_guess)
1547+
.map(|lazy| lazy.decode(self));
1548+
1549+
// Fast path: the definition and its index is unchanged from the
1550+
// previous compilation session. There is no need to decode anything
1551+
// else
1552+
if old_hash == Some(hash) {
1553+
return Some(DefId { krate, index: def_index_guess });
1554+
}
1555+
1556+
// Slow path: We need to find out the new `DefIndex` of the provided
1557+
// `DefPathHash`, if its still exists. This requires decoding every `DefPathHash`
1558+
// stored in this crate.
1559+
let map = self.cdata.def_path_hash_map.get_or_init(|| {
1560+
let end_id = self.root.tables.def_path_hashes.size() as u32;
1561+
let mut map = FxHashMap::with_capacity_and_hasher(end_id as usize, Default::default());
1562+
for i in 0..end_id {
1563+
let def_index = DefIndex::from_u32(i);
1564+
let hash =
1565+
self.root.tables.def_path_hashes.get(self, def_index).unwrap().decode(self);
1566+
map.insert(hash, def_index);
1567+
}
1568+
map
1569+
});
1570+
map.get(&hash).map(|index| DefId { krate, index: *index })
1571+
}
1572+
15221573
// Returns the path leading to the thing with this `id`.
15231574
fn def_path(&self, id: DefIndex) -> DefPath {
15241575
debug!("def_path(cnum={:?}, id={:?})", self.cnum, id);
@@ -1797,6 +1848,7 @@ impl CrateMetadata {
17971848
trait_impls,
17981849
raw_proc_macros,
17991850
source_map_import_info: OnceCell::new(),
1851+
def_path_hash_map: Default::default(),
18001852
alloc_decoding_state,
18011853
dep_node_index: AtomicCell::new(DepNodeIndex::INVALID),
18021854
cnum,

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));

compiler/rustc_middle/src/dep_graph/dep_node.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,7 @@ 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+
tcx.queries.on_disk_cache.as_ref()?.def_path_hash_to_def_id(tcx, DefPathHash(self.hash.into()))
257256
} else {
258257
None
259258
}
@@ -320,7 +319,17 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId {
320319
}
321320

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

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

360369
fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
361370
let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX };
362-
tcx.def_path_hash(def_id).0
371+
def_id.to_fingerprint(tcx)
363372
}
364373

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

compiler/rustc_middle/src/dep_graph/mod.rs

+7-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,12 @@ 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+
if let Some(cache) = self.queries.on_disk_cache.as_ref() {
96+
cache.register_reused_dep_path_hash(hash)
97+
}
98+
}
99+
94100
fn create_stable_hashing_context(&self) -> Self::StableHashingContext {
95101
TyCtxt::create_stable_hashing_context(*self)
96102
}

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;

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)