]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_middle/src/ty/query/on_disk_cache.rs
New upstream version 1.53.0+dfsg1
[rustc.git] / compiler / rustc_middle / src / ty / query / on_disk_cache.rs
CommitLineData
fc512014 1use crate::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex};
9fa01778 2use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState};
3dfed10e 3use crate::mir::{self, interpret};
5869c6ff 4use crate::ty::codec::{RefDecodable, TyDecoder, TyEncoder};
9fa01778 5use crate::ty::context::TyCtxt;
dfeec247 6use crate::ty::{self, Ty};
3dfed10e 7use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
f9f354fc 8use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, OnceCell};
0731742a 9use rustc_data_structures::thin_vec::ThinVec;
5869c6ff 10use rustc_data_structures::unhash::UnhashMap;
dfeec247 11use rustc_errors::Diagnostic;
dfeec247 12use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE};
ba9703b0 13use rustc_hir::definitions::DefPathHash;
fc512014 14use rustc_hir::definitions::Definitions;
dfeec247 15use rustc_index::vec::{Idx, IndexVec};
6a06907d
XL
16use rustc_query_system::dep_graph::DepContext;
17use rustc_query_system::query::QueryContext;
5869c6ff 18use rustc_serialize::{
cdc7bbd5 19 opaque::{self, FileEncodeResult, FileEncoder, IntEncodedWithFixedSize},
5869c6ff
XL
20 Decodable, Decoder, Encodable, Encoder,
21};
ba9703b0 22use rustc_session::{CrateDisambiguator, Session};
3dfed10e
XL
23use rustc_span::hygiene::{
24 ExpnDataDecodeMode, ExpnDataEncodeMode, ExpnId, HygieneDecodeContext, HygieneEncodeContext,
25 SyntaxContext, SyntaxContextData,
26};
dfeec247 27use rustc_span::source_map::{SourceMap, StableSourceFileId};
ba9703b0 28use rustc_span::CachingSourceMapView;
3dfed10e 29use rustc_span::{BytePos, ExpnData, SourceFile, Span, DUMMY_SP};
fc512014
XL
30use std::collections::hash_map::Entry;
31use std::iter::FromIterator;
abe05a73 32use std::mem;
abe05a73 33
ff7c6d11
XL
34const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE;
35
5869c6ff
XL
36// A normal span encoded with both location information and a `SyntaxContext`
37const TAG_FULL_SPAN: u8 = 0;
38// A partial span with no location information, encoded only with a `SyntaxContext`
39const TAG_PARTIAL_SPAN: u8 = 1;
abe05a73 40
3dfed10e
XL
41const TAG_SYNTAX_CONTEXT: u8 = 0;
42const TAG_EXPN_DATA: u8 = 1;
43
e1599b0c 44/// Provides an interface to incremental compilation data cached from the
abe05a73 45/// previous compilation session. This data will eventually include the results
3dfed10e 46/// of a few selected queries (like `typeck` and `mir_optimized`) and
abe05a73
XL
47/// any diagnostics that have been emitted during a query.
48pub struct OnDiskCache<'sess> {
abe05a73
XL
49 // The complete cache data in serialized form.
50 serialized_data: Vec<u8>,
51
e1599b0c
XL
52 // Collects all `Diagnostic`s emitted during the current compilation
53 // session.
83c7162d 54 current_diagnostics: Lock<FxHashMap<DepNodeIndex, Vec<Diagnostic>>>,
abe05a73
XL
55
56 prev_cnums: Vec<(u32, String, CrateDisambiguator)>,
f9f354fc 57 cnum_map: OnceCell<IndexVec<CrateNum, Option<CrateNum>>>,
abe05a73 58
b7449926 59 source_map: &'sess SourceMap,
a1dfa0c6 60 file_index_to_stable_id: FxHashMap<SourceFileIndex, StableSourceFileId>,
ff7c6d11 61
e1599b0c 62 // Caches that are populated lazily during decoding.
b7449926 63 file_index_to_file: Lock<FxHashMap<SourceFileIndex, Lrc<SourceFile>>>,
abe05a73
XL
64
65 // A map from dep-node to the position of the cached query result in
66 // `serialized_data`.
ff7c6d11
XL
67 query_result_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
68
69 // A map from dep-node to the position of any associated diagnostics in
70 // `serialized_data`.
71 prev_diagnostics_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
0531ce1d 72
94b46f34 73 alloc_decoding_state: AllocDecodingState,
3dfed10e
XL
74
75 // A map from syntax context ids to the position of their associated
76 // `SyntaxContextData`. We use a `u32` instead of a `SyntaxContext`
77 // to represent the fact that we are storing *encoded* ids. When we decode
78 // a `SyntaxContext`, a new id will be allocated from the global `HygieneData`,
79 // which will almost certainly be different than the serialized id.
80 syntax_contexts: FxHashMap<u32, AbsoluteBytePos>,
81 // A map from the `DefPathHash` of an `ExpnId` to the position
82 // of their associated `ExpnData`. Ideally, we would store a `DefId`,
83 // but we need to decode this before we've constructed a `TyCtxt` (which
84 // makes it difficult to decode a `DefId`).
85
86 // Note that these `DefPathHashes` correspond to both local and foreign
87 // `ExpnData` (e.g `ExpnData.krate` may not be `LOCAL_CRATE`). Alternatively,
88 // we could look up the `ExpnData` from the metadata of foreign crates,
89 // but it seemed easier to have `OnDiskCache` be independent of the `CStore`.
90 expn_data: FxHashMap<u32, AbsoluteBytePos>,
91 // Additional information used when decoding hygiene data.
92 hygiene_context: HygieneDecodeContext,
fc512014
XL
93 // Maps `DefPathHash`es to their `RawDefId`s from the *previous*
94 // compilation session. This is used as an initial 'guess' when
95 // we try to map a `DefPathHash` to its `DefId` in the current compilation
96 // session.
5869c6ff 97 foreign_def_path_hashes: UnhashMap<DefPathHash, RawDefId>,
fc512014
XL
98
99 // The *next* compilation sessison's `foreign_def_path_hashes` - at
100 // the end of our current compilation session, this will get written
101 // out to the `foreign_def_path_hashes` field of the `Footer`, which
102 // will become `foreign_def_path_hashes` of the next compilation session.
103 // This stores any `DefPathHash` that we may need to map to a `DefId`
104 // during the next compilation session.
5869c6ff 105 latest_foreign_def_path_hashes: Lock<UnhashMap<DefPathHash, RawDefId>>,
fc512014
XL
106
107 // Maps `DefPathHashes` to their corresponding `LocalDefId`s for all
108 // local items in the current compilation session. This is only populated
109 // when we are in incremental mode and have loaded a pre-existing cache
110 // from disk, since this map is only used when deserializing a `DefPathHash`
111 // from the incremental cache.
5869c6ff 112 local_def_path_hash_to_def_id: UnhashMap<DefPathHash, LocalDefId>,
fc512014
XL
113 // Caches all lookups of `DefPathHashes`, both for local and foreign
114 // definitions. A definition from the previous compilation session
115 // may no longer exist in the current compilation session, so
116 // we use `Option<DefId>` so that we can cache a lookup failure.
5869c6ff 117 def_path_hash_to_def_id_cache: Lock<UnhashMap<DefPathHash, Option<DefId>>>,
abe05a73
XL
118}
119
3dfed10e
XL
120// This type is used only for serialization and deserialization.
121#[derive(Encodable, Decodable)]
ff7c6d11 122struct Footer {
a1dfa0c6 123 file_index_to_stable_id: FxHashMap<SourceFileIndex, StableSourceFileId>,
abe05a73 124 prev_cnums: Vec<(u32, String, CrateDisambiguator)>,
ff7c6d11
XL
125 query_result_index: EncodedQueryResultIndex,
126 diagnostics_index: EncodedQueryResultIndex,
e1599b0c 127 // The location of all allocations.
94b46f34 128 interpret_alloc_index: Vec<u32>,
3dfed10e
XL
129 // See `OnDiskCache.syntax_contexts`
130 syntax_contexts: FxHashMap<u32, AbsoluteBytePos>,
131 // See `OnDiskCache.expn_data`
132 expn_data: FxHashMap<u32, AbsoluteBytePos>,
5869c6ff 133 foreign_def_path_hashes: UnhashMap<DefPathHash, RawDefId>,
abe05a73
XL
134}
135
6a06907d 136pub type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
ff7c6d11
XL
137type EncodedDiagnosticsIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
138type EncodedDiagnostics = Vec<Diagnostic>;
139
3dfed10e 140#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable, Decodable)]
b7449926 141struct SourceFileIndex(u32);
ff7c6d11 142
3dfed10e 143#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Encodable, Decodable)]
6a06907d 144pub struct AbsoluteBytePos(u32);
ff7c6d11
XL
145
146impl AbsoluteBytePos {
147 fn new(pos: usize) -> AbsoluteBytePos {
74b04a01 148 debug_assert!(pos <= u32::MAX as usize);
ff7c6d11
XL
149 AbsoluteBytePos(pos as u32)
150 }
151
152 fn to_usize(self) -> usize {
153 self.0 as usize
154 }
155}
abe05a73 156
fc512014
XL
157/// Represents a potentially invalid `DefId`. This is used during incremental
158/// compilation to represent a `DefId` from the *previous* compilation session,
159/// which may no longer be valid. This is used to help map a `DefPathHash`
160/// to a `DefId` in the current compilation session.
161#[derive(Encodable, Decodable, Copy, Clone, Debug)]
162crate struct RawDefId {
163 // We deliberately do not use `CrateNum` and `DefIndex`
164 // here, since a crate/index from the previous compilation
165 // session may no longer exist.
166 pub krate: u32,
167 pub index: u32,
168}
169
5869c6ff
XL
170fn make_local_def_path_hash_map(definitions: &Definitions) -> UnhashMap<DefPathHash, LocalDefId> {
171 UnhashMap::from_iter(
fc512014
XL
172 definitions
173 .def_path_table()
174 .all_def_path_hashes_and_def_ids(LOCAL_CRATE)
175 .map(|(hash, def_id)| (hash, def_id.as_local().unwrap())),
176 )
177}
178
abe05a73 179impl<'sess> OnDiskCache<'sess> {
e1599b0c 180 /// Creates a new `OnDiskCache` instance from the serialized data in `data`.
fc512014
XL
181 pub fn new(
182 sess: &'sess Session,
183 data: Vec<u8>,
184 start_pos: usize,
185 definitions: &Definitions,
186 ) -> Self {
abe05a73
XL
187 debug_assert!(sess.opts.incremental.is_some());
188
e1599b0c 189 // Wrap in a scope so we can borrow `data`.
ff7c6d11 190 let footer: Footer = {
abe05a73 191 let mut decoder = opaque::Decoder::new(&data[..], start_pos);
abe05a73 192
e1599b0c 193 // Decode the *position* of the footer, which can be found in the
ff7c6d11
XL
194 // last 8 bytes of the file.
195 decoder.set_position(data.len() - IntEncodedWithFixedSize::ENCODED_SIZE);
e1599b0c
XL
196 let footer_pos = IntEncodedWithFixedSize::decode(&mut decoder)
197 .expect("error while trying to decode footer position")
ff7c6d11
XL
198 .0 as usize;
199
e1599b0c
XL
200 // Decode the file footer, which contains all the lookup tables, etc.
201 decoder.set_position(footer_pos);
3dfed10e 202
ff7c6d11 203 decode_tagged(&mut decoder, TAG_FILE_FOOTER)
e1599b0c 204 .expect("error while trying to decode footer position")
abe05a73
XL
205 };
206
e1599b0c 207 Self {
abe05a73 208 serialized_data: data,
ff7c6d11 209 file_index_to_stable_id: footer.file_index_to_stable_id,
0bf4aa26 210 file_index_to_file: Default::default(),
ff7c6d11 211 prev_cnums: footer.prev_cnums,
f9f354fc 212 cnum_map: OnceCell::new(),
b7449926 213 source_map: sess.source_map(),
0bf4aa26 214 current_diagnostics: Default::default(),
ff7c6d11
XL
215 query_result_index: footer.query_result_index.into_iter().collect(),
216 prev_diagnostics_index: footer.diagnostics_index.into_iter().collect(),
94b46f34 217 alloc_decoding_state: AllocDecodingState::new(footer.interpret_alloc_index),
3dfed10e
XL
218 syntax_contexts: footer.syntax_contexts,
219 expn_data: footer.expn_data,
220 hygiene_context: Default::default(),
fc512014
XL
221 foreign_def_path_hashes: footer.foreign_def_path_hashes,
222 latest_foreign_def_path_hashes: Default::default(),
223 local_def_path_hash_to_def_id: make_local_def_path_hash_map(definitions),
224 def_path_hash_to_def_id_cache: Default::default(),
abe05a73
XL
225 }
226 }
227
e1599b0c
XL
228 pub fn new_empty(source_map: &'sess SourceMap) -> Self {
229 Self {
abe05a73 230 serialized_data: Vec::new(),
0bf4aa26
XL
231 file_index_to_stable_id: Default::default(),
232 file_index_to_file: Default::default(),
abe05a73 233 prev_cnums: vec![],
f9f354fc 234 cnum_map: OnceCell::new(),
b7449926 235 source_map,
0bf4aa26
XL
236 current_diagnostics: Default::default(),
237 query_result_index: Default::default(),
238 prev_diagnostics_index: Default::default(),
94b46f34 239 alloc_decoding_state: AllocDecodingState::new(Vec::new()),
3dfed10e
XL
240 syntax_contexts: FxHashMap::default(),
241 expn_data: FxHashMap::default(),
242 hygiene_context: Default::default(),
fc512014
XL
243 foreign_def_path_hashes: Default::default(),
244 latest_foreign_def_path_hashes: Default::default(),
245 local_def_path_hash_to_def_id: Default::default(),
246 def_path_hash_to_def_id_cache: Default::default(),
abe05a73
XL
247 }
248 }
249
5869c6ff
XL
250 pub fn serialize<'tcx>(
251 &self,
252 tcx: TyCtxt<'tcx>,
253 encoder: &mut FileEncoder,
254 ) -> FileEncodeResult {
e1599b0c 255 // Serializing the `DepGraph` should not modify it.
2c00a5a8 256 tcx.dep_graph.with_ignore(|| {
e1599b0c 257 // Allocate `SourceFileIndex`es.
2c00a5a8 258 let (file_to_file_index, file_index_to_stable_id) = {
a1dfa0c6 259 let files = tcx.sess.source_map().files();
dfeec247
XL
260 let mut file_to_file_index =
261 FxHashMap::with_capacity_and_hasher(files.len(), Default::default());
262 let mut file_index_to_stable_id =
263 FxHashMap::with_capacity_and_hasher(files.len(), Default::default());
2c00a5a8 264
a1dfa0c6 265 for (index, file) in files.iter().enumerate() {
b7449926
XL
266 let index = SourceFileIndex(index as u32);
267 let file_ptr: *const SourceFile = &**file as *const _;
2c00a5a8 268 file_to_file_index.insert(file_ptr, index);
a1dfa0c6 269 file_index_to_stable_id.insert(index, StableSourceFileId::new(&file));
2c00a5a8 270 }
abe05a73 271
2c00a5a8
XL
272 (file_to_file_index, file_index_to_stable_id)
273 };
274
fc512014
XL
275 // Register any dep nodes that we reused from the previous session,
276 // but didn't `DepNode::construct` in this session. This ensures
277 // that their `DefPathHash` to `RawDefId` mappings are registered
278 // in 'latest_foreign_def_path_hashes' if necessary, since that
279 // normally happens in `DepNode::construct`.
280 tcx.dep_graph.register_reused_dep_nodes(tcx);
281
282 // Load everything into memory so we can write it out to the on-disk
283 // cache. The vast majority of cacheable query results should already
284 // be in memory, so this should be a cheap operation.
285 // Do this *before* we clone 'latest_foreign_def_path_hashes', since
286 // loading existing queries may cause us to create new DepNodes, which
287 // may in turn end up invoking `store_foreign_def_id_hash`
6a06907d 288 tcx.queries.exec_cache_promotions(tcx);
fc512014
XL
289
290 let latest_foreign_def_path_hashes = self.latest_foreign_def_path_hashes.lock().clone();
3dfed10e
XL
291 let hygiene_encode_context = HygieneEncodeContext::default();
292
2c00a5a8
XL
293 let mut encoder = CacheEncoder {
294 tcx,
295 encoder,
0bf4aa26
XL
296 type_shorthands: Default::default(),
297 predicate_shorthands: Default::default(),
0bf4aa26 298 interpret_allocs: Default::default(),
b7449926 299 source_map: CachingSourceMapView::new(tcx.sess.source_map()),
2c00a5a8 300 file_to_file_index,
3dfed10e 301 hygiene_context: &hygiene_encode_context,
fc512014 302 latest_foreign_def_path_hashes,
2c00a5a8
XL
303 };
304
e1599b0c 305 // Encode query results.
2c00a5a8
XL
306 let mut query_result_index = EncodedQueryResultIndex::new();
307
5869c6ff 308 tcx.sess.time("encode_query_results", || -> FileEncodeResult {
2c00a5a8
XL
309 let enc = &mut encoder;
310 let qri = &mut query_result_index;
6a06907d 311 tcx.queries.encode_query_results(tcx, enc, qri)
83c7162d 312 })?;
ff7c6d11 313
e1599b0c 314 // Encode diagnostics.
dfeec247
XL
315 let diagnostics_index: EncodedDiagnosticsIndex = self
316 .current_diagnostics
317 .borrow()
0bf4aa26 318 .iter()
5869c6ff
XL
319 .map(
320 |(dep_node_index, diagnostics)| -> Result<_, <FileEncoder as Encoder>::Error> {
321 let pos = AbsoluteBytePos::new(encoder.position());
322 // Let's make sure we get the expected type here.
323 let diagnostics: &EncodedDiagnostics = diagnostics;
324 let dep_node_index = SerializedDepNodeIndex::new(dep_node_index.index());
325 encoder.encode_tagged(dep_node_index, diagnostics)?;
326
327 Ok((dep_node_index, pos))
328 },
329 )
e1599b0c 330 .collect::<Result<_, _>>()?;
2c00a5a8 331
0531ce1d
XL
332 let interpret_alloc_index = {
333 let mut interpret_alloc_index = Vec::new();
334 let mut n = 0;
335 loop {
3dfed10e 336 let new_n = encoder.interpret_allocs.len();
e1599b0c 337 // If we have found new IDs, serialize those too.
0531ce1d 338 if n == new_n {
e1599b0c 339 // Otherwise, abort.
0531ce1d
XL
340 break;
341 }
a1dfa0c6 342 interpret_alloc_index.reserve(new_n - n);
0531ce1d 343 for idx in n..new_n {
3dfed10e 344 let id = encoder.interpret_allocs[idx];
94b46f34 345 let pos = encoder.position() as u32;
0531ce1d 346 interpret_alloc_index.push(pos);
dfeec247 347 interpret::specialized_encode_alloc_id(&mut encoder, tcx, id)?;
0531ce1d
XL
348 }
349 n = new_n;
350 }
351 interpret_alloc_index
352 };
353
2c00a5a8 354 let sorted_cnums = sorted_cnums_including_local_crate(tcx);
dfeec247
XL
355 let prev_cnums: Vec<_> = sorted_cnums
356 .iter()
e1599b0c 357 .map(|&cnum| {
60c5eb7d 358 let crate_name = tcx.original_crate_name(cnum).to_string();
e1599b0c
XL
359 let crate_disambiguator = tcx.crate_disambiguator(cnum);
360 (cnum.as_u32(), crate_name, crate_disambiguator)
361 })
362 .collect();
363
3dfed10e
XL
364 let mut syntax_contexts = FxHashMap::default();
365 let mut expn_ids = FxHashMap::default();
366
367 // Encode all hygiene data (`SyntaxContextData` and `ExpnData`) from the current
368 // session.
369
370 hygiene_encode_context.encode(
371 &mut encoder,
5869c6ff 372 |encoder, index, ctxt_data| -> FileEncodeResult {
3dfed10e
XL
373 let pos = AbsoluteBytePos::new(encoder.position());
374 encoder.encode_tagged(TAG_SYNTAX_CONTEXT, ctxt_data)?;
375 syntax_contexts.insert(index, pos);
376 Ok(())
377 },
5869c6ff 378 |encoder, index, expn_data| -> FileEncodeResult {
3dfed10e
XL
379 let pos = AbsoluteBytePos::new(encoder.position());
380 encoder.encode_tagged(TAG_EXPN_DATA, expn_data)?;
381 expn_ids.insert(index, pos);
382 Ok(())
383 },
384 )?;
385
fc512014
XL
386 let foreign_def_path_hashes =
387 std::mem::take(&mut encoder.latest_foreign_def_path_hashes);
388
3dfed10e 389 // `Encode the file footer.
2c00a5a8 390 let footer_pos = encoder.position() as u64;
dfeec247
XL
391 encoder.encode_tagged(
392 TAG_FILE_FOOTER,
393 &Footer {
394 file_index_to_stable_id,
395 prev_cnums,
396 query_result_index,
397 diagnostics_index,
398 interpret_alloc_index,
3dfed10e
XL
399 syntax_contexts,
400 expn_data: expn_ids,
fc512014 401 foreign_def_path_hashes,
dfeec247
XL
402 },
403 )?;
2c00a5a8
XL
404
405 // Encode the position of the footer as the last 8 bytes of the
406 // file so we know where to look for it.
5869c6ff 407 IntEncodedWithFixedSize(footer_pos).encode(encoder.encoder)?;
2c00a5a8
XL
408
409 // DO NOT WRITE ANYTHING TO THE ENCODER AFTER THIS POINT! The address
410 // of the footer must be the last thing in the data stream.
411
412 return Ok(());
413
dc9dc135 414 fn sorted_cnums_including_local_crate(tcx: TyCtxt<'_>) -> Vec<CrateNum> {
2c00a5a8 415 let mut cnums = vec![LOCAL_CRATE];
6a06907d 416 cnums.extend_from_slice(tcx.crates());
2c00a5a8
XL
417 cnums.sort_unstable();
418 // Just to be sure...
419 cnums.dedup();
420 cnums
421 }
422 })
abe05a73
XL
423 }
424
9fa01778 425 /// Loads a diagnostic emitted during the previous compilation session.
416331ca 426 pub fn load_diagnostics(
dc9dc135 427 &self,
416331ca 428 tcx: TyCtxt<'_>,
dc9dc135
XL
429 dep_node_index: SerializedDepNodeIndex,
430 ) -> Vec<Diagnostic> {
dfeec247
XL
431 let diagnostics: Option<EncodedDiagnostics> =
432 self.load_indexed(tcx, dep_node_index, &self.prev_diagnostics_index, "diagnostics");
ff7c6d11 433
0bf4aa26 434 diagnostics.unwrap_or_default()
abe05a73
XL
435 }
436
9fa01778 437 /// Stores a diagnostic emitted during the current compilation session.
abe05a73
XL
438 /// Anything stored like this will be available via `load_diagnostics` in
439 /// the next compilation session.
0731742a
XL
440 #[inline(never)]
441 #[cold]
dfeec247
XL
442 pub fn store_diagnostics(
443 &self,
444 dep_node_index: DepNodeIndex,
445 diagnostics: ThinVec<Diagnostic>,
446 ) {
abe05a73 447 let mut current_diagnostics = self.current_diagnostics.borrow_mut();
0731742a 448 let prev = current_diagnostics.insert(dep_node_index, diagnostics.into());
abe05a73
XL
449 debug_assert!(prev.is_none());
450 }
451
fc512014
XL
452 fn get_raw_def_id(&self, hash: &DefPathHash) -> Option<RawDefId> {
453 self.foreign_def_path_hashes.get(hash).copied()
454 }
455
456 fn try_remap_cnum(&self, tcx: TyCtxt<'_>, cnum: u32) -> Option<CrateNum> {
457 let cnum_map =
458 self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx, &self.prev_cnums[..]));
459 debug!("try_remap_cnum({}): cnum_map={:?}", cnum, cnum_map);
460
461 cnum_map[CrateNum::from_u32(cnum)]
462 }
463
464 pub(crate) fn store_foreign_def_id_hash(&self, def_id: DefId, hash: DefPathHash) {
465 // We may overwrite an existing entry, but it will have the same value,
466 // so it's fine
467 self.latest_foreign_def_path_hashes
468 .lock()
469 .insert(hash, RawDefId { krate: def_id.krate.as_u32(), index: def_id.index.as_u32() });
470 }
471
472 /// If the given `dep_node`'s hash still exists in the current compilation,
473 /// and its current `DefId` is foreign, calls `store_foreign_def_id` with it.
474 ///
475 /// Normally, `store_foreign_def_id_hash` can be called directly by
476 /// the dependency graph when we construct a `DepNode`. However,
477 /// when we re-use a deserialized `DepNode` from the previous compilation
478 /// session, we only have the `DefPathHash` available. This method is used
479 /// to that any `DepNode` that we re-use has a `DefPathHash` -> `RawId` written
480 /// out for usage in the next compilation session.
481 pub fn register_reused_dep_node(&self, tcx: TyCtxt<'tcx>, dep_node: &DepNode) {
482 // For reused dep nodes, we only need to store the mapping if the node
483 // is one whose query key we can reconstruct from the hash. We use the
484 // mapping to aid that reconstruction in the next session. While we also
485 // use it to decode `DefId`s we encoded in the cache as `DefPathHashes`,
486 // they're already registered during `DefId` encoding.
487 if dep_node.kind.can_reconstruct_query_key() {
488 let hash = DefPathHash(dep_node.hash.into());
489
490 // We can't simply copy the `RawDefId` from `foreign_def_path_hashes` to
491 // `latest_foreign_def_path_hashes`, since the `RawDefId` might have
492 // changed in the current compilation session (e.g. we've added/removed crates,
493 // or added/removed definitions before/after the target definition).
494 if let Some(def_id) = self.def_path_hash_to_def_id(tcx, hash) {
495 if !def_id.is_local() {
496 self.store_foreign_def_id_hash(def_id, hash);
497 }
498 }
499 }
500 }
501
ff7c6d11 502 /// Returns the cached query result if there is something in the cache for
9fa01778 503 /// the given `SerializedDepNodeIndex`; otherwise returns `None`.
6a06907d 504 pub fn try_load_query_result<'tcx, T>(
dc9dc135 505 &self,
3dfed10e 506 tcx: TyCtxt<'tcx>,
dc9dc135
XL
507 dep_node_index: SerializedDepNodeIndex,
508 ) -> Option<T>
509 where
3dfed10e 510 T: for<'a> Decodable<CacheDecoder<'a, 'tcx>>,
abe05a73 511 {
dfeec247 512 self.load_indexed(tcx, dep_node_index, &self.query_result_index, "query result")
ff7c6d11
XL
513 }
514
9fa01778 515 /// Stores a diagnostic emitted during computation of an anonymous query.
ff7c6d11
XL
516 /// Since many anonymous queries can share the same `DepNode`, we aggregate
517 /// them -- as opposed to regular queries where we assume that there is a
518 /// 1:1 relationship between query-key and `DepNode`.
0731742a
XL
519 #[inline(never)]
520 #[cold]
dfeec247
XL
521 pub fn store_diagnostics_for_anon_node(
522 &self,
523 dep_node_index: DepNodeIndex,
524 diagnostics: ThinVec<Diagnostic>,
525 ) {
ff7c6d11
XL
526 let mut current_diagnostics = self.current_diagnostics.borrow_mut();
527
cdc7bbd5 528 let x = current_diagnostics.entry(dep_node_index).or_default();
ff7c6d11 529
0731742a 530 x.extend(Into::<Vec<_>>::into(diagnostics));
ff7c6d11
XL
531 }
532
dc9dc135
XL
533 fn load_indexed<'tcx, T>(
534 &self,
535 tcx: TyCtxt<'tcx>,
536 dep_node_index: SerializedDepNodeIndex,
537 index: &FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
538 debug_tag: &'static str,
539 ) -> Option<T>
540 where
3dfed10e 541 T: for<'a> Decodable<CacheDecoder<'a, 'tcx>>,
ff7c6d11 542 {
0731742a 543 let pos = index.get(&dep_node_index).cloned()?;
abe05a73 544
3dfed10e
XL
545 self.with_decoder(tcx, pos, |decoder| match decode_tagged(decoder, dep_node_index) {
546 Ok(v) => Some(v),
547 Err(e) => bug!("could not decode cached {}: {}", debug_tag, e),
548 })
549 }
550
551 fn with_decoder<'a, 'tcx, T, F: FnOnce(&mut CacheDecoder<'sess, 'tcx>) -> T>(
552 &'sess self,
553 tcx: TyCtxt<'tcx>,
554 pos: AbsoluteBytePos,
555 f: F,
556 ) -> T
557 where
558 T: Decodable<CacheDecoder<'a, 'tcx>>,
559 {
f9f354fc
XL
560 let cnum_map =
561 self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx, &self.prev_cnums[..]));
ff7c6d11 562
abe05a73 563 let mut decoder = CacheDecoder {
ff7c6d11
XL
564 tcx,
565 opaque: opaque::Decoder::new(&self.serialized_data[..], pos.to_usize()),
b7449926 566 source_map: self.source_map,
f9f354fc 567 cnum_map,
0531ce1d 568 file_index_to_file: &self.file_index_to_file,
ff7c6d11 569 file_index_to_stable_id: &self.file_index_to_stable_id,
94b46f34 570 alloc_decoding_session: self.alloc_decoding_state.new_decoding_session(),
3dfed10e
XL
571 syntax_contexts: &self.syntax_contexts,
572 expn_data: &self.expn_data,
573 hygiene_context: &self.hygiene_context,
abe05a73 574 };
3dfed10e 575 f(&mut decoder)
abe05a73
XL
576 }
577
e1599b0c
XL
578 // This function builds mapping from previous-session-`CrateNum` to
579 // current-session-`CrateNum`. There might be `CrateNum`s from the previous
580 // `Session` that don't occur in the current one. For these, the mapping
abe05a73 581 // maps to None.
dc9dc135
XL
582 fn compute_cnum_map(
583 tcx: TyCtxt<'_>,
584 prev_cnums: &[(u32, String, CrateDisambiguator)],
585 ) -> IndexVec<CrateNum, Option<CrateNum>> {
2c00a5a8 586 tcx.dep_graph.with_ignore(|| {
dfeec247
XL
587 let current_cnums = tcx
588 .all_crate_nums(LOCAL_CRATE)
589 .iter()
590 .map(|&cnum| {
591 let crate_name = tcx.original_crate_name(cnum).to_string();
592 let crate_disambiguator = tcx.crate_disambiguator(cnum);
593 ((crate_name, crate_disambiguator), cnum)
594 })
595 .collect::<FxHashMap<_, _>>();
596
597 let map_size = prev_cnums.iter().map(|&(cnum, ..)| cnum).max().unwrap_or(0) + 1;
a1dfa0c6 598 let mut map = IndexVec::from_elem_n(None, map_size as usize);
2c00a5a8
XL
599
600 for &(prev_cnum, ref crate_name, crate_disambiguator) in prev_cnums {
601 let key = (crate_name.clone(), crate_disambiguator);
602 map[CrateNum::from_u32(prev_cnum)] = current_cnums.get(&key).cloned();
603 }
abe05a73 604
2c00a5a8
XL
605 map[LOCAL_CRATE] = Some(LOCAL_CRATE);
606 map
607 })
abe05a73 608 }
fc512014
XL
609
610 /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation
611 /// session, if it still exists. This is used during incremental compilation to
612 /// turn a deserialized `DefPathHash` into its current `DefId`.
613 pub(crate) fn def_path_hash_to_def_id(
614 &self,
615 tcx: TyCtxt<'tcx>,
616 hash: DefPathHash,
617 ) -> Option<DefId> {
618 let mut cache = self.def_path_hash_to_def_id_cache.lock();
619 match cache.entry(hash) {
620 Entry::Occupied(e) => *e.get(),
621 Entry::Vacant(e) => {
622 debug!("def_path_hash_to_def_id({:?})", hash);
623 // Check if the `DefPathHash` corresponds to a definition in the current
624 // crate
625 if let Some(def_id) = self.local_def_path_hash_to_def_id.get(&hash).cloned() {
626 let def_id = def_id.to_def_id();
627 e.insert(Some(def_id));
628 return Some(def_id);
629 }
630 // This `raw_def_id` represents the `DefId` of this `DefPathHash` in
631 // the *previous* compliation session. The `DefPathHash` includes the
632 // owning crate, so if the corresponding definition still exists in the
633 // current compilation session, the crate is guaranteed to be the same
634 // (otherwise, we would compute a different `DefPathHash`).
635 let raw_def_id = self.get_raw_def_id(&hash)?;
636 debug!("def_path_hash_to_def_id({:?}): raw_def_id = {:?}", hash, raw_def_id);
637 // If the owning crate no longer exists, the corresponding definition definitely
638 // no longer exists.
639 let krate = self.try_remap_cnum(tcx, raw_def_id.krate)?;
640 debug!("def_path_hash_to_def_id({:?}): krate = {:?}", hash, krate);
641 // If our `DefPathHash` corresponded to a definition in the local crate,
642 // we should have either found it in `local_def_path_hash_to_def_id`, or
643 // never attempted to load it in the first place. Any query result or `DepNode`
644 // that references a local `DefId` should depend on some HIR-related `DepNode`.
645 // If a local definition is removed/modified such that its old `DefPathHash`
646 // no longer has a corresponding definition, that HIR-related `DepNode` should
647 // end up red. This should prevent us from ever calling
648 // `tcx.def_path_hash_to_def_id`, since we'll end up recomputing any
649 // queries involved.
650 debug_assert_ne!(krate, LOCAL_CRATE);
651 // Try to find a definition in the current session, using the previous `DefIndex`
652 // as an initial guess.
653 let opt_def_id = tcx.cstore.def_path_hash_to_def_id(krate, raw_def_id.index, hash);
654 debug!("def_path_to_def_id({:?}): opt_def_id = {:?}", hash, opt_def_id);
655 e.insert(opt_def_id);
656 opt_def_id
657 }
658 }
659 }
abe05a73
XL
660}
661
abe05a73
XL
662//- DECODING -------------------------------------------------------------------
663
fc512014 664/// A decoder that can read from the incremental compilation cache. It is similar to the one
e1599b0c
XL
665/// we use for crate metadata decoding in that it can rebase spans and eventually
666/// will also handle things that contain `Ty` instances.
6a06907d 667pub struct CacheDecoder<'a, 'tcx> {
dc9dc135
XL
668 tcx: TyCtxt<'tcx>,
669 opaque: opaque::Decoder<'a>,
670 source_map: &'a SourceMap,
671 cnum_map: &'a IndexVec<CrateNum, Option<CrateNum>>,
dc9dc135
XL
672 file_index_to_file: &'a Lock<FxHashMap<SourceFileIndex, Lrc<SourceFile>>>,
673 file_index_to_stable_id: &'a FxHashMap<SourceFileIndex, StableSourceFileId>,
674 alloc_decoding_session: AllocDecodingSession<'a>,
3dfed10e
XL
675 syntax_contexts: &'a FxHashMap<u32, AbsoluteBytePos>,
676 expn_data: &'a FxHashMap<u32, AbsoluteBytePos>,
677 hygiene_context: &'a HygieneDecodeContext,
abe05a73
XL
678}
679
dc9dc135 680impl<'a, 'tcx> CacheDecoder<'a, 'tcx> {
b7449926 681 fn file_index_to_file(&self, index: SourceFileIndex) -> Lrc<SourceFile> {
ff7c6d11 682 let CacheDecoder {
0531ce1d 683 ref file_index_to_file,
ff7c6d11 684 ref file_index_to_stable_id,
b7449926 685 ref source_map,
ff7c6d11
XL
686 ..
687 } = *self;
688
dfeec247
XL
689 file_index_to_file
690 .borrow_mut()
691 .entry(index)
692 .or_insert_with(|| {
693 let stable_id = file_index_to_stable_id[&index];
694 source_map
695 .source_file_by_stable_id(stable_id)
696 .expect("failed to lookup `SourceFile` in new context")
697 })
698 .clone()
ff7c6d11
XL
699 }
700}
701
702trait DecoderWithPosition: Decoder {
703 fn position(&self) -> usize;
704}
705
dc9dc135 706impl<'a> DecoderWithPosition for opaque::Decoder<'a> {
ff7c6d11
XL
707 fn position(&self) -> usize {
708 self.position()
709 }
710}
abe05a73 711
dc9dc135 712impl<'a, 'tcx> DecoderWithPosition for CacheDecoder<'a, 'tcx> {
ff7c6d11
XL
713 fn position(&self) -> usize {
714 self.opaque.position()
abe05a73
XL
715 }
716}
717
e1599b0c 718// Decodes something that was encoded with `encode_tagged()` and verify that the
abe05a73 719// tag matches and the correct amount of bytes was read.
dc9dc135
XL
720fn decode_tagged<D, T, V>(decoder: &mut D, expected_tag: T) -> Result<V, D::Error>
721where
29967ef6 722 T: Decodable<D> + Eq + std::fmt::Debug,
3dfed10e 723 V: Decodable<D>,
dc9dc135 724 D: DecoderWithPosition,
abe05a73
XL
725{
726 let start_pos = decoder.position();
727
728 let actual_tag = T::decode(decoder)?;
729 assert_eq!(actual_tag, expected_tag);
730 let value = V::decode(decoder)?;
731 let end_pos = decoder.position();
732
733 let expected_len: u64 = Decodable::decode(decoder)?;
734 assert_eq!((end_pos - start_pos) as u64, expected_len);
735
736 Ok(value)
737}
738
e1599b0c 739impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> {
3dfed10e
XL
740 const CLEAR_CROSS_CRATE: bool = false;
741
abe05a73 742 #[inline]
dc9dc135 743 fn tcx(&self) -> TyCtxt<'tcx> {
ff7c6d11 744 self.tcx
abe05a73
XL
745 }
746
747 #[inline]
748 fn position(&self) -> usize {
749 self.opaque.position()
750 }
751
752 #[inline]
753 fn peek_byte(&self) -> u8 {
754 self.opaque.data[self.opaque.position()]
755 }
756
dfeec247
XL
757 fn cached_ty_for_shorthand<F>(
758 &mut self,
759 shorthand: usize,
760 or_insert_with: F,
761 ) -> Result<Ty<'tcx>, Self::Error>
762 where
763 F: FnOnce(&mut Self) -> Result<Ty<'tcx>, Self::Error>,
abe05a73
XL
764 {
765 let tcx = self.tcx();
766
dfeec247
XL
767 let cache_key =
768 ty::CReaderCacheKey { cnum: CrateNum::ReservedForIncrCompCache, pos: shorthand };
abe05a73 769
f035d41b 770 if let Some(&ty) = tcx.ty_rcache.borrow().get(&cache_key) {
abe05a73
XL
771 return Ok(ty);
772 }
773
774 let ty = or_insert_with(self)?;
e1599b0c 775 // This may overwrite the entry, but it should overwrite with the same value.
f035d41b 776 tcx.ty_rcache.borrow_mut().insert_same(cache_key, ty);
abe05a73
XL
777 Ok(ty)
778 }
779
780 fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
dfeec247
XL
781 where
782 F: FnOnce(&mut Self) -> R,
abe05a73
XL
783 {
784 debug_assert!(pos < self.opaque.data.len());
785
786 let new_opaque = opaque::Decoder::new(self.opaque.data, pos);
787 let old_opaque = mem::replace(&mut self.opaque, new_opaque);
788 let r = f(self);
789 self.opaque = old_opaque;
790 r
791 }
792
793 fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum {
dfeec247 794 self.cnum_map[cnum].unwrap_or_else(|| bug!("could not find new `CrateNum` for {:?}", cnum))
abe05a73 795 }
abe05a73 796
3dfed10e 797 fn decode_alloc_id(&mut self) -> Result<interpret::AllocId, Self::Error> {
94b46f34
XL
798 let alloc_decoding_session = self.alloc_decoding_session;
799 alloc_decoding_session.decode_alloc_id(self)
0531ce1d
XL
800 }
801}
4462d4a0 802
3dfed10e
XL
803crate::implement_ty_decoder!(CacheDecoder<'a, 'tcx>);
804
5869c6ff
XL
805// This ensures that the `Decodable<opaque::Decoder>::decode` specialization for `Vec<u8>` is used
806// when a `CacheDecoder` is passed to `Decodable::decode`. Unfortunately, we have to manually opt
807// into specializations this way, given how `CacheDecoder` and the decoding traits currently work.
808impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Vec<u8> {
809 fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
810 Decodable::decode(&mut d.opaque)
811 }
812}
813
3dfed10e
XL
814impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for SyntaxContext {
815 fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
816 let syntax_contexts = decoder.syntax_contexts;
817 rustc_span::hygiene::decode_syntax_context(decoder, decoder.hygiene_context, |this, id| {
818 // This closure is invoked if we haven't already decoded the data for the `SyntaxContext` we are deserializing.
819 // We look up the position of the associated `SyntaxData` and decode it.
820 let pos = syntax_contexts.get(&id).unwrap();
821 this.with_position(pos.to_usize(), |decoder| {
822 let data: SyntaxContextData = decode_tagged(decoder, TAG_SYNTAX_CONTEXT)?;
823 Ok(data)
824 })
825 })
826 }
827}
828
829impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId {
830 fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
831 let expn_data = decoder.expn_data;
832 rustc_span::hygiene::decode_expn_id(
833 decoder,
834 ExpnDataDecodeMode::incr_comp(decoder.hygiene_context),
835 |this, index| {
836 // This closure is invoked if we haven't already decoded the data for the `ExpnId` we are deserializing.
837 // We look up the position of the associated `ExpnData` and decode it.
838 let pos = expn_data
839 .get(&index)
840 .unwrap_or_else(|| panic!("Bad index {:?} (map {:?})", index, expn_data));
841
842 this.with_position(pos.to_usize(), |decoder| {
843 let data: ExpnData = decode_tagged(decoder, TAG_EXPN_DATA)?;
844 Ok(data)
845 })
846 },
847 )
848 }
849}
850
851impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span {
852 fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
853 let tag: u8 = Decodable::decode(decoder)?;
ff7c6d11 854
5869c6ff
XL
855 if tag == TAG_PARTIAL_SPAN {
856 let ctxt = SyntaxContext::decode(decoder)?;
857 return Ok(DUMMY_SP.with_ctxt(ctxt));
ff7c6d11 858 } else {
5869c6ff 859 debug_assert_eq!(tag, TAG_FULL_SPAN);
abe05a73
XL
860 }
861
3dfed10e
XL
862 let file_lo_index = SourceFileIndex::decode(decoder)?;
863 let line_lo = usize::decode(decoder)?;
864 let col_lo = BytePos::decode(decoder)?;
865 let len = BytePos::decode(decoder)?;
866 let ctxt = SyntaxContext::decode(decoder)?;
ff7c6d11 867
3dfed10e 868 let file_lo = decoder.file_index_to_file(file_lo_index);
8faf50e0 869 let lo = file_lo.lines[line_lo - 1] + col_lo;
ff7c6d11
XL
870 let hi = lo + len;
871
3dfed10e 872 Ok(Span::new(lo, hi, ctxt))
abe05a73
XL
873 }
874}
875
3dfed10e
XL
876impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for CrateNum {
877 fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
878 let cnum = CrateNum::from_u32(u32::decode(d)?);
879 Ok(d.map_encoded_cnum_to_current(cnum))
e1599b0c
XL
880 }
881}
882
abe05a73 883// This impl makes sure that we get a runtime error when we try decode a
e1599b0c
XL
884// `DefIndex` that is not contained in a `DefId`. Such a case would be problematic
885// because we would not know how to transform the `DefIndex` to the current
abe05a73 886// context.
3dfed10e
XL
887impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefIndex {
888 fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<DefIndex, String> {
889 Err(d.error("trying to decode `DefIndex` outside the context of a `DefId`"))
abe05a73
XL
890 }
891}
892
e1599b0c
XL
893// Both the `CrateNum` and the `DefIndex` of a `DefId` can change in between two
894// compilation sessions. We use the `DefPathHash`, which is stable across
895// sessions, to map the old `DefId` to the new one.
3dfed10e
XL
896impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefId {
897 fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
e1599b0c 898 // Load the `DefPathHash` which is was we encoded the `DefId` as.
3dfed10e 899 let def_path_hash = DefPathHash::decode(d)?;
abe05a73 900
e1599b0c 901 // Using the `DefPathHash`, we can lookup the new `DefId`.
fc512014
XL
902 // Subtle: We only encode a `DefId` as part of a query result.
903 // If we get to this point, then all of the query inputs were green,
904 // which means that the definition with this hash is guaranteed to
905 // still exist in the current compilation session.
906 Ok(d.tcx()
fc512014
XL
907 .on_disk_cache
908 .as_ref()
909 .unwrap()
910 .def_path_hash_to_def_id(d.tcx(), def_path_hash)
911 .unwrap())
abe05a73
XL
912 }
913}
914
3dfed10e
XL
915impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx FxHashSet<LocalDefId> {
916 fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
917 RefDecodable::decode(d)
918 }
919}
920
921impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
922 for &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>>
923{
924 fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
925 RefDecodable::decode(d)
926 }
927}
928
1b1a35ee
XL
929impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
930 fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
931 RefDecodable::decode(d)
932 }
933}
934
3dfed10e
XL
935impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
936 fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
937 RefDecodable::decode(d)
938 }
939}
940
941impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [rustc_ast::InlineAsmTemplatePiece] {
942 fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
943 RefDecodable::decode(d)
944 }
945}
946
947impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [Span] {
948 fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
949 RefDecodable::decode(d)
2c00a5a8
XL
950 }
951}
952
abe05a73
XL
953//- ENCODING -------------------------------------------------------------------
954
6a06907d 955pub trait OpaqueEncoder: Encoder {
5869c6ff
XL
956 fn position(&self) -> usize;
957}
958
959impl OpaqueEncoder for FileEncoder {
960 #[inline]
961 fn position(&self) -> usize {
962 FileEncoder::position(self)
963 }
964}
965
fc512014 966/// An encoder that can write to the incremental compilation cache.
6a06907d 967pub struct CacheEncoder<'a, 'tcx, E: OpaqueEncoder> {
dc9dc135
XL
968 tcx: TyCtxt<'tcx>,
969 encoder: &'a mut E,
48663c56 970 type_shorthands: FxHashMap<Ty<'tcx>, usize>,
5869c6ff 971 predicate_shorthands: FxHashMap<ty::PredicateKind<'tcx>, usize>,
3dfed10e 972 interpret_allocs: FxIndexSet<interpret::AllocId>,
b7449926
XL
973 source_map: CachingSourceMapView<'tcx>,
974 file_to_file_index: FxHashMap<*const SourceFile, SourceFileIndex>,
3dfed10e 975 hygiene_context: &'a HygieneEncodeContext,
5869c6ff 976 latest_foreign_def_path_hashes: UnhashMap<DefPathHash, RawDefId>,
abe05a73
XL
977}
978
dc9dc135
XL
979impl<'a, 'tcx, E> CacheEncoder<'a, 'tcx, E>
980where
3dfed10e 981 E: 'a + OpaqueEncoder,
abe05a73 982{
b7449926
XL
983 fn source_file_index(&mut self, source_file: Lrc<SourceFile>) -> SourceFileIndex {
984 self.file_to_file_index[&(&*source_file as *const SourceFile)]
ff7c6d11
XL
985 }
986
abe05a73
XL
987 /// Encode something with additional information that allows to do some
988 /// sanity checks when decoding the data again. This method will first
989 /// encode the specified tag, then the given value, then the number of
990 /// bytes taken up by tag and value. On decoding, we can then verify that
991 /// we get the expected tag and read the expected number of bytes.
3dfed10e 992 fn encode_tagged<T: Encodable<Self>, V: Encodable<Self>>(
e1599b0c
XL
993 &mut self,
994 tag: T,
dfeec247 995 value: &V,
e1599b0c 996 ) -> Result<(), E::Error> {
abe05a73
XL
997 let start_pos = self.position();
998
999 tag.encode(self)?;
1000 value.encode(self)?;
1001
1002 let end_pos = self.position();
1003 ((end_pos - start_pos) as u64).encode(self)
1004 }
1005}
1006
3dfed10e 1007impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for SyntaxContext
dc9dc135 1008where
3dfed10e 1009 E: 'a + OpaqueEncoder,
0531ce1d 1010{
3dfed10e
XL
1011 fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
1012 rustc_span::hygiene::raw_encode_syntax_context(*self, s.hygiene_context, s)
1013 }
1014}
0531ce1d 1015
3dfed10e
XL
1016impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for ExpnId
1017where
1018 E: 'a + OpaqueEncoder,
1019{
1020 fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
1021 rustc_span::hygiene::raw_encode_expn_id(
1022 *self,
1023 s.hygiene_context,
1024 ExpnDataEncodeMode::IncrComp,
1025 s,
1026 )
0531ce1d
XL
1027 }
1028}
1029
3dfed10e 1030impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for Span
dc9dc135 1031where
3dfed10e 1032 E: 'a + OpaqueEncoder,
ff7c6d11 1033{
3dfed10e 1034 fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
6a06907d
XL
1035 let span_data = self.data();
1036 if self.is_dummy() {
5869c6ff 1037 TAG_PARTIAL_SPAN.encode(s)?;
6a06907d 1038 return span_data.ctxt.encode(s);
ff7c6d11
XL
1039 }
1040
5869c6ff
XL
1041 let pos = s.source_map.byte_pos_to_line_and_col(span_data.lo);
1042 let partial_span = match &pos {
1043 Some((file_lo, _, _)) => !file_lo.contains(span_data.hi),
1044 None => true,
3dfed10e 1045 };
ff7c6d11 1046
5869c6ff
XL
1047 if partial_span {
1048 TAG_PARTIAL_SPAN.encode(s)?;
1049 return span_data.ctxt.encode(s);
ff7c6d11
XL
1050 }
1051
5869c6ff
XL
1052 let (file_lo, line_lo, col_lo) = pos.unwrap();
1053
ff7c6d11
XL
1054 let len = span_data.hi - span_data.lo;
1055
3dfed10e 1056 let source_file_index = s.source_file_index(file_lo);
ff7c6d11 1057
5869c6ff 1058 TAG_FULL_SPAN.encode(s)?;
3dfed10e
XL
1059 source_file_index.encode(s)?;
1060 line_lo.encode(s)?;
1061 col_lo.encode(s)?;
1062 len.encode(s)?;
1063 span_data.ctxt.encode(s)
ff7c6d11
XL
1064 }
1065}
1066
3dfed10e 1067impl<'a, 'tcx, E> TyEncoder<'tcx> for CacheEncoder<'a, 'tcx, E>
dc9dc135 1068where
3dfed10e 1069 E: 'a + OpaqueEncoder,
e1599b0c 1070{
3dfed10e 1071 const CLEAR_CROSS_CRATE: bool = false;
e1599b0c 1072
abe05a73 1073 fn position(&self) -> usize {
5869c6ff 1074 self.encoder.position()
abe05a73 1075 }
3dfed10e
XL
1076 fn type_shorthands(&mut self) -> &mut FxHashMap<Ty<'tcx>, usize> {
1077 &mut self.type_shorthands
abe05a73 1078 }
5869c6ff 1079 fn predicate_shorthands(&mut self) -> &mut FxHashMap<ty::PredicateKind<'tcx>, usize> {
3dfed10e 1080 &mut self.predicate_shorthands
abe05a73 1081 }
3dfed10e
XL
1082 fn encode_alloc_id(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> {
1083 let (index, _) = self.interpret_allocs.insert_full(*alloc_id);
abe05a73 1084
3dfed10e 1085 index.encode(self)
abe05a73
XL
1086 }
1087}
1088
3dfed10e 1089impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for DefId
dc9dc135 1090where
3dfed10e 1091 E: 'a + OpaqueEncoder,
abe05a73 1092{
3dfed10e
XL
1093 fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
1094 let def_path_hash = s.tcx.def_path_hash(*self);
fc512014
XL
1095 // Store additional information when we encode a foreign `DefId`,
1096 // so that we can map its `DefPathHash` back to a `DefId` in the next
1097 // compilation session.
1098 if !self.is_local() {
1099 s.latest_foreign_def_path_hashes.insert(
1100 def_path_hash,
1101 RawDefId { krate: self.krate.as_u32(), index: self.index.as_u32() },
1102 );
1103 }
3dfed10e 1104 def_path_hash.encode(s)
abe05a73
XL
1105 }
1106}
1107
3dfed10e 1108impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for DefIndex
dc9dc135 1109where
3dfed10e 1110 E: 'a + OpaqueEncoder,
abe05a73 1111{
3dfed10e 1112 fn encode(&self, _: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
e1599b0c 1113 bug!("encoding `DefIndex` without context");
abe05a73
XL
1114 }
1115}
1116
abe05a73
XL
1117macro_rules! encoder_methods {
1118 ($($name:ident($ty:ty);)*) => {
74b04a01 1119 #[inline]
abe05a73
XL
1120 $(fn $name(&mut self, value: $ty) -> Result<(), Self::Error> {
1121 self.encoder.$name(value)
1122 })*
1123 }
1124}
1125
dc9dc135
XL
1126impl<'a, 'tcx, E> Encoder for CacheEncoder<'a, 'tcx, E>
1127where
3dfed10e 1128 E: 'a + OpaqueEncoder,
abe05a73
XL
1129{
1130 type Error = E::Error;
1131
f9f354fc 1132 #[inline]
b7449926 1133 fn emit_unit(&mut self) -> Result<(), Self::Error> {
abe05a73
XL
1134 Ok(())
1135 }
1136
1137 encoder_methods! {
1138 emit_usize(usize);
1139 emit_u128(u128);
1140 emit_u64(u64);
1141 emit_u32(u32);
1142 emit_u16(u16);
1143 emit_u8(u8);
1144
1145 emit_isize(isize);
1146 emit_i128(i128);
1147 emit_i64(i64);
1148 emit_i32(i32);
1149 emit_i16(i16);
1150 emit_i8(i8);
1151
1152 emit_bool(bool);
1153 emit_f64(f64);
1154 emit_f32(f32);
1155 emit_char(char);
1156 emit_str(&str);
cdc7bbd5 1157 emit_raw_bytes(&[u8]);
abe05a73
XL
1158 }
1159}
1160
5869c6ff
XL
1161// This ensures that the `Encodable<opaque::FileEncoder>::encode` specialization for byte slices
1162// is used when a `CacheEncoder` having an `opaque::FileEncoder` is passed to `Encodable::encode`.
1163// Unfortunately, we have to manually opt into specializations this way, given how `CacheEncoder`
1164// and the encoding traits currently work.
1165impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx, FileEncoder>> for [u8] {
1166 fn encode(&self, e: &mut CacheEncoder<'a, 'tcx, FileEncoder>) -> FileEncodeResult {
1167 self.encode(e.encoder)
1168 }
1169}
1170
6a06907d
XL
1171pub fn encode_query_results<'a, 'tcx, CTX, Q>(
1172 tcx: CTX,
5869c6ff 1173 encoder: &mut CacheEncoder<'a, 'tcx, FileEncoder>,
dc9dc135 1174 query_result_index: &mut EncodedQueryResultIndex,
5869c6ff 1175) -> FileEncodeResult
dc9dc135 1176where
6a06907d
XL
1177 CTX: QueryContext + 'tcx,
1178 Q: super::QueryDescription<CTX> + super::QueryAccessors<CTX>,
5869c6ff 1179 Q::Value: Encodable<CacheEncoder<'a, 'tcx, FileEncoder>>,
abe05a73 1180{
74b04a01 1181 let _timer = tcx
6a06907d
XL
1182 .dep_context()
1183 .profiler()
29967ef6 1184 .extra_verbose_generic_activity("encode_query_results_for", std::any::type_name::<Q>());
dfeec247 1185
6a06907d
XL
1186 assert!(Q::query_state(tcx).all_inactive());
1187 let cache = Q::query_cache(tcx);
cdc7bbd5
XL
1188 let mut res = Ok(());
1189 cache.iter_results(&mut |key, value, dep_node| {
1190 if res.is_err() {
1191 return;
1192 }
1193 if Q::cache_on_disk(tcx, &key, Some(value)) {
1194 let dep_node = SerializedDepNodeIndex::new(dep_node.index());
1195
1196 // Record position of the cache entry.
1197 query_result_index.push((dep_node, AbsoluteBytePos::new(encoder.encoder.position())));
1198
1199 // Encode the type check tables with the `SerializedDepNodeIndex`
1200 // as tag.
1201 match encoder.encode_tagged(dep_node, value) {
1202 Ok(()) => {}
1203 Err(e) => {
1204 res = Err(e);
1205 }
74b04a01
XL
1206 }
1207 }
cdc7bbd5
XL
1208 });
1209
1210 res
abe05a73 1211}