]>
Commit | Line | Data |
---|---|---|
fc512014 | 1 | use crate::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex}; |
9fa01778 | 2 | use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState}; |
3dfed10e | 3 | use crate::mir::{self, interpret}; |
5869c6ff | 4 | use crate::ty::codec::{RefDecodable, TyDecoder, TyEncoder}; |
9fa01778 | 5 | use crate::ty::context::TyCtxt; |
dfeec247 | 6 | use crate::ty::{self, Ty}; |
3dfed10e | 7 | use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; |
f9f354fc | 8 | use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, OnceCell}; |
0731742a | 9 | use rustc_data_structures::thin_vec::ThinVec; |
5869c6ff | 10 | use rustc_data_structures::unhash::UnhashMap; |
dfeec247 | 11 | use rustc_errors::Diagnostic; |
dfeec247 | 12 | use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE}; |
ba9703b0 | 13 | use rustc_hir::definitions::DefPathHash; |
fc512014 | 14 | use rustc_hir::definitions::Definitions; |
dfeec247 | 15 | use rustc_index::vec::{Idx, IndexVec}; |
6a06907d XL |
16 | use rustc_query_system::dep_graph::DepContext; |
17 | use rustc_query_system::query::QueryContext; | |
5869c6ff | 18 | use rustc_serialize::{ |
cdc7bbd5 | 19 | opaque::{self, FileEncodeResult, FileEncoder, IntEncodedWithFixedSize}, |
5869c6ff XL |
20 | Decodable, Decoder, Encodable, Encoder, |
21 | }; | |
ba9703b0 | 22 | use rustc_session::{CrateDisambiguator, Session}; |
3dfed10e XL |
23 | use rustc_span::hygiene::{ |
24 | ExpnDataDecodeMode, ExpnDataEncodeMode, ExpnId, HygieneDecodeContext, HygieneEncodeContext, | |
25 | SyntaxContext, SyntaxContextData, | |
26 | }; | |
dfeec247 | 27 | use rustc_span::source_map::{SourceMap, StableSourceFileId}; |
ba9703b0 | 28 | use rustc_span::CachingSourceMapView; |
3dfed10e | 29 | use rustc_span::{BytePos, ExpnData, SourceFile, Span, DUMMY_SP}; |
fc512014 XL |
30 | use std::collections::hash_map::Entry; |
31 | use std::iter::FromIterator; | |
abe05a73 | 32 | use std::mem; |
abe05a73 | 33 | |
ff7c6d11 XL |
34 | const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE; |
35 | ||
5869c6ff XL |
36 | // A normal span encoded with both location information and a `SyntaxContext` |
37 | const TAG_FULL_SPAN: u8 = 0; | |
38 | // A partial span with no location information, encoded only with a `SyntaxContext` | |
39 | const TAG_PARTIAL_SPAN: u8 = 1; | |
abe05a73 | 40 | |
3dfed10e XL |
41 | const TAG_SYNTAX_CONTEXT: u8 = 0; |
42 | const 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. |
48 | pub 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 | 122 | struct 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 | 136 | pub type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; |
ff7c6d11 XL |
137 | type EncodedDiagnosticsIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; |
138 | type EncodedDiagnostics = Vec<Diagnostic>; | |
139 | ||
3dfed10e | 140 | #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable, Decodable)] |
b7449926 | 141 | struct SourceFileIndex(u32); |
ff7c6d11 | 142 | |
3dfed10e | 143 | #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Encodable, Decodable)] |
6a06907d | 144 | pub struct AbsoluteBytePos(u32); |
ff7c6d11 XL |
145 | |
146 | impl 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)] | |
162 | crate 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 |
170 | fn 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 | 179 | impl<'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 | 667 | pub 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 | 680 | impl<'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 | ||
702 | trait DecoderWithPosition: Decoder { | |
703 | fn position(&self) -> usize; | |
704 | } | |
705 | ||
dc9dc135 | 706 | impl<'a> DecoderWithPosition for opaque::Decoder<'a> { |
ff7c6d11 XL |
707 | fn position(&self) -> usize { |
708 | self.position() | |
709 | } | |
710 | } | |
abe05a73 | 711 | |
dc9dc135 | 712 | impl<'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 |
720 | fn decode_tagged<D, T, V>(decoder: &mut D, expected_tag: T) -> Result<V, D::Error> |
721 | where | |
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 | 739 | impl<'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 |
803 | crate::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. | |
808 | impl<'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 |
814 | impl<'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 | ||
829 | impl<'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 | ||
851 | impl<'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 |
876 | impl<'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 |
887 | impl<'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 |
896 | impl<'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 |
915 | impl<'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 | ||
921 | impl<'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 |
929 | impl<'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 |
935 | impl<'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 | ||
941 | impl<'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 | ||
947 | impl<'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 | 955 | pub trait OpaqueEncoder: Encoder { |
5869c6ff XL |
956 | fn position(&self) -> usize; |
957 | } | |
958 | ||
959 | impl 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 | 967 | pub 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 |
979 | impl<'a, 'tcx, E> CacheEncoder<'a, 'tcx, E> |
980 | where | |
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 | 1007 | impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for SyntaxContext |
dc9dc135 | 1008 | where |
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 |
1016 | impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for ExpnId |
1017 | where | |
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 | 1030 | impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for Span |
dc9dc135 | 1031 | where |
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 | 1067 | impl<'a, 'tcx, E> TyEncoder<'tcx> for CacheEncoder<'a, 'tcx, E> |
dc9dc135 | 1068 | where |
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 | 1089 | impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for DefId |
dc9dc135 | 1090 | where |
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 | 1108 | impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for DefIndex |
dc9dc135 | 1109 | where |
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 |
1117 | macro_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 |
1126 | impl<'a, 'tcx, E> Encoder for CacheEncoder<'a, 'tcx, E> |
1127 | where | |
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. | |
1165 | impl<'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 |
1171 | pub 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 | 1176 | where |
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 | } |