Skip to content

Commit

Permalink
Auto merge of rust-lang#74967 - Aaron1011:feature/incr-def-path-table…
Browse files Browse the repository at this point in the history
…, r=pnkfelix

Implement lazy decoding of DefPathTable during incremental compilation

PR rust-lang#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).
  • Loading branch information
bors committed Dec 1, 2020
2 parents b2dd829 + 7a9aa4f commit 4cbda82
Show file tree
Hide file tree
Showing 11 changed files with 289 additions and 40 deletions.
8 changes: 6 additions & 2 deletions compiler/rustc_incremental/src/persist/load.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Code to save/load the dep-graph from files.

use rustc_data_structures::fx::FxHashMap;
use rustc_hir::definitions::Definitions;
use rustc_middle::dep_graph::{PreviousDepGraph, SerializedDepGraph, WorkProduct, WorkProductId};
use rustc_middle::ty::query::OnDiskCache;
use rustc_middle::ty::TyCtxt;
Expand Down Expand Up @@ -204,7 +205,10 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
/// If we are not in incremental compilation mode, returns `None`.
/// Otherwise, tries to load the query result cache from disk,
/// creating an empty cache if it could not be loaded.
pub fn load_query_result_cache(sess: &Session) -> Option<OnDiskCache<'_>> {
pub fn load_query_result_cache<'a>(
sess: &'a Session,
definitions: &Definitions,
) -> Option<OnDiskCache<'a>> {
if sess.opts.incremental.is_none() {
return None;
}
Expand All @@ -217,7 +221,7 @@ pub fn load_query_result_cache(sess: &Session) -> Option<OnDiskCache<'_>> {
sess.is_nightly_build(),
) {
LoadResult::Ok { data: (bytes, start_pos) } => {
Some(OnDiskCache::new(sess, bytes, start_pos))
Some(OnDiskCache::new(sess, bytes, start_pos, definitions))
}
_ => Some(OnDiskCache::new_empty(sess.source_map())),
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,7 @@ pub fn create_global_ctxt<'tcx>(
Definitions::new(crate_name, sess.local_crate_disambiguator()),
));

let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess);
let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess, defs);

let codegen_backend = compiler.codegen_backend();
let mut local_providers = *DEFAULT_QUERY_PROVIDERS;
Expand Down
52 changes: 52 additions & 0 deletions compiler/rustc_metadata/src/rmeta/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ crate struct CrateMetadata {
raw_proc_macros: Option<&'static [ProcMacro]>,
/// Source maps for code from the crate.
source_map_import_info: OnceCell<Vec<ImportedSourceFile>>,
/// For every definition in this crate, maps its `DefPathHash` to its
/// `DefIndex`. See `raw_def_id_to_def_id` for more details about how
/// this is used.
def_path_hash_map: OnceCell<FxHashMap<DefPathHash, DefIndex>>,
/// Used for decoding interpret::AllocIds in a cached & thread-safe manner.
alloc_decoding_state: AllocDecodingState,
/// The `DepNodeIndex` of the `DepNode` representing this upstream crate.
Expand Down Expand Up @@ -1519,6 +1523,53 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
.or_insert_with(|| self.root.tables.def_keys.get(self, index).unwrap().decode(self))
}

/// Finds the corresponding `DefId` for the provided `DefPathHash`, if it exists.
/// This is used by incremental compilation to map a serialized `DefPathHash` to
/// its `DefId` in the current session.
/// Normally, only one 'main' crate will change between incremental compilation sessions:
/// all dependencies will be completely unchanged. In this case, we can avoid
/// decoding every `DefPathHash` in the crate, since the `DefIndex` from the previous
/// session will still be valid. If our 'guess' is wrong (the `DefIndex` no longer exists,
/// or has a different `DefPathHash`, then we need to decode all `DefPathHashes` to determine
/// the correct mapping).
fn def_path_hash_to_def_id(
&self,
krate: CrateNum,
index_guess: u32,
hash: DefPathHash,
) -> Option<DefId> {
let def_index_guess = DefIndex::from_u32(index_guess);
let old_hash = self
.root
.tables
.def_path_hashes
.get(self, def_index_guess)
.map(|lazy| lazy.decode(self));

// Fast path: the definition and its index is unchanged from the
// previous compilation session. There is no need to decode anything
// else
if old_hash == Some(hash) {
return Some(DefId { krate, index: def_index_guess });
}

// Slow path: We need to find out the new `DefIndex` of the provided
// `DefPathHash`, if its still exists. This requires decoding every `DefPathHash`
// stored in this crate.
let map = self.cdata.def_path_hash_map.get_or_init(|| {
let end_id = self.root.tables.def_path_hashes.size() as u32;
let mut map = FxHashMap::with_capacity_and_hasher(end_id as usize, Default::default());
for i in 0..end_id {
let def_index = DefIndex::from_u32(i);
let hash =
self.root.tables.def_path_hashes.get(self, def_index).unwrap().decode(self);
map.insert(hash, def_index);
}
map
});
map.get(&hash).map(|index| DefId { krate, index: *index })
}

// Returns the path leading to the thing with this `id`.
fn def_path(&self, id: DefIndex) -> DefPath {
debug!("def_path(cnum={:?}, id={:?})", self.cnum, id);
Expand Down Expand Up @@ -1797,6 +1848,7 @@ impl CrateMetadata {
trait_impls,
raw_proc_macros,
source_map_import_info: OnceCell::new(),
def_path_hash_map: Default::default(),
alloc_decoding_state,
dep_node_index: AtomicCell::new(DepNodeIndex::INVALID),
cnum,
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,16 @@ impl CrateStore for CStore {
self.get_crate_data(cnum).num_def_ids()
}

// See `CrateMetadataRef::def_path_hash_to_def_id` for more details
fn def_path_hash_to_def_id(
&self,
cnum: CrateNum,
index_guess: u32,
hash: DefPathHash,
) -> Option<DefId> {
self.get_crate_data(cnum).def_path_hash_to_def_id(cnum, index_guess, hash)
}

fn crates_untracked(&self) -> Vec<CrateNum> {
let mut result = vec![];
self.iter_crate_data(|cnum, _| result.push(cnum));
Expand Down
17 changes: 13 additions & 4 deletions compiler/rustc_middle/src/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,7 @@ macro_rules! define_dep_nodes {
/// has been removed.
fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> {
if self.kind.can_reconstruct_query_key() {
let def_path_hash = DefPathHash(self.hash.into());
tcx.def_path_hash_to_def_id.as_ref()?.get(&def_path_hash).cloned()
tcx.queries.on_disk_cache.as_ref()?.def_path_hash_to_def_id(tcx, DefPathHash(self.hash.into()))
} else {
None
}
Expand Down Expand Up @@ -320,7 +319,17 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId {
}

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

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

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

fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
Expand Down
8 changes: 7 additions & 1 deletion compiler/rustc_middle/src/dep_graph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use rustc_data_structures::profiling::SelfProfilerRef;
use rustc_data_structures::sync::Lock;
use rustc_data_structures::thin_vec::ThinVec;
use rustc_errors::Diagnostic;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::def_id::{DefPathHash, LocalDefId};

mod dep_node;

Expand Down Expand Up @@ -91,6 +91,12 @@ impl<'tcx> DepContext for TyCtxt<'tcx> {
type DepKind = DepKind;
type StableHashingContext = StableHashingContext<'tcx>;

fn register_reused_dep_path_hash(&self, hash: DefPathHash) {
if let Some(cache) = self.queries.on_disk_cache.as_ref() {
cache.register_reused_dep_path_hash(hash)
}
}

fn create_stable_hashing_context(&self) -> Self::StableHashingContext {
TyCtxt::create_stable_hashing_context(*self)
}
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_middle/src/middle/cstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,12 @@ pub trait CrateStore {
fn def_path_hash(&self, def: DefId) -> DefPathHash;
fn all_def_path_hashes_and_def_ids(&self, cnum: CrateNum) -> Vec<(DefPathHash, DefId)>;
fn num_def_ids(&self, cnum: CrateNum) -> usize;
fn def_path_hash_to_def_id(
&self,
cnum: CrateNum,
index_guess: u32,
hash: DefPathHash,
) -> Option<DefId>;

// "queries" used in resolve that aren't tracked for incremental compilation
fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol;
Expand Down
31 changes: 6 additions & 25 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Type context book-keeping.

use crate::arena::Arena;
use crate::dep_graph::{self, DepConstructor, DepGraph};
use crate::dep_graph::{self, DepGraph, DepKind, DepNode, DepNodeExt};
use crate::hir::exports::ExportMap;
use crate::ich::{NodeIdHashingMode, StableHashingContext};
use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
Expand Down Expand Up @@ -34,12 +34,12 @@ use rustc_data_structures::stable_hasher::{
};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal};
use rustc_data_structures::unhash::UnhashMap;
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
use rustc_hir::definitions::{DefPathHash, Definitions};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId};
use rustc_hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::definitions::Definitions;
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{
Expand Down Expand Up @@ -945,10 +945,6 @@ pub struct GlobalCtxt<'tcx> {
pub(crate) untracked_crate: &'tcx hir::Crate<'tcx>,
pub(crate) definitions: &'tcx Definitions,

/// A map from `DefPathHash` -> `DefId`. Includes `DefId`s from the local crate
/// as well as all upstream crates. Only populated in incremental mode.
pub def_path_hash_to_def_id: Option<UnhashMap<DefPathHash, DefId>>,

pub queries: query::Queries<'tcx>,

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

let def_path_hash_to_def_id = if s.opts.build_dep_graph() {
let capacity = definitions.def_path_table().num_def_ids()
+ crates.iter().map(|cnum| cstore.num_def_ids(*cnum)).sum::<usize>();
let mut map = UnhashMap::with_capacity_and_hasher(capacity, Default::default());

map.extend(definitions.def_path_table().all_def_path_hashes_and_def_ids(LOCAL_CRATE));
for cnum in &crates {
map.extend(cstore.all_def_path_hashes_and_def_ids(*cnum).into_iter());
}

Some(map)
} else {
None
};

let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default();
for (hir_id, v) in krate.trait_map.iter() {
let map = trait_map.entry(hir_id.owner).or_default();
Expand Down Expand Up @@ -1155,7 +1136,6 @@ impl<'tcx> TyCtxt<'tcx> {
extern_prelude: resolutions.extern_prelude,
untracked_crate: krate,
definitions,
def_path_hash_to_def_id,
queries: query::Queries::new(providers, extern_providers, on_disk_query_result_cache),
ty_rcache: Default::default(),
pred_rcache: Default::default(),
Expand Down Expand Up @@ -1329,7 +1309,8 @@ impl<'tcx> TyCtxt<'tcx> {
// We cannot use the query versions of crates() and crate_hash(), since
// those would need the DepNodes that we are allocating here.
for cnum in self.cstore.crates_untracked() {
let dep_node = DepConstructor::CrateMetadata(self, cnum);
let def_path_hash = self.def_path_hash(DefId { krate: cnum, index: CRATE_DEF_INDEX });
let dep_node = DepNode::from_def_path_hash(def_path_hash, DepKind::CrateMetadata);
let crate_hash = self.cstore.crate_hash_untracked(cnum);
self.dep_graph.with_task(
dep_node,
Expand Down
Loading

0 comments on commit 4cbda82

Please sign in to comment.