1 use crate::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex};
2 use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState};
3 use crate::mir::{self, interpret};
4 use crate::ty::codec::{RefDecodable, TyDecoder, TyEncoder};
5 use crate::ty::context::TyCtxt;
6 use crate::ty::{self, Ty};
7 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
8 use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, OnceCell};
9 use rustc_data_structures::thin_vec::ThinVec;
10 use rustc_data_structures::unhash::UnhashMap;
11 use rustc_errors::Diagnostic;
12 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, StableCrateId, LOCAL_CRATE};
13 use rustc_hir::definitions::DefPathHash;
14 use rustc_index::vec::{Idx, IndexVec};
15 use rustc_query_system::dep_graph::DepContext;
16 use rustc_query_system::query::QueryContext;
17 use rustc_serialize::{
18 opaque::{self, FileEncodeResult, FileEncoder, IntEncodedWithFixedSize},
19 Decodable, Decoder, Encodable, Encoder,
21 use rustc_session::Session;
22 use rustc_span::hygiene::{
23 ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextData,
25 use rustc_span::source_map::{SourceMap, StableSourceFileId};
26 use rustc_span::CachingSourceMapView;
27 use rustc_span::{BytePos, ExpnData, ExpnHash, SourceFile, Span, DUMMY_SP};
28 use std::collections::hash_map::Entry;
31 const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE;
33 // A normal span encoded with both location information and a `SyntaxContext`
34 const TAG_FULL_SPAN: u8 = 0;
35 // A partial span with no location information, encoded only with a `SyntaxContext`
36 const TAG_PARTIAL_SPAN: u8 = 1;
38 const TAG_SYNTAX_CONTEXT: u8 = 0;
39 const TAG_EXPN_DATA: u8 = 1;
41 /// Provides an interface to incremental compilation data cached from the
42 /// previous compilation session. This data will eventually include the results
43 /// of a few selected queries (like `typeck` and `mir_optimized`) and
44 /// any diagnostics that have been emitted during a query.
45 pub struct OnDiskCache<'sess> {
46 // The complete cache data in serialized form.
47 serialized_data: Vec<u8>,
49 // Collects all `Diagnostic`s emitted during the current compilation
51 current_diagnostics: Lock<FxHashMap<DepNodeIndex, Vec<Diagnostic>>>,
53 cnum_map: OnceCell<UnhashMap<StableCrateId, CrateNum>>,
55 source_map: &'sess SourceMap,
56 file_index_to_stable_id: FxHashMap<SourceFileIndex, EncodedSourceFileId>,
58 // Caches that are populated lazily during decoding.
59 file_index_to_file: Lock<FxHashMap<SourceFileIndex, Lrc<SourceFile>>>,
61 // A map from dep-node to the position of the cached query result in
63 query_result_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
65 // A map from dep-node to the position of any associated diagnostics in
67 prev_diagnostics_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
69 alloc_decoding_state: AllocDecodingState,
71 // A map from syntax context ids to the position of their associated
72 // `SyntaxContextData`. We use a `u32` instead of a `SyntaxContext`
73 // to represent the fact that we are storing *encoded* ids. When we decode
74 // a `SyntaxContext`, a new id will be allocated from the global `HygieneData`,
75 // which will almost certainly be different than the serialized id.
76 syntax_contexts: FxHashMap<u32, AbsoluteBytePos>,
77 // A map from the `DefPathHash` of an `ExpnId` to the position
78 // of their associated `ExpnData`. Ideally, we would store a `DefId`,
79 // but we need to decode this before we've constructed a `TyCtxt` (which
80 // makes it difficult to decode a `DefId`).
82 // Note that these `DefPathHashes` correspond to both local and foreign
83 // `ExpnData` (e.g `ExpnData.krate` may not be `LOCAL_CRATE`). Alternatively,
84 // we could look up the `ExpnData` from the metadata of foreign crates,
85 // but it seemed easier to have `OnDiskCache` be independent of the `CStore`.
86 expn_data: UnhashMap<ExpnHash, AbsoluteBytePos>,
87 // Additional information used when decoding hygiene data.
88 hygiene_context: HygieneDecodeContext,
89 // Maps `DefPathHash`es to their `RawDefId`s from the *previous*
90 // compilation session. This is used as an initial 'guess' when
91 // we try to map a `DefPathHash` to its `DefId` in the current compilation
93 foreign_def_path_hashes: UnhashMap<DefPathHash, RawDefId>,
94 // Likewise for ExpnId.
95 foreign_expn_data: UnhashMap<ExpnHash, u32>,
97 // The *next* compilation sessison's `foreign_def_path_hashes` - at
98 // the end of our current compilation session, this will get written
99 // out to the `foreign_def_path_hashes` field of the `Footer`, which
100 // will become `foreign_def_path_hashes` of the next compilation session.
101 // This stores any `DefPathHash` that we may need to map to a `DefId`
102 // during the next compilation session.
103 latest_foreign_def_path_hashes: Lock<UnhashMap<DefPathHash, RawDefId>>,
105 // Caches all lookups of `DefPathHashes`, both for local and foreign
106 // definitions. A definition from the previous compilation session
107 // may no longer exist in the current compilation session, so
108 // we use `Option<DefId>` so that we can cache a lookup failure.
109 def_path_hash_to_def_id_cache: Lock<UnhashMap<DefPathHash, Option<DefId>>>,
112 // This type is used only for serialization and deserialization.
113 #[derive(Encodable, Decodable)]
115 file_index_to_stable_id: FxHashMap<SourceFileIndex, EncodedSourceFileId>,
116 query_result_index: EncodedQueryResultIndex,
117 diagnostics_index: EncodedQueryResultIndex,
118 // The location of all allocations.
119 interpret_alloc_index: Vec<u32>,
120 // See `OnDiskCache.syntax_contexts`
121 syntax_contexts: FxHashMap<u32, AbsoluteBytePos>,
122 // See `OnDiskCache.expn_data`
123 expn_data: UnhashMap<ExpnHash, AbsoluteBytePos>,
124 foreign_def_path_hashes: UnhashMap<DefPathHash, RawDefId>,
125 foreign_expn_data: UnhashMap<ExpnHash, u32>,
128 pub type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
129 type EncodedDiagnosticsIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
130 type EncodedDiagnostics = Vec<Diagnostic>;
132 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable, Decodable)]
133 struct SourceFileIndex(u32);
135 #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Encodable, Decodable)]
136 pub struct AbsoluteBytePos(u32);
138 impl AbsoluteBytePos {
139 fn new(pos: usize) -> AbsoluteBytePos {
140 debug_assert!(pos <= u32::MAX as usize);
141 AbsoluteBytePos(pos as u32)
144 fn to_usize(self) -> usize {
149 /// Represents a potentially invalid `DefId`. This is used during incremental
150 /// compilation to represent a `DefId` from the *previous* compilation session,
151 /// which may no longer be valid. This is used to help map a `DefPathHash`
152 /// to a `DefId` in the current compilation session.
153 #[derive(Encodable, Decodable, Copy, Clone, Debug)]
154 crate struct RawDefId {
155 // We deliberately do not use `CrateNum` and `DefIndex`
156 // here, since a crate/index from the previous compilation
157 // session may no longer exist.
162 /// An `EncodedSourceFileId` is the same as a `StableSourceFileId` except that
163 /// the source crate is represented as a [StableCrateId] instead of as a
164 /// `CrateNum`. This way `EncodedSourceFileId` can be encoded and decoded
165 /// without any additional context, i.e. with a simple `opaque::Decoder` (which
166 /// is the only thing available when decoding the cache's [Footer].
167 #[derive(Encodable, Decodable, Clone, Debug)]
168 struct EncodedSourceFileId {
170 stable_crate_id: StableCrateId,
173 impl EncodedSourceFileId {
174 fn translate(&self, cnum_map: &UnhashMap<StableCrateId, CrateNum>) -> StableSourceFileId {
175 let cnum = cnum_map[&self.stable_crate_id];
176 StableSourceFileId { file_name_hash: self.file_name_hash, cnum }
179 fn new(tcx: TyCtxt<'_>, file: &SourceFile) -> EncodedSourceFileId {
180 let source_file_id = StableSourceFileId::new(file);
181 EncodedSourceFileId {
182 file_name_hash: source_file_id.file_name_hash,
183 stable_crate_id: tcx.stable_crate_id(source_file_id.cnum),
188 impl<'sess> OnDiskCache<'sess> {
189 /// Creates a new `OnDiskCache` instance from the serialized data in `data`.
190 pub fn new(sess: &'sess Session, data: Vec<u8>, start_pos: usize) -> Self {
191 debug_assert!(sess.opts.incremental.is_some());
193 // Wrap in a scope so we can borrow `data`.
194 let footer: Footer = {
195 let mut decoder = opaque::Decoder::new(&data[..], start_pos);
197 // Decode the *position* of the footer, which can be found in the
198 // last 8 bytes of the file.
199 decoder.set_position(data.len() - IntEncodedWithFixedSize::ENCODED_SIZE);
200 let footer_pos = IntEncodedWithFixedSize::decode(&mut decoder)
201 .expect("error while trying to decode footer position")
204 // Decode the file footer, which contains all the lookup tables, etc.
205 decoder.set_position(footer_pos);
207 decode_tagged(&mut decoder, TAG_FILE_FOOTER)
208 .expect("error while trying to decode footer position")
212 serialized_data: data,
213 file_index_to_stable_id: footer.file_index_to_stable_id,
214 file_index_to_file: Default::default(),
215 cnum_map: OnceCell::new(),
216 source_map: sess.source_map(),
217 current_diagnostics: Default::default(),
218 query_result_index: footer.query_result_index.into_iter().collect(),
219 prev_diagnostics_index: footer.diagnostics_index.into_iter().collect(),
220 alloc_decoding_state: AllocDecodingState::new(footer.interpret_alloc_index),
221 syntax_contexts: footer.syntax_contexts,
222 expn_data: footer.expn_data,
223 foreign_expn_data: footer.foreign_expn_data,
224 hygiene_context: Default::default(),
225 foreign_def_path_hashes: footer.foreign_def_path_hashes,
226 latest_foreign_def_path_hashes: Default::default(),
227 def_path_hash_to_def_id_cache: Default::default(),
231 pub fn new_empty(source_map: &'sess SourceMap) -> Self {
233 serialized_data: Vec::new(),
234 file_index_to_stable_id: Default::default(),
235 file_index_to_file: Default::default(),
236 cnum_map: OnceCell::new(),
238 current_diagnostics: Default::default(),
239 query_result_index: Default::default(),
240 prev_diagnostics_index: Default::default(),
241 alloc_decoding_state: AllocDecodingState::new(Vec::new()),
242 syntax_contexts: FxHashMap::default(),
243 expn_data: UnhashMap::default(),
244 foreign_expn_data: UnhashMap::default(),
245 hygiene_context: Default::default(),
246 foreign_def_path_hashes: Default::default(),
247 latest_foreign_def_path_hashes: Default::default(),
248 def_path_hash_to_def_id_cache: Default::default(),
252 pub fn serialize<'tcx>(
255 encoder: &mut FileEncoder,
256 ) -> FileEncodeResult {
257 // Serializing the `DepGraph` should not modify it.
258 tcx.dep_graph.with_ignore(|| {
259 // Allocate `SourceFileIndex`es.
260 let (file_to_file_index, file_index_to_stable_id) = {
261 let files = tcx.sess.source_map().files();
262 let mut file_to_file_index =
263 FxHashMap::with_capacity_and_hasher(files.len(), Default::default());
264 let mut file_index_to_stable_id =
265 FxHashMap::with_capacity_and_hasher(files.len(), Default::default());
267 for (index, file) in files.iter().enumerate() {
268 let index = SourceFileIndex(index as u32);
269 let file_ptr: *const SourceFile = &**file as *const _;
270 file_to_file_index.insert(file_ptr, index);
271 let source_file_id = EncodedSourceFileId::new(tcx, &file);
272 file_index_to_stable_id.insert(index, source_file_id);
275 (file_to_file_index, file_index_to_stable_id)
278 // Register any dep nodes that we reused from the previous session,
279 // but didn't `DepNode::construct` in this session. This ensures
280 // that their `DefPathHash` to `RawDefId` mappings are registered
281 // in 'latest_foreign_def_path_hashes' if necessary, since that
282 // normally happens in `DepNode::construct`.
283 tcx.dep_graph.register_reused_dep_nodes(tcx);
285 // Load everything into memory so we can write it out to the on-disk
286 // cache. The vast majority of cacheable query results should already
287 // be in memory, so this should be a cheap operation.
288 // Do this *before* we clone 'latest_foreign_def_path_hashes', since
289 // loading existing queries may cause us to create new DepNodes, which
290 // may in turn end up invoking `store_foreign_def_id_hash`
291 tcx.queries.exec_cache_promotions(tcx);
293 let latest_foreign_def_path_hashes = self.latest_foreign_def_path_hashes.lock().clone();
294 let hygiene_encode_context = HygieneEncodeContext::default();
296 let mut encoder = CacheEncoder {
299 type_shorthands: Default::default(),
300 predicate_shorthands: Default::default(),
301 interpret_allocs: Default::default(),
302 source_map: CachingSourceMapView::new(tcx.sess.source_map()),
304 hygiene_context: &hygiene_encode_context,
305 latest_foreign_def_path_hashes,
308 // Encode query results.
309 let mut query_result_index = EncodedQueryResultIndex::new();
311 tcx.sess.time("encode_query_results", || -> FileEncodeResult {
312 let enc = &mut encoder;
313 let qri = &mut query_result_index;
314 tcx.queries.encode_query_results(tcx, enc, qri)
317 // Encode diagnostics.
318 let diagnostics_index: EncodedDiagnosticsIndex = self
323 |(dep_node_index, diagnostics)| -> Result<_, <FileEncoder as Encoder>::Error> {
324 let pos = AbsoluteBytePos::new(encoder.position());
325 // Let's make sure we get the expected type here.
326 let diagnostics: &EncodedDiagnostics = diagnostics;
327 let dep_node_index = SerializedDepNodeIndex::new(dep_node_index.index());
328 encoder.encode_tagged(dep_node_index, diagnostics)?;
330 Ok((dep_node_index, pos))
333 .collect::<Result<_, _>>()?;
335 let interpret_alloc_index = {
336 let mut interpret_alloc_index = Vec::new();
339 let new_n = encoder.interpret_allocs.len();
340 // If we have found new IDs, serialize those too.
345 interpret_alloc_index.reserve(new_n - n);
346 for idx in n..new_n {
347 let id = encoder.interpret_allocs[idx];
348 let pos = encoder.position() as u32;
349 interpret_alloc_index.push(pos);
350 interpret::specialized_encode_alloc_id(&mut encoder, tcx, id)?;
354 interpret_alloc_index
357 let mut syntax_contexts = FxHashMap::default();
358 let mut expn_data = UnhashMap::default();
359 let mut foreign_expn_data = UnhashMap::default();
361 // Encode all hygiene data (`SyntaxContextData` and `ExpnData`) from the current
364 hygiene_encode_context.encode(
366 |encoder, index, ctxt_data| -> FileEncodeResult {
367 let pos = AbsoluteBytePos::new(encoder.position());
368 encoder.encode_tagged(TAG_SYNTAX_CONTEXT, ctxt_data)?;
369 syntax_contexts.insert(index, pos);
372 |encoder, expn_id, data, hash| -> FileEncodeResult {
373 if expn_id.krate == LOCAL_CRATE {
374 let pos = AbsoluteBytePos::new(encoder.position());
375 encoder.encode_tagged(TAG_EXPN_DATA, &data)?;
376 expn_data.insert(hash, pos);
378 foreign_expn_data.insert(hash, expn_id.local_id.as_u32());
384 let foreign_def_path_hashes =
385 std::mem::take(&mut encoder.latest_foreign_def_path_hashes);
387 // `Encode the file footer.
388 let footer_pos = encoder.position() as u64;
389 encoder.encode_tagged(
392 file_index_to_stable_id,
395 interpret_alloc_index,
399 foreign_def_path_hashes,
403 // Encode the position of the footer as the last 8 bytes of the
404 // file so we know where to look for it.
405 IntEncodedWithFixedSize(footer_pos).encode(encoder.encoder)?;
407 // DO NOT WRITE ANYTHING TO THE ENCODER AFTER THIS POINT! The address
408 // of the footer must be the last thing in the data stream.
414 /// Loads a diagnostic emitted during the previous compilation session.
415 pub fn load_diagnostics(
418 dep_node_index: SerializedDepNodeIndex,
419 ) -> Vec<Diagnostic> {
420 let diagnostics: Option<EncodedDiagnostics> =
421 self.load_indexed(tcx, dep_node_index, &self.prev_diagnostics_index, "diagnostics");
423 diagnostics.unwrap_or_default()
426 /// Stores a diagnostic emitted during the current compilation session.
427 /// Anything stored like this will be available via `load_diagnostics` in
428 /// the next compilation session.
431 pub fn store_diagnostics(
433 dep_node_index: DepNodeIndex,
434 diagnostics: ThinVec<Diagnostic>,
436 let mut current_diagnostics = self.current_diagnostics.borrow_mut();
437 let prev = current_diagnostics.insert(dep_node_index, diagnostics.into());
438 debug_assert!(prev.is_none());
441 fn get_raw_def_id(&self, hash: &DefPathHash) -> Option<RawDefId> {
442 self.foreign_def_path_hashes.get(hash).copied()
445 fn try_remap_cnum(&self, tcx: TyCtxt<'_>, stable_crate_id: StableCrateId) -> Option<CrateNum> {
446 let cnum_map = self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx));
447 debug!("try_remap_cnum({:?}): cnum_map={:?}", stable_crate_id, cnum_map);
449 cnum_map.get(&stable_crate_id).copied()
452 pub(crate) fn store_foreign_def_id_hash(&self, def_id: DefId, hash: DefPathHash) {
453 // We may overwrite an existing entry, but it will have the same value,
455 self.latest_foreign_def_path_hashes
457 .insert(hash, RawDefId { krate: def_id.krate.as_u32(), index: def_id.index.as_u32() });
460 /// If the given `dep_node`'s hash still exists in the current compilation,
461 /// and its current `DefId` is foreign, calls `store_foreign_def_id` with it.
463 /// Normally, `store_foreign_def_id_hash` can be called directly by
464 /// the dependency graph when we construct a `DepNode`. However,
465 /// when we re-use a deserialized `DepNode` from the previous compilation
466 /// session, we only have the `DefPathHash` available. This method is used
467 /// to that any `DepNode` that we re-use has a `DefPathHash` -> `RawId` written
468 /// out for usage in the next compilation session.
469 pub fn register_reused_dep_node(&self, tcx: TyCtxt<'tcx>, dep_node: &DepNode) {
470 // For reused dep nodes, we only need to store the mapping if the node
471 // is one whose query key we can reconstruct from the hash. We use the
472 // mapping to aid that reconstruction in the next session. While we also
473 // use it to decode `DefId`s we encoded in the cache as `DefPathHashes`,
474 // they're already registered during `DefId` encoding.
475 if dep_node.kind.can_reconstruct_query_key() {
476 let hash = DefPathHash(dep_node.hash.into());
478 // We can't simply copy the `RawDefId` from `foreign_def_path_hashes` to
479 // `latest_foreign_def_path_hashes`, since the `RawDefId` might have
480 // changed in the current compilation session (e.g. we've added/removed crates,
481 // or added/removed definitions before/after the target definition).
482 if let Some(def_id) = self.def_path_hash_to_def_id(tcx, hash) {
483 if !def_id.is_local() {
484 self.store_foreign_def_id_hash(def_id, hash);
490 /// Returns the cached query result if there is something in the cache for
491 /// the given `SerializedDepNodeIndex`; otherwise returns `None`.
492 pub fn try_load_query_result<'tcx, T>(
495 dep_node_index: SerializedDepNodeIndex,
498 T: for<'a> Decodable<CacheDecoder<'a, 'tcx>>,
500 self.load_indexed(tcx, dep_node_index, &self.query_result_index, "query result")
503 /// Stores a diagnostic emitted during computation of an anonymous query.
504 /// Since many anonymous queries can share the same `DepNode`, we aggregate
505 /// them -- as opposed to regular queries where we assume that there is a
506 /// 1:1 relationship between query-key and `DepNode`.
509 pub fn store_diagnostics_for_anon_node(
511 dep_node_index: DepNodeIndex,
512 diagnostics: ThinVec<Diagnostic>,
514 let mut current_diagnostics = self.current_diagnostics.borrow_mut();
516 let x = current_diagnostics.entry(dep_node_index).or_default();
518 x.extend(Into::<Vec<_>>::into(diagnostics));
521 fn load_indexed<'tcx, T>(
524 dep_node_index: SerializedDepNodeIndex,
525 index: &FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
526 debug_tag: &'static str,
529 T: for<'a> Decodable<CacheDecoder<'a, 'tcx>>,
531 let pos = index.get(&dep_node_index).cloned()?;
533 self.with_decoder(tcx, pos, |decoder| match decode_tagged(decoder, dep_node_index) {
535 Err(e) => bug!("could not decode cached {}: {}", debug_tag, e),
539 fn with_decoder<'a, 'tcx, T, F: FnOnce(&mut CacheDecoder<'sess, 'tcx>) -> T>(
542 pos: AbsoluteBytePos,
546 T: Decodable<CacheDecoder<'a, 'tcx>>,
548 let cnum_map = self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx));
550 let mut decoder = CacheDecoder {
552 opaque: opaque::Decoder::new(&self.serialized_data[..], pos.to_usize()),
553 source_map: self.source_map,
555 file_index_to_file: &self.file_index_to_file,
556 file_index_to_stable_id: &self.file_index_to_stable_id,
557 alloc_decoding_session: self.alloc_decoding_state.new_decoding_session(),
558 syntax_contexts: &self.syntax_contexts,
559 expn_data: &self.expn_data,
560 foreign_expn_data: &self.foreign_expn_data,
561 hygiene_context: &self.hygiene_context,
566 // This function builds mapping from previous-session-`CrateNum` to
567 // current-session-`CrateNum`. There might be `CrateNum`s from the previous
568 // `Session` that don't occur in the current one. For these, the mapping
570 fn compute_cnum_map(tcx: TyCtxt<'_>) -> UnhashMap<StableCrateId, CrateNum> {
571 tcx.dep_graph.with_ignore(|| {
574 .chain(std::iter::once(&LOCAL_CRATE))
576 let hash = tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
583 /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation
584 /// session, if it still exists. This is used during incremental compilation to
585 /// turn a deserialized `DefPathHash` into its current `DefId`.
586 pub(crate) fn def_path_hash_to_def_id(
591 let mut cache = self.def_path_hash_to_def_id_cache.lock();
592 match cache.entry(hash) {
593 Entry::Occupied(e) => *e.get(),
594 Entry::Vacant(e) => {
595 debug!("def_path_hash_to_def_id({:?})", hash);
596 // Check if the `DefPathHash` corresponds to a definition in the current
598 if let Some(def_id) =
599 tcx.untracked_resolutions.definitions.local_def_path_hash_to_def_id(hash)
601 let def_id = def_id.to_def_id();
602 e.insert(Some(def_id));
605 // This `raw_def_id` represents the `DefId` of this `DefPathHash` in
606 // the *previous* compliation session. The `DefPathHash` includes the
607 // owning crate, so if the corresponding definition still exists in the
608 // current compilation session, the crate is guaranteed to be the same
609 // (otherwise, we would compute a different `DefPathHash`).
610 let raw_def_id = self.get_raw_def_id(&hash)?;
611 debug!("def_path_hash_to_def_id({:?}): raw_def_id = {:?}", hash, raw_def_id);
612 // If the owning crate no longer exists, the corresponding definition definitely
614 let krate = self.try_remap_cnum(tcx, hash.stable_crate_id())?;
615 debug!("def_path_hash_to_def_id({:?}): krate = {:?}", hash, krate);
616 // If our `DefPathHash` corresponded to a definition in the local crate,
617 // we should have either found it in `local_def_path_hash_to_def_id`, or
618 // never attempted to load it in the first place. Any query result or `DepNode`
619 // that references a local `DefId` should depend on some HIR-related `DepNode`.
620 // If a local definition is removed/modified such that its old `DefPathHash`
621 // no longer has a corresponding definition, that HIR-related `DepNode` should
622 // end up red. This should prevent us from ever calling
623 // `tcx.def_path_hash_to_def_id`, since we'll end up recomputing any
625 debug_assert_ne!(krate, LOCAL_CRATE);
626 // Try to find a definition in the current session, using the previous `DefIndex`
627 // as an initial guess.
628 let opt_def_id = tcx.untracked_resolutions.cstore.def_path_hash_to_def_id(
633 debug!("def_path_to_def_id({:?}): opt_def_id = {:?}", hash, opt_def_id);
634 e.insert(opt_def_id);
641 //- DECODING -------------------------------------------------------------------
643 /// A decoder that can read from the incremental compilation cache. It is similar to the one
644 /// we use for crate metadata decoding in that it can rebase spans and eventually
645 /// will also handle things that contain `Ty` instances.
646 pub struct CacheDecoder<'a, 'tcx> {
648 opaque: opaque::Decoder<'a>,
649 source_map: &'a SourceMap,
650 cnum_map: &'a UnhashMap<StableCrateId, CrateNum>,
651 file_index_to_file: &'a Lock<FxHashMap<SourceFileIndex, Lrc<SourceFile>>>,
652 file_index_to_stable_id: &'a FxHashMap<SourceFileIndex, EncodedSourceFileId>,
653 alloc_decoding_session: AllocDecodingSession<'a>,
654 syntax_contexts: &'a FxHashMap<u32, AbsoluteBytePos>,
655 expn_data: &'a UnhashMap<ExpnHash, AbsoluteBytePos>,
656 foreign_expn_data: &'a UnhashMap<ExpnHash, u32>,
657 hygiene_context: &'a HygieneDecodeContext,
660 impl<'a, 'tcx> CacheDecoder<'a, 'tcx> {
661 fn file_index_to_file(&self, index: SourceFileIndex) -> Lrc<SourceFile> {
663 ref file_index_to_file,
664 ref file_index_to_stable_id,
674 let stable_id = file_index_to_stable_id[&index].translate(cnum_map);
676 .source_file_by_stable_id(stable_id)
677 .expect("failed to lookup `SourceFile` in new context")
683 trait DecoderWithPosition: Decoder {
684 fn position(&self) -> usize;
687 impl<'a> DecoderWithPosition for opaque::Decoder<'a> {
688 fn position(&self) -> usize {
693 impl<'a, 'tcx> DecoderWithPosition for CacheDecoder<'a, 'tcx> {
694 fn position(&self) -> usize {
695 self.opaque.position()
699 // Decodes something that was encoded with `encode_tagged()` and verify that the
700 // tag matches and the correct amount of bytes was read.
701 fn decode_tagged<D, T, V>(decoder: &mut D, expected_tag: T) -> Result<V, D::Error>
703 T: Decodable<D> + Eq + std::fmt::Debug,
705 D: DecoderWithPosition,
707 let start_pos = decoder.position();
709 let actual_tag = T::decode(decoder)?;
710 assert_eq!(actual_tag, expected_tag);
711 let value = V::decode(decoder)?;
712 let end_pos = decoder.position();
714 let expected_len: u64 = Decodable::decode(decoder)?;
715 assert_eq!((end_pos - start_pos) as u64, expected_len);
720 impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> {
721 const CLEAR_CROSS_CRATE: bool = false;
724 fn tcx(&self) -> TyCtxt<'tcx> {
729 fn position(&self) -> usize {
730 self.opaque.position()
734 fn peek_byte(&self) -> u8 {
735 self.opaque.data[self.opaque.position()]
738 fn cached_ty_for_shorthand<F>(
742 ) -> Result<Ty<'tcx>, Self::Error>
744 F: FnOnce(&mut Self) -> Result<Ty<'tcx>, Self::Error>,
746 let tcx = self.tcx();
748 let cache_key = ty::CReaderCacheKey { cnum: None, pos: shorthand };
750 if let Some(&ty) = tcx.ty_rcache.borrow().get(&cache_key) {
754 let ty = or_insert_with(self)?;
755 // This may overwrite the entry, but it should overwrite with the same value.
756 tcx.ty_rcache.borrow_mut().insert_same(cache_key, ty);
760 fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
762 F: FnOnce(&mut Self) -> R,
764 debug_assert!(pos < self.opaque.data.len());
766 let new_opaque = opaque::Decoder::new(self.opaque.data, pos);
767 let old_opaque = mem::replace(&mut self.opaque, new_opaque);
769 self.opaque = old_opaque;
773 fn decode_alloc_id(&mut self) -> Result<interpret::AllocId, Self::Error> {
774 let alloc_decoding_session = self.alloc_decoding_session;
775 alloc_decoding_session.decode_alloc_id(self)
779 crate::implement_ty_decoder!(CacheDecoder<'a, 'tcx>);
781 // This ensures that the `Decodable<opaque::Decoder>::decode` specialization for `Vec<u8>` is used
782 // when a `CacheDecoder` is passed to `Decodable::decode`. Unfortunately, we have to manually opt
783 // into specializations this way, given how `CacheDecoder` and the decoding traits currently work.
784 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Vec<u8> {
785 fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
786 Decodable::decode(&mut d.opaque)
790 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for SyntaxContext {
791 fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
792 let syntax_contexts = decoder.syntax_contexts;
793 rustc_span::hygiene::decode_syntax_context(decoder, decoder.hygiene_context, |this, id| {
794 // This closure is invoked if we haven't already decoded the data for the `SyntaxContext` we are deserializing.
795 // We look up the position of the associated `SyntaxData` and decode it.
796 let pos = syntax_contexts.get(&id).unwrap();
797 this.with_position(pos.to_usize(), |decoder| {
798 let data: SyntaxContextData = decode_tagged(decoder, TAG_SYNTAX_CONTEXT)?;
805 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId {
806 fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
807 let hash = ExpnHash::decode(decoder)?;
809 return Ok(ExpnId::root());
812 if let Some(expn_id) = ExpnId::from_hash(hash) {
816 let krate = decoder.cnum_map[&hash.stable_crate_id()];
818 let expn_id = if krate == LOCAL_CRATE {
819 // We look up the position of the associated `ExpnData` and decode it.
823 .unwrap_or_else(|| panic!("Bad hash {:?} (map {:?})", hash, decoder.expn_data));
825 let data: ExpnData = decoder
826 .with_position(pos.to_usize(), |decoder| decode_tagged(decoder, TAG_EXPN_DATA))?;
827 rustc_span::hygiene::register_local_expn_id(data, hash)
829 let index_guess = decoder.foreign_expn_data[&hash];
830 decoder.tcx.untracked_resolutions.cstore.expn_hash_to_expn_id(krate, index_guess, hash)
833 #[cfg(debug_assertions)]
835 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
836 let mut hcx = decoder.tcx.create_stable_hashing_context();
837 let mut hasher = StableHasher::new();
838 hcx.while_hashing_spans(true, |hcx| expn_id.expn_data().hash_stable(hcx, &mut hasher));
839 let local_hash: u64 = hasher.finish();
840 debug_assert_eq!(hash.local_hash(), local_hash);
847 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span {
848 fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
849 let tag: u8 = Decodable::decode(decoder)?;
851 if tag == TAG_PARTIAL_SPAN {
852 let ctxt = SyntaxContext::decode(decoder)?;
853 return Ok(DUMMY_SP.with_ctxt(ctxt));
855 debug_assert_eq!(tag, TAG_FULL_SPAN);
858 let file_lo_index = SourceFileIndex::decode(decoder)?;
859 let line_lo = usize::decode(decoder)?;
860 let col_lo = BytePos::decode(decoder)?;
861 let len = BytePos::decode(decoder)?;
862 let ctxt = SyntaxContext::decode(decoder)?;
864 let file_lo = decoder.file_index_to_file(file_lo_index);
865 let lo = file_lo.lines[line_lo - 1] + col_lo;
868 Ok(Span::new(lo, hi, ctxt))
872 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for CrateNum {
873 fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
874 let stable_id = StableCrateId::decode(d)?;
875 let cnum = d.cnum_map[&stable_id];
880 // This impl makes sure that we get a runtime error when we try decode a
881 // `DefIndex` that is not contained in a `DefId`. Such a case would be problematic
882 // because we would not know how to transform the `DefIndex` to the current
884 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefIndex {
885 fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<DefIndex, String> {
886 Err(d.error("trying to decode `DefIndex` outside the context of a `DefId`"))
890 // Both the `CrateNum` and the `DefIndex` of a `DefId` can change in between two
891 // compilation sessions. We use the `DefPathHash`, which is stable across
892 // sessions, to map the old `DefId` to the new one.
893 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefId {
894 fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
895 // Load the `DefPathHash` which is was we encoded the `DefId` as.
896 let def_path_hash = DefPathHash::decode(d)?;
898 // Using the `DefPathHash`, we can lookup the new `DefId`.
899 // Subtle: We only encode a `DefId` as part of a query result.
900 // If we get to this point, then all of the query inputs were green,
901 // which means that the definition with this hash is guaranteed to
902 // still exist in the current compilation session.
907 .def_path_hash_to_def_id(d.tcx(), def_path_hash)
912 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx FxHashSet<LocalDefId> {
913 fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
914 RefDecodable::decode(d)
918 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
919 for &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>>
921 fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
922 RefDecodable::decode(d)
926 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
927 fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
928 RefDecodable::decode(d)
932 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
933 fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
934 RefDecodable::decode(d)
938 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [rustc_ast::InlineAsmTemplatePiece] {
939 fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
940 RefDecodable::decode(d)
944 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [Span] {
945 fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
946 RefDecodable::decode(d)
950 //- ENCODING -------------------------------------------------------------------
952 pub trait OpaqueEncoder: Encoder {
953 fn position(&self) -> usize;
956 impl OpaqueEncoder for FileEncoder {
958 fn position(&self) -> usize {
959 FileEncoder::position(self)
963 /// An encoder that can write to the incremental compilation cache.
964 pub struct CacheEncoder<'a, 'tcx, E: OpaqueEncoder> {
967 type_shorthands: FxHashMap<Ty<'tcx>, usize>,
968 predicate_shorthands: FxHashMap<ty::PredicateKind<'tcx>, usize>,
969 interpret_allocs: FxIndexSet<interpret::AllocId>,
970 source_map: CachingSourceMapView<'tcx>,
971 file_to_file_index: FxHashMap<*const SourceFile, SourceFileIndex>,
972 hygiene_context: &'a HygieneEncodeContext,
973 latest_foreign_def_path_hashes: UnhashMap<DefPathHash, RawDefId>,
976 impl<'a, 'tcx, E> CacheEncoder<'a, 'tcx, E>
978 E: 'a + OpaqueEncoder,
980 fn source_file_index(&mut self, source_file: Lrc<SourceFile>) -> SourceFileIndex {
981 self.file_to_file_index[&(&*source_file as *const SourceFile)]
984 /// Encode something with additional information that allows to do some
985 /// sanity checks when decoding the data again. This method will first
986 /// encode the specified tag, then the given value, then the number of
987 /// bytes taken up by tag and value. On decoding, we can then verify that
988 /// we get the expected tag and read the expected number of bytes.
989 fn encode_tagged<T: Encodable<Self>, V: Encodable<Self>>(
993 ) -> Result<(), E::Error> {
994 let start_pos = self.position();
999 let end_pos = self.position();
1000 ((end_pos - start_pos) as u64).encode(self)
1004 impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for SyntaxContext
1006 E: 'a + OpaqueEncoder,
1008 fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
1009 rustc_span::hygiene::raw_encode_syntax_context(*self, s.hygiene_context, s)
1013 impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for ExpnId
1015 E: 'a + OpaqueEncoder,
1017 fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
1018 s.hygiene_context.schedule_expn_data_for_encoding(*self);
1019 self.expn_hash().encode(s)
1023 impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for Span
1025 E: 'a + OpaqueEncoder,
1027 fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
1028 let span_data = self.data();
1029 if self.is_dummy() {
1030 TAG_PARTIAL_SPAN.encode(s)?;
1031 return span_data.ctxt.encode(s);
1034 let pos = s.source_map.byte_pos_to_line_and_col(span_data.lo);
1035 let partial_span = match &pos {
1036 Some((file_lo, _, _)) => !file_lo.contains(span_data.hi),
1041 TAG_PARTIAL_SPAN.encode(s)?;
1042 return span_data.ctxt.encode(s);
1045 let (file_lo, line_lo, col_lo) = pos.unwrap();
1047 let len = span_data.hi - span_data.lo;
1049 let source_file_index = s.source_file_index(file_lo);
1051 TAG_FULL_SPAN.encode(s)?;
1052 source_file_index.encode(s)?;
1056 span_data.ctxt.encode(s)
1060 impl<'a, 'tcx, E> TyEncoder<'tcx> for CacheEncoder<'a, 'tcx, E>
1062 E: 'a + OpaqueEncoder,
1064 const CLEAR_CROSS_CRATE: bool = false;
1066 fn position(&self) -> usize {
1067 self.encoder.position()
1069 fn type_shorthands(&mut self) -> &mut FxHashMap<Ty<'tcx>, usize> {
1070 &mut self.type_shorthands
1072 fn predicate_shorthands(&mut self) -> &mut FxHashMap<ty::PredicateKind<'tcx>, usize> {
1073 &mut self.predicate_shorthands
1075 fn encode_alloc_id(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> {
1076 let (index, _) = self.interpret_allocs.insert_full(*alloc_id);
1082 impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for CrateNum
1084 E: 'a + OpaqueEncoder,
1086 fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
1087 s.tcx.stable_crate_id(*self).encode(s)
1091 impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for DefId
1093 E: 'a + OpaqueEncoder,
1095 fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
1096 let def_path_hash = s.tcx.def_path_hash(*self);
1097 // Store additional information when we encode a foreign `DefId`,
1098 // so that we can map its `DefPathHash` back to a `DefId` in the next
1099 // compilation session.
1100 if !self.is_local() {
1101 s.latest_foreign_def_path_hashes.insert(
1103 RawDefId { krate: self.krate.as_u32(), index: self.index.as_u32() },
1106 def_path_hash.encode(s)
1110 impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for DefIndex
1112 E: 'a + OpaqueEncoder,
1114 fn encode(&self, _: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
1115 bug!("encoding `DefIndex` without context");
1119 macro_rules! encoder_methods {
1120 ($($name:ident($ty:ty);)*) => {
1122 $(fn $name(&mut self, value: $ty) -> Result<(), Self::Error> {
1123 self.encoder.$name(value)
1128 impl<'a, 'tcx, E> Encoder for CacheEncoder<'a, 'tcx, E>
1130 E: 'a + OpaqueEncoder,
1132 type Error = E::Error;
1135 fn emit_unit(&mut self) -> Result<(), Self::Error> {
1159 emit_raw_bytes(&[u8]);
1163 // This ensures that the `Encodable<opaque::FileEncoder>::encode` specialization for byte slices
1164 // is used when a `CacheEncoder` having an `opaque::FileEncoder` is passed to `Encodable::encode`.
1165 // Unfortunately, we have to manually opt into specializations this way, given how `CacheEncoder`
1166 // and the encoding traits currently work.
1167 impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx, FileEncoder>> for [u8] {
1168 fn encode(&self, e: &mut CacheEncoder<'a, 'tcx, FileEncoder>) -> FileEncodeResult {
1169 self.encode(e.encoder)
1173 pub fn encode_query_results<'a, 'tcx, CTX, Q>(
1175 encoder: &mut CacheEncoder<'a, 'tcx, FileEncoder>,
1176 query_result_index: &mut EncodedQueryResultIndex,
1177 ) -> FileEncodeResult
1179 CTX: QueryContext + 'tcx,
1180 Q: super::QueryDescription<CTX> + super::QueryAccessors<CTX>,
1181 Q::Value: Encodable<CacheEncoder<'a, 'tcx, FileEncoder>>,
1186 .extra_verbose_generic_activity("encode_query_results_for", std::any::type_name::<Q>());
1188 assert!(Q::query_state(tcx).all_inactive());
1189 let cache = Q::query_cache(tcx);
1190 let mut res = Ok(());
1191 cache.iter_results(&mut |key, value, dep_node| {
1195 if Q::cache_on_disk(tcx, &key, Some(value)) {
1196 let dep_node = SerializedDepNodeIndex::new(dep_node.index());
1198 // Record position of the cache entry.
1199 query_result_index.push((dep_node, AbsoluteBytePos::new(encoder.encoder.position())));
1201 // Encode the type check tables with the `SerializedDepNodeIndex`
1203 match encoder.encode_tagged(dep_node, value) {