]>
Commit | Line | Data |
---|---|---|
136023e0 | 1 | use crate::QueryCtxt; |
2b03887a | 2 | use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; |
c295e0f8 XL |
3 | use rustc_data_structures::memmap::Mmap; |
4 | use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, RwLock}; | |
5869c6ff | 5 | use rustc_data_structures::unhash::UnhashMap; |
2b03887a | 6 | use rustc_data_structures::unord::UnordSet; |
17df50a5 | 7 | use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, StableCrateId, LOCAL_CRATE}; |
ba9703b0 | 8 | use rustc_hir::definitions::DefPathHash; |
dfeec247 | 9 | use rustc_index::vec::{Idx, IndexVec}; |
c295e0f8 | 10 | use rustc_middle::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; |
136023e0 XL |
11 | use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; |
12 | use rustc_middle::mir::{self, interpret}; | |
13 | use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder}; | |
14 | use rustc_middle::ty::{self, Ty, TyCtxt}; | |
6a06907d | 15 | use rustc_query_system::dep_graph::DepContext; |
5e7ed085 | 16 | use rustc_query_system::query::{QueryCache, QueryContext, QuerySideEffects}; |
5869c6ff | 17 | use rustc_serialize::{ |
923072b8 | 18 | opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder}, |
5869c6ff XL |
19 | Decodable, Decoder, Encodable, Encoder, |
20 | }; | |
17df50a5 | 21 | use rustc_session::Session; |
3dfed10e | 22 | use rustc_span::hygiene::{ |
136023e0 | 23 | ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextData, |
3dfed10e | 24 | }; |
dfeec247 | 25 | use rustc_span::source_map::{SourceMap, StableSourceFileId}; |
c295e0f8 | 26 | use rustc_span::{BytePos, ExpnData, ExpnHash, Pos, SourceFile, Span}; |
f2b60f7d FG |
27 | use rustc_span::{CachingSourceMapView, Symbol}; |
28 | use std::collections::hash_map::Entry; | |
923072b8 | 29 | use std::io; |
abe05a73 | 30 | use std::mem; |
abe05a73 | 31 | |
ff7c6d11 XL |
32 | const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE; |
33 | ||
5869c6ff XL |
34 | // A normal span encoded with both location information and a `SyntaxContext` |
35 | const TAG_FULL_SPAN: u8 = 0; | |
36 | // A partial span with no location information, encoded only with a `SyntaxContext` | |
37 | const TAG_PARTIAL_SPAN: u8 = 1; | |
c295e0f8 | 38 | const TAG_RELATIVE_SPAN: u8 = 2; |
abe05a73 | 39 | |
3dfed10e XL |
40 | const TAG_SYNTAX_CONTEXT: u8 = 0; |
41 | const TAG_EXPN_DATA: u8 = 1; | |
42 | ||
f2b60f7d FG |
43 | // Tags for encoding Symbol's |
44 | const SYMBOL_STR: u8 = 0; | |
45 | const SYMBOL_OFFSET: u8 = 1; | |
46 | const SYMBOL_PREINTERNED: u8 = 2; | |
47 | ||
e1599b0c | 48 | /// Provides an interface to incremental compilation data cached from the |
abe05a73 | 49 | /// previous compilation session. This data will eventually include the results |
3dfed10e | 50 | /// of a few selected queries (like `typeck` and `mir_optimized`) and |
94222f64 | 51 | /// any side effects that have been emitted during a query. |
abe05a73 | 52 | pub struct OnDiskCache<'sess> { |
abe05a73 | 53 | // The complete cache data in serialized form. |
c295e0f8 | 54 | serialized_data: RwLock<Option<Mmap>>, |
abe05a73 | 55 | |
94222f64 | 56 | // Collects all `QuerySideEffects` created during the current compilation |
e1599b0c | 57 | // session. |
94222f64 | 58 | current_side_effects: Lock<FxHashMap<DepNodeIndex, QuerySideEffects>>, |
abe05a73 | 59 | |
b7449926 | 60 | source_map: &'sess SourceMap, |
17df50a5 | 61 | file_index_to_stable_id: FxHashMap<SourceFileIndex, EncodedSourceFileId>, |
ff7c6d11 | 62 | |
e1599b0c | 63 | // Caches that are populated lazily during decoding. |
b7449926 | 64 | file_index_to_file: Lock<FxHashMap<SourceFileIndex, Lrc<SourceFile>>>, |
abe05a73 XL |
65 | |
66 | // A map from dep-node to the position of the cached query result in | |
67 | // `serialized_data`. | |
ff7c6d11 XL |
68 | query_result_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>, |
69 | ||
94222f64 | 70 | // A map from dep-node to the position of any associated `QuerySideEffects` in |
ff7c6d11 | 71 | // `serialized_data`. |
94222f64 | 72 | prev_side_effects_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>, |
0531ce1d | 73 | |
94b46f34 | 74 | alloc_decoding_state: AllocDecodingState, |
3dfed10e XL |
75 | |
76 | // A map from syntax context ids to the position of their associated | |
77 | // `SyntaxContextData`. We use a `u32` instead of a `SyntaxContext` | |
78 | // to represent the fact that we are storing *encoded* ids. When we decode | |
79 | // a `SyntaxContext`, a new id will be allocated from the global `HygieneData`, | |
80 | // which will almost certainly be different than the serialized id. | |
81 | syntax_contexts: FxHashMap<u32, AbsoluteBytePos>, | |
82 | // A map from the `DefPathHash` of an `ExpnId` to the position | |
83 | // of their associated `ExpnData`. Ideally, we would store a `DefId`, | |
84 | // but we need to decode this before we've constructed a `TyCtxt` (which | |
85 | // makes it difficult to decode a `DefId`). | |
86 | ||
87 | // Note that these `DefPathHashes` correspond to both local and foreign | |
88 | // `ExpnData` (e.g `ExpnData.krate` may not be `LOCAL_CRATE`). Alternatively, | |
89 | // we could look up the `ExpnData` from the metadata of foreign crates, | |
90 | // but it seemed easier to have `OnDiskCache` be independent of the `CStore`. | |
136023e0 | 91 | expn_data: UnhashMap<ExpnHash, AbsoluteBytePos>, |
3dfed10e XL |
92 | // Additional information used when decoding hygiene data. |
93 | hygiene_context: HygieneDecodeContext, | |
c295e0f8 | 94 | // Maps `ExpnHash`es to their raw value from the *previous* |
fc512014 | 95 | // compilation session. This is used as an initial 'guess' when |
c295e0f8 XL |
96 | // we try to map an `ExpnHash` to its value in the current |
97 | // compilation session. | |
136023e0 | 98 | foreign_expn_data: UnhashMap<ExpnHash, u32>, |
abe05a73 XL |
99 | } |
100 | ||
3dfed10e XL |
101 | // This type is used only for serialization and deserialization. |
102 | #[derive(Encodable, Decodable)] | |
ff7c6d11 | 103 | struct Footer { |
17df50a5 | 104 | file_index_to_stable_id: FxHashMap<SourceFileIndex, EncodedSourceFileId>, |
94222f64 XL |
105 | query_result_index: EncodedDepNodeIndex, |
106 | side_effects_index: EncodedDepNodeIndex, | |
e1599b0c | 107 | // The location of all allocations. |
94b46f34 | 108 | interpret_alloc_index: Vec<u32>, |
3dfed10e XL |
109 | // See `OnDiskCache.syntax_contexts` |
110 | syntax_contexts: FxHashMap<u32, AbsoluteBytePos>, | |
111 | // See `OnDiskCache.expn_data` | |
136023e0 | 112 | expn_data: UnhashMap<ExpnHash, AbsoluteBytePos>, |
136023e0 | 113 | foreign_expn_data: UnhashMap<ExpnHash, u32>, |
abe05a73 XL |
114 | } |
115 | ||
94222f64 | 116 | pub type EncodedDepNodeIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; |
ff7c6d11 | 117 | |
3dfed10e | 118 | #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable, Decodable)] |
b7449926 | 119 | struct SourceFileIndex(u32); |
ff7c6d11 | 120 | |
3dfed10e | 121 | #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Encodable, Decodable)] |
2b03887a | 122 | pub struct AbsoluteBytePos(u64); |
ff7c6d11 XL |
123 | |
124 | impl AbsoluteBytePos { | |
125 | fn new(pos: usize) -> AbsoluteBytePos { | |
2b03887a | 126 | AbsoluteBytePos(pos.try_into().expect("Incremental cache file size overflowed u64.")) |
ff7c6d11 XL |
127 | } |
128 | ||
129 | fn to_usize(self) -> usize { | |
130 | self.0 as usize | |
131 | } | |
132 | } | |
abe05a73 | 133 | |
17df50a5 XL |
134 | /// An `EncodedSourceFileId` is the same as a `StableSourceFileId` except that |
135 | /// the source crate is represented as a [StableCrateId] instead of as a | |
136 | /// `CrateNum`. This way `EncodedSourceFileId` can be encoded and decoded | |
137 | /// without any additional context, i.e. with a simple `opaque::Decoder` (which | |
138 | /// is the only thing available when decoding the cache's [Footer]. | |
139 | #[derive(Encodable, Decodable, Clone, Debug)] | |
140 | struct EncodedSourceFileId { | |
141 | file_name_hash: u64, | |
142 | stable_crate_id: StableCrateId, | |
143 | } | |
144 | ||
145 | impl EncodedSourceFileId { | |
c295e0f8 XL |
146 | fn translate(&self, tcx: TyCtxt<'_>) -> StableSourceFileId { |
147 | let cnum = tcx.stable_crate_id_to_crate_num(self.stable_crate_id); | |
17df50a5 XL |
148 | StableSourceFileId { file_name_hash: self.file_name_hash, cnum } |
149 | } | |
150 | ||
151 | fn new(tcx: TyCtxt<'_>, file: &SourceFile) -> EncodedSourceFileId { | |
152 | let source_file_id = StableSourceFileId::new(file); | |
153 | EncodedSourceFileId { | |
154 | file_name_hash: source_file_id.file_name_hash, | |
155 | stable_crate_id: tcx.stable_crate_id(source_file_id.cnum), | |
156 | } | |
157 | } | |
fc512014 XL |
158 | } |
159 | ||
136023e0 | 160 | impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> { |
c295e0f8 XL |
161 | /// Creates a new `OnDiskCache` instance from the serialized data in `data`. |
162 | fn new(sess: &'sess Session, data: Mmap, start_pos: usize) -> Self { | |
abe05a73 XL |
163 | debug_assert!(sess.opts.incremental.is_some()); |
164 | ||
e1599b0c | 165 | // Wrap in a scope so we can borrow `data`. |
ff7c6d11 | 166 | let footer: Footer = { |
923072b8 | 167 | let mut decoder = MemDecoder::new(&data, start_pos); |
abe05a73 | 168 | |
e1599b0c | 169 | // Decode the *position* of the footer, which can be found in the |
ff7c6d11 XL |
170 | // last 8 bytes of the file. |
171 | decoder.set_position(data.len() - IntEncodedWithFixedSize::ENCODED_SIZE); | |
5099ac24 | 172 | let footer_pos = IntEncodedWithFixedSize::decode(&mut decoder).0 as usize; |
ff7c6d11 | 173 | |
e1599b0c XL |
174 | // Decode the file footer, which contains all the lookup tables, etc. |
175 | decoder.set_position(footer_pos); | |
3dfed10e | 176 | |
ff7c6d11 | 177 | decode_tagged(&mut decoder, TAG_FILE_FOOTER) |
abe05a73 XL |
178 | }; |
179 | ||
e1599b0c | 180 | Self { |
c295e0f8 | 181 | serialized_data: RwLock::new(Some(data)), |
ff7c6d11 | 182 | file_index_to_stable_id: footer.file_index_to_stable_id, |
0bf4aa26 | 183 | file_index_to_file: Default::default(), |
b7449926 | 184 | source_map: sess.source_map(), |
94222f64 | 185 | current_side_effects: Default::default(), |
ff7c6d11 | 186 | query_result_index: footer.query_result_index.into_iter().collect(), |
94222f64 | 187 | prev_side_effects_index: footer.side_effects_index.into_iter().collect(), |
94b46f34 | 188 | alloc_decoding_state: AllocDecodingState::new(footer.interpret_alloc_index), |
3dfed10e XL |
189 | syntax_contexts: footer.syntax_contexts, |
190 | expn_data: footer.expn_data, | |
136023e0 | 191 | foreign_expn_data: footer.foreign_expn_data, |
3dfed10e | 192 | hygiene_context: Default::default(), |
abe05a73 XL |
193 | } |
194 | } | |
195 | ||
136023e0 | 196 | fn new_empty(source_map: &'sess SourceMap) -> Self { |
e1599b0c | 197 | Self { |
c295e0f8 | 198 | serialized_data: RwLock::new(None), |
0bf4aa26 XL |
199 | file_index_to_stable_id: Default::default(), |
200 | file_index_to_file: Default::default(), | |
b7449926 | 201 | source_map, |
94222f64 | 202 | current_side_effects: Default::default(), |
0bf4aa26 | 203 | query_result_index: Default::default(), |
94222f64 | 204 | prev_side_effects_index: Default::default(), |
94b46f34 | 205 | alloc_decoding_state: AllocDecodingState::new(Vec::new()), |
3dfed10e | 206 | syntax_contexts: FxHashMap::default(), |
136023e0 XL |
207 | expn_data: UnhashMap::default(), |
208 | foreign_expn_data: UnhashMap::default(), | |
3dfed10e | 209 | hygiene_context: Default::default(), |
abe05a73 XL |
210 | } |
211 | } | |
212 | ||
c295e0f8 XL |
213 | /// Execute all cache promotions and release the serialized backing Mmap. |
214 | /// | |
215 | /// Cache promotions require invoking queries, which needs to read the serialized data. | |
216 | /// In order to serialize the new on-disk cache, the former on-disk cache file needs to be | |
217 | /// deleted, hence we won't be able to refer to its memmapped data. | |
a2a8927a | 218 | fn drop_serialized_data(&self, tcx: TyCtxt<'_>) { |
c295e0f8 XL |
219 | // Load everything into memory so we can write it out to the on-disk |
220 | // cache. The vast majority of cacheable query results should already | |
221 | // be in memory, so this should be a cheap operation. | |
222 | // Do this *before* we clone 'latest_foreign_def_path_hashes', since | |
223 | // loading existing queries may cause us to create new DepNodes, which | |
224 | // may in turn end up invoking `store_foreign_def_id_hash` | |
3c0e092e | 225 | tcx.dep_graph.exec_cache_promotions(tcx); |
c295e0f8 XL |
226 | |
227 | *self.serialized_data.write() = None; | |
228 | } | |
229 | ||
9c376795 | 230 | fn serialize(&self, tcx: TyCtxt<'_>, encoder: FileEncoder) -> FileEncodeResult { |
e1599b0c | 231 | // Serializing the `DepGraph` should not modify it. |
2c00a5a8 | 232 | tcx.dep_graph.with_ignore(|| { |
e1599b0c | 233 | // Allocate `SourceFileIndex`es. |
2c00a5a8 | 234 | let (file_to_file_index, file_index_to_stable_id) = { |
a1dfa0c6 | 235 | let files = tcx.sess.source_map().files(); |
dfeec247 XL |
236 | let mut file_to_file_index = |
237 | FxHashMap::with_capacity_and_hasher(files.len(), Default::default()); | |
238 | let mut file_index_to_stable_id = | |
239 | FxHashMap::with_capacity_and_hasher(files.len(), Default::default()); | |
2c00a5a8 | 240 | |
a1dfa0c6 | 241 | for (index, file) in files.iter().enumerate() { |
b7449926 XL |
242 | let index = SourceFileIndex(index as u32); |
243 | let file_ptr: *const SourceFile = &**file as *const _; | |
2c00a5a8 | 244 | file_to_file_index.insert(file_ptr, index); |
17df50a5 XL |
245 | let source_file_id = EncodedSourceFileId::new(tcx, &file); |
246 | file_index_to_stable_id.insert(index, source_file_id); | |
2c00a5a8 | 247 | } |
abe05a73 | 248 | |
2c00a5a8 XL |
249 | (file_to_file_index, file_index_to_stable_id) |
250 | }; | |
251 | ||
3dfed10e XL |
252 | let hygiene_encode_context = HygieneEncodeContext::default(); |
253 | ||
2c00a5a8 XL |
254 | let mut encoder = CacheEncoder { |
255 | tcx, | |
256 | encoder, | |
0bf4aa26 XL |
257 | type_shorthands: Default::default(), |
258 | predicate_shorthands: Default::default(), | |
0bf4aa26 | 259 | interpret_allocs: Default::default(), |
b7449926 | 260 | source_map: CachingSourceMapView::new(tcx.sess.source_map()), |
2c00a5a8 | 261 | file_to_file_index, |
3dfed10e | 262 | hygiene_context: &hygiene_encode_context, |
f2b60f7d | 263 | symbol_table: Default::default(), |
2c00a5a8 XL |
264 | }; |
265 | ||
e1599b0c | 266 | // Encode query results. |
94222f64 | 267 | let mut query_result_index = EncodedDepNodeIndex::new(); |
2c00a5a8 | 268 | |
923072b8 | 269 | tcx.sess.time("encode_query_results", || { |
2c00a5a8 XL |
270 | let enc = &mut encoder; |
271 | let qri = &mut query_result_index; | |
923072b8 FG |
272 | QueryCtxt::from_tcx(tcx).encode_query_results(enc, qri); |
273 | }); | |
ff7c6d11 | 274 | |
94222f64 XL |
275 | // Encode side effects. |
276 | let side_effects_index: EncodedDepNodeIndex = self | |
277 | .current_side_effects | |
dfeec247 | 278 | .borrow() |
0bf4aa26 | 279 | .iter() |
923072b8 FG |
280 | .map(|(dep_node_index, side_effects)| { |
281 | let pos = AbsoluteBytePos::new(encoder.position()); | |
282 | let dep_node_index = SerializedDepNodeIndex::new(dep_node_index.index()); | |
283 | encoder.encode_tagged(dep_node_index, side_effects); | |
5869c6ff | 284 | |
923072b8 FG |
285 | (dep_node_index, pos) |
286 | }) | |
287 | .collect(); | |
2c00a5a8 | 288 | |
0531ce1d XL |
289 | let interpret_alloc_index = { |
290 | let mut interpret_alloc_index = Vec::new(); | |
291 | let mut n = 0; | |
292 | loop { | |
3dfed10e | 293 | let new_n = encoder.interpret_allocs.len(); |
e1599b0c | 294 | // If we have found new IDs, serialize those too. |
0531ce1d | 295 | if n == new_n { |
e1599b0c | 296 | // Otherwise, abort. |
0531ce1d XL |
297 | break; |
298 | } | |
a1dfa0c6 | 299 | interpret_alloc_index.reserve(new_n - n); |
0531ce1d | 300 | for idx in n..new_n { |
3dfed10e | 301 | let id = encoder.interpret_allocs[idx]; |
94b46f34 | 302 | let pos = encoder.position() as u32; |
0531ce1d | 303 | interpret_alloc_index.push(pos); |
923072b8 | 304 | interpret::specialized_encode_alloc_id(&mut encoder, tcx, id); |
0531ce1d XL |
305 | } |
306 | n = new_n; | |
307 | } | |
308 | interpret_alloc_index | |
309 | }; | |
310 | ||
3dfed10e | 311 | let mut syntax_contexts = FxHashMap::default(); |
136023e0 XL |
312 | let mut expn_data = UnhashMap::default(); |
313 | let mut foreign_expn_data = UnhashMap::default(); | |
3dfed10e XL |
314 | |
315 | // Encode all hygiene data (`SyntaxContextData` and `ExpnData`) from the current | |
316 | // session. | |
317 | ||
318 | hygiene_encode_context.encode( | |
319 | &mut encoder, | |
923072b8 | 320 | |encoder, index, ctxt_data| { |
3dfed10e | 321 | let pos = AbsoluteBytePos::new(encoder.position()); |
923072b8 | 322 | encoder.encode_tagged(TAG_SYNTAX_CONTEXT, ctxt_data); |
3dfed10e | 323 | syntax_contexts.insert(index, pos); |
3dfed10e | 324 | }, |
923072b8 | 325 | |encoder, expn_id, data, hash| { |
136023e0 XL |
326 | if expn_id.krate == LOCAL_CRATE { |
327 | let pos = AbsoluteBytePos::new(encoder.position()); | |
923072b8 | 328 | encoder.encode_tagged(TAG_EXPN_DATA, data); |
136023e0 XL |
329 | expn_data.insert(hash, pos); |
330 | } else { | |
331 | foreign_expn_data.insert(hash, expn_id.local_id.as_u32()); | |
332 | } | |
3dfed10e | 333 | }, |
923072b8 | 334 | ); |
3dfed10e XL |
335 | |
336 | // `Encode the file footer. | |
2c00a5a8 | 337 | let footer_pos = encoder.position() as u64; |
dfeec247 XL |
338 | encoder.encode_tagged( |
339 | TAG_FILE_FOOTER, | |
340 | &Footer { | |
341 | file_index_to_stable_id, | |
dfeec247 | 342 | query_result_index, |
94222f64 | 343 | side_effects_index, |
dfeec247 | 344 | interpret_alloc_index, |
3dfed10e | 345 | syntax_contexts, |
136023e0 XL |
346 | expn_data, |
347 | foreign_expn_data, | |
dfeec247 | 348 | }, |
923072b8 | 349 | ); |
2c00a5a8 XL |
350 | |
351 | // Encode the position of the footer as the last 8 bytes of the | |
352 | // file so we know where to look for it. | |
923072b8 | 353 | IntEncodedWithFixedSize(footer_pos).encode(&mut encoder.encoder); |
2c00a5a8 XL |
354 | |
355 | // DO NOT WRITE ANYTHING TO THE ENCODER AFTER THIS POINT! The address | |
356 | // of the footer must be the last thing in the data stream. | |
357 | ||
923072b8 | 358 | encoder.finish() |
2c00a5a8 | 359 | }) |
abe05a73 | 360 | } |
136023e0 XL |
361 | } |
362 | ||
363 | impl<'sess> OnDiskCache<'sess> { | |
364 | pub fn as_dyn(&self) -> &dyn rustc_middle::ty::OnDiskCache<'sess> { | |
365 | self as _ | |
366 | } | |
367 | ||
94222f64 XL |
368 | /// Loads a `QuerySideEffects` created during the previous compilation session. |
369 | pub fn load_side_effects( | |
dc9dc135 | 370 | &self, |
416331ca | 371 | tcx: TyCtxt<'_>, |
dc9dc135 | 372 | dep_node_index: SerializedDepNodeIndex, |
94222f64 XL |
373 | ) -> QuerySideEffects { |
374 | let side_effects: Option<QuerySideEffects> = | |
5099ac24 | 375 | self.load_indexed(tcx, dep_node_index, &self.prev_side_effects_index); |
ff7c6d11 | 376 | |
94222f64 | 377 | side_effects.unwrap_or_default() |
abe05a73 XL |
378 | } |
379 | ||
94222f64 XL |
380 | /// Stores a `QuerySideEffects` emitted during the current compilation session. |
381 | /// Anything stored like this will be available via `load_side_effects` in | |
abe05a73 | 382 | /// the next compilation session. |
0731742a XL |
383 | #[inline(never)] |
384 | #[cold] | |
94222f64 XL |
385 | pub fn store_side_effects(&self, dep_node_index: DepNodeIndex, side_effects: QuerySideEffects) { |
386 | let mut current_side_effects = self.current_side_effects.borrow_mut(); | |
387 | let prev = current_side_effects.insert(dep_node_index, side_effects); | |
abe05a73 XL |
388 | debug_assert!(prev.is_none()); |
389 | } | |
390 | ||
ff7c6d11 | 391 | /// Returns the cached query result if there is something in the cache for |
9fa01778 | 392 | /// the given `SerializedDepNodeIndex`; otherwise returns `None`. |
6a06907d | 393 | pub fn try_load_query_result<'tcx, T>( |
dc9dc135 | 394 | &self, |
3dfed10e | 395 | tcx: TyCtxt<'tcx>, |
dc9dc135 XL |
396 | dep_node_index: SerializedDepNodeIndex, |
397 | ) -> Option<T> | |
398 | where | |
3dfed10e | 399 | T: for<'a> Decodable<CacheDecoder<'a, 'tcx>>, |
abe05a73 | 400 | { |
5099ac24 | 401 | self.load_indexed(tcx, dep_node_index, &self.query_result_index) |
ff7c6d11 XL |
402 | } |
403 | ||
94222f64 | 404 | /// Stores side effect emitted during computation of an anonymous query. |
ff7c6d11 XL |
405 | /// Since many anonymous queries can share the same `DepNode`, we aggregate |
406 | /// them -- as opposed to regular queries where we assume that there is a | |
407 | /// 1:1 relationship between query-key and `DepNode`. | |
0731742a XL |
408 | #[inline(never)] |
409 | #[cold] | |
94222f64 | 410 | pub fn store_side_effects_for_anon_node( |
dfeec247 XL |
411 | &self, |
412 | dep_node_index: DepNodeIndex, | |
94222f64 | 413 | side_effects: QuerySideEffects, |
dfeec247 | 414 | ) { |
94222f64 | 415 | let mut current_side_effects = self.current_side_effects.borrow_mut(); |
ff7c6d11 | 416 | |
94222f64 XL |
417 | let x = current_side_effects.entry(dep_node_index).or_default(); |
418 | x.append(side_effects); | |
ff7c6d11 XL |
419 | } |
420 | ||
dc9dc135 XL |
421 | fn load_indexed<'tcx, T>( |
422 | &self, | |
423 | tcx: TyCtxt<'tcx>, | |
424 | dep_node_index: SerializedDepNodeIndex, | |
425 | index: &FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>, | |
dc9dc135 XL |
426 | ) -> Option<T> |
427 | where | |
3dfed10e | 428 | T: for<'a> Decodable<CacheDecoder<'a, 'tcx>>, |
ff7c6d11 | 429 | { |
0731742a | 430 | let pos = index.get(&dep_node_index).cloned()?; |
abe05a73 | 431 | |
5099ac24 | 432 | self.with_decoder(tcx, pos, |decoder| Some(decode_tagged(decoder, dep_node_index))) |
3dfed10e XL |
433 | } |
434 | ||
c295e0f8 | 435 | fn with_decoder<'a, 'tcx, T, F: for<'s> FnOnce(&mut CacheDecoder<'s, 'tcx>) -> T>( |
3dfed10e XL |
436 | &'sess self, |
437 | tcx: TyCtxt<'tcx>, | |
438 | pos: AbsoluteBytePos, | |
439 | f: F, | |
440 | ) -> T | |
441 | where | |
442 | T: Decodable<CacheDecoder<'a, 'tcx>>, | |
443 | { | |
c295e0f8 | 444 | let serialized_data = self.serialized_data.read(); |
abe05a73 | 445 | let mut decoder = CacheDecoder { |
ff7c6d11 | 446 | tcx, |
923072b8 | 447 | opaque: MemDecoder::new(serialized_data.as_deref().unwrap_or(&[]), pos.to_usize()), |
b7449926 | 448 | source_map: self.source_map, |
0531ce1d | 449 | file_index_to_file: &self.file_index_to_file, |
ff7c6d11 | 450 | file_index_to_stable_id: &self.file_index_to_stable_id, |
94b46f34 | 451 | alloc_decoding_session: self.alloc_decoding_state.new_decoding_session(), |
3dfed10e XL |
452 | syntax_contexts: &self.syntax_contexts, |
453 | expn_data: &self.expn_data, | |
136023e0 | 454 | foreign_expn_data: &self.foreign_expn_data, |
3dfed10e | 455 | hygiene_context: &self.hygiene_context, |
abe05a73 | 456 | }; |
3dfed10e | 457 | f(&mut decoder) |
abe05a73 | 458 | } |
abe05a73 XL |
459 | } |
460 | ||
abe05a73 XL |
461 | //- DECODING ------------------------------------------------------------------- |
462 | ||
fc512014 | 463 | /// A decoder that can read from the incremental compilation cache. It is similar to the one |
e1599b0c XL |
464 | /// we use for crate metadata decoding in that it can rebase spans and eventually |
465 | /// will also handle things that contain `Ty` instances. | |
6a06907d | 466 | pub struct CacheDecoder<'a, 'tcx> { |
dc9dc135 | 467 | tcx: TyCtxt<'tcx>, |
923072b8 | 468 | opaque: MemDecoder<'a>, |
dc9dc135 | 469 | source_map: &'a SourceMap, |
dc9dc135 | 470 | file_index_to_file: &'a Lock<FxHashMap<SourceFileIndex, Lrc<SourceFile>>>, |
17df50a5 | 471 | file_index_to_stable_id: &'a FxHashMap<SourceFileIndex, EncodedSourceFileId>, |
dc9dc135 | 472 | alloc_decoding_session: AllocDecodingSession<'a>, |
3dfed10e | 473 | syntax_contexts: &'a FxHashMap<u32, AbsoluteBytePos>, |
136023e0 XL |
474 | expn_data: &'a UnhashMap<ExpnHash, AbsoluteBytePos>, |
475 | foreign_expn_data: &'a UnhashMap<ExpnHash, u32>, | |
3dfed10e | 476 | hygiene_context: &'a HygieneDecodeContext, |
abe05a73 XL |
477 | } |
478 | ||
dc9dc135 | 479 | impl<'a, 'tcx> CacheDecoder<'a, 'tcx> { |
b7449926 | 480 | fn file_index_to_file(&self, index: SourceFileIndex) -> Lrc<SourceFile> { |
ff7c6d11 | 481 | let CacheDecoder { |
c295e0f8 | 482 | tcx, |
0531ce1d | 483 | ref file_index_to_file, |
ff7c6d11 | 484 | ref file_index_to_stable_id, |
b7449926 | 485 | ref source_map, |
ff7c6d11 XL |
486 | .. |
487 | } = *self; | |
488 | ||
dfeec247 XL |
489 | file_index_to_file |
490 | .borrow_mut() | |
491 | .entry(index) | |
492 | .or_insert_with(|| { | |
c295e0f8 | 493 | let stable_id = file_index_to_stable_id[&index].translate(tcx); |
a2a8927a XL |
494 | |
495 | // If this `SourceFile` is from a foreign crate, then make sure | |
496 | // that we've imported all of the source files from that crate. | |
497 | // This has usually already been done during macro invocation. | |
498 | // However, when encoding query results like `TypeckResults`, | |
499 | // we might encode an `AdtDef` for a foreign type (because it | |
500 | // was referenced in the body of the function). There is no guarantee | |
501 | // that we will load the source files from that crate during macro | |
502 | // expansion, so we use `import_source_files` to ensure that the foreign | |
503 | // source files are actually imported before we call `source_file_by_stable_id`. | |
504 | if stable_id.cnum != LOCAL_CRATE { | |
505 | self.tcx.cstore_untracked().import_source_files(self.tcx.sess, stable_id.cnum); | |
506 | } | |
507 | ||
dfeec247 XL |
508 | source_map |
509 | .source_file_by_stable_id(stable_id) | |
510 | .expect("failed to lookup `SourceFile` in new context") | |
511 | }) | |
512 | .clone() | |
ff7c6d11 XL |
513 | } |
514 | } | |
515 | ||
516 | trait DecoderWithPosition: Decoder { | |
517 | fn position(&self) -> usize; | |
518 | } | |
519 | ||
923072b8 | 520 | impl<'a> DecoderWithPosition for MemDecoder<'a> { |
ff7c6d11 XL |
521 | fn position(&self) -> usize { |
522 | self.position() | |
523 | } | |
524 | } | |
abe05a73 | 525 | |
dc9dc135 | 526 | impl<'a, 'tcx> DecoderWithPosition for CacheDecoder<'a, 'tcx> { |
ff7c6d11 XL |
527 | fn position(&self) -> usize { |
528 | self.opaque.position() | |
abe05a73 XL |
529 | } |
530 | } | |
531 | ||
e1599b0c | 532 | // Decodes something that was encoded with `encode_tagged()` and verify that the |
abe05a73 | 533 | // tag matches and the correct amount of bytes was read. |
5099ac24 | 534 | fn decode_tagged<D, T, V>(decoder: &mut D, expected_tag: T) -> V |
dc9dc135 | 535 | where |
29967ef6 | 536 | T: Decodable<D> + Eq + std::fmt::Debug, |
3dfed10e | 537 | V: Decodable<D>, |
dc9dc135 | 538 | D: DecoderWithPosition, |
abe05a73 XL |
539 | { |
540 | let start_pos = decoder.position(); | |
541 | ||
5099ac24 | 542 | let actual_tag = T::decode(decoder); |
abe05a73 | 543 | assert_eq!(actual_tag, expected_tag); |
5099ac24 | 544 | let value = V::decode(decoder); |
abe05a73 XL |
545 | let end_pos = decoder.position(); |
546 | ||
5099ac24 | 547 | let expected_len: u64 = Decodable::decode(decoder); |
abe05a73 XL |
548 | assert_eq!((end_pos - start_pos) as u64, expected_len); |
549 | ||
5099ac24 | 550 | value |
abe05a73 XL |
551 | } |
552 | ||
923072b8 FG |
553 | impl<'a, 'tcx> TyDecoder for CacheDecoder<'a, 'tcx> { |
554 | type I = TyCtxt<'tcx>; | |
3dfed10e XL |
555 | const CLEAR_CROSS_CRATE: bool = false; |
556 | ||
abe05a73 | 557 | #[inline] |
923072b8 | 558 | fn interner(&self) -> TyCtxt<'tcx> { |
ff7c6d11 | 559 | self.tcx |
abe05a73 XL |
560 | } |
561 | ||
562 | #[inline] | |
563 | fn position(&self) -> usize { | |
564 | self.opaque.position() | |
565 | } | |
566 | ||
567 | #[inline] | |
568 | fn peek_byte(&self) -> u8 { | |
569 | self.opaque.data[self.opaque.position()] | |
570 | } | |
571 | ||
5099ac24 | 572 | fn cached_ty_for_shorthand<F>(&mut self, shorthand: usize, or_insert_with: F) -> Ty<'tcx> |
dfeec247 | 573 | where |
5099ac24 | 574 | F: FnOnce(&mut Self) -> Ty<'tcx>, |
abe05a73 | 575 | { |
923072b8 | 576 | let tcx = self.tcx; |
abe05a73 | 577 | |
17df50a5 | 578 | let cache_key = ty::CReaderCacheKey { cnum: None, pos: shorthand }; |
abe05a73 | 579 | |
f035d41b | 580 | if let Some(&ty) = tcx.ty_rcache.borrow().get(&cache_key) { |
5099ac24 | 581 | return ty; |
abe05a73 XL |
582 | } |
583 | ||
5099ac24 | 584 | let ty = or_insert_with(self); |
e1599b0c | 585 | // This may overwrite the entry, but it should overwrite with the same value. |
f035d41b | 586 | tcx.ty_rcache.borrow_mut().insert_same(cache_key, ty); |
5099ac24 | 587 | ty |
abe05a73 XL |
588 | } |
589 | ||
590 | fn with_position<F, R>(&mut self, pos: usize, f: F) -> R | |
dfeec247 XL |
591 | where |
592 | F: FnOnce(&mut Self) -> R, | |
abe05a73 XL |
593 | { |
594 | debug_assert!(pos < self.opaque.data.len()); | |
595 | ||
923072b8 | 596 | let new_opaque = MemDecoder::new(self.opaque.data, pos); |
abe05a73 XL |
597 | let old_opaque = mem::replace(&mut self.opaque, new_opaque); |
598 | let r = f(self); | |
599 | self.opaque = old_opaque; | |
600 | r | |
601 | } | |
602 | ||
5099ac24 | 603 | fn decode_alloc_id(&mut self) -> interpret::AllocId { |
94b46f34 XL |
604 | let alloc_decoding_session = self.alloc_decoding_session; |
605 | alloc_decoding_session.decode_alloc_id(self) | |
0531ce1d XL |
606 | } |
607 | } | |
4462d4a0 | 608 | |
136023e0 | 609 | rustc_middle::implement_ty_decoder!(CacheDecoder<'a, 'tcx>); |
3dfed10e | 610 | |
5869c6ff XL |
611 | // This ensures that the `Decodable<opaque::Decoder>::decode` specialization for `Vec<u8>` is used |
612 | // when a `CacheDecoder` is passed to `Decodable::decode`. Unfortunately, we have to manually opt | |
613 | // into specializations this way, given how `CacheDecoder` and the decoding traits currently work. | |
614 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Vec<u8> { | |
5099ac24 | 615 | fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { |
5869c6ff XL |
616 | Decodable::decode(&mut d.opaque) |
617 | } | |
618 | } | |
619 | ||
3dfed10e | 620 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for SyntaxContext { |
5099ac24 | 621 | fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Self { |
3dfed10e XL |
622 | let syntax_contexts = decoder.syntax_contexts; |
623 | rustc_span::hygiene::decode_syntax_context(decoder, decoder.hygiene_context, |this, id| { | |
624 | // This closure is invoked if we haven't already decoded the data for the `SyntaxContext` we are deserializing. | |
625 | // We look up the position of the associated `SyntaxData` and decode it. | |
626 | let pos = syntax_contexts.get(&id).unwrap(); | |
627 | this.with_position(pos.to_usize(), |decoder| { | |
5099ac24 FG |
628 | let data: SyntaxContextData = decode_tagged(decoder, TAG_SYNTAX_CONTEXT); |
629 | data | |
3dfed10e XL |
630 | }) |
631 | }) | |
632 | } | |
633 | } | |
634 | ||
635 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId { | |
5099ac24 FG |
636 | fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Self { |
637 | let hash = ExpnHash::decode(decoder); | |
136023e0 | 638 | if hash.is_root() { |
5099ac24 | 639 | return ExpnId::root(); |
136023e0 XL |
640 | } |
641 | ||
642 | if let Some(expn_id) = ExpnId::from_hash(hash) { | |
5099ac24 | 643 | return expn_id; |
136023e0 XL |
644 | } |
645 | ||
c295e0f8 | 646 | let krate = decoder.tcx.stable_crate_id_to_crate_num(hash.stable_crate_id()); |
136023e0 XL |
647 | |
648 | let expn_id = if krate == LOCAL_CRATE { | |
649 | // We look up the position of the associated `ExpnData` and decode it. | |
650 | let pos = decoder | |
651 | .expn_data | |
652 | .get(&hash) | |
653 | .unwrap_or_else(|| panic!("Bad hash {:?} (map {:?})", hash, decoder.expn_data)); | |
654 | ||
655 | let data: ExpnData = decoder | |
5099ac24 | 656 | .with_position(pos.to_usize(), |decoder| decode_tagged(decoder, TAG_EXPN_DATA)); |
c295e0f8 XL |
657 | let expn_id = rustc_span::hygiene::register_local_expn_id(data, hash); |
658 | ||
659 | #[cfg(debug_assertions)] | |
660 | { | |
661 | use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; | |
064997fb FG |
662 | let local_hash: u64 = decoder.tcx.with_stable_hashing_context(|mut hcx| { |
663 | let mut hasher = StableHasher::new(); | |
664 | expn_id.expn_data().hash_stable(&mut hcx, &mut hasher); | |
665 | hasher.finish() | |
c295e0f8 | 666 | }); |
c295e0f8 XL |
667 | debug_assert_eq!(hash.local_hash(), local_hash); |
668 | } | |
669 | ||
670 | expn_id | |
136023e0 XL |
671 | } else { |
672 | let index_guess = decoder.foreign_expn_data[&hash]; | |
c295e0f8 XL |
673 | decoder.tcx.cstore_untracked().expn_hash_to_expn_id( |
674 | decoder.tcx.sess, | |
675 | krate, | |
676 | index_guess, | |
677 | hash, | |
678 | ) | |
136023e0 XL |
679 | }; |
680 | ||
c295e0f8 | 681 | debug_assert_eq!(expn_id.krate, krate); |
5099ac24 | 682 | expn_id |
3dfed10e XL |
683 | } |
684 | } | |
685 | ||
686 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span { | |
5099ac24 FG |
687 | fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Self { |
688 | let ctxt = SyntaxContext::decode(decoder); | |
689 | let parent = Option::<LocalDefId>::decode(decoder); | |
690 | let tag: u8 = Decodable::decode(decoder); | |
ff7c6d11 | 691 | |
5869c6ff | 692 | if tag == TAG_PARTIAL_SPAN { |
5099ac24 | 693 | return Span::new(BytePos(0), BytePos(0), ctxt, parent); |
c295e0f8 | 694 | } else if tag == TAG_RELATIVE_SPAN { |
5099ac24 FG |
695 | let dlo = u32::decode(decoder); |
696 | let dto = u32::decode(decoder); | |
c295e0f8 | 697 | |
923072b8 | 698 | let enclosing = decoder.tcx.source_span_untracked(parent.unwrap()).data_untracked(); |
c295e0f8 XL |
699 | let span = Span::new( |
700 | enclosing.lo + BytePos::from_u32(dlo), | |
701 | enclosing.lo + BytePos::from_u32(dto), | |
702 | ctxt, | |
703 | parent, | |
704 | ); | |
705 | ||
5099ac24 | 706 | return span; |
ff7c6d11 | 707 | } else { |
5869c6ff | 708 | debug_assert_eq!(tag, TAG_FULL_SPAN); |
abe05a73 XL |
709 | } |
710 | ||
5099ac24 FG |
711 | let file_lo_index = SourceFileIndex::decode(decoder); |
712 | let line_lo = usize::decode(decoder); | |
713 | let col_lo = BytePos::decode(decoder); | |
714 | let len = BytePos::decode(decoder); | |
ff7c6d11 | 715 | |
3dfed10e | 716 | let file_lo = decoder.file_index_to_file(file_lo_index); |
923072b8 | 717 | let lo = file_lo.lines(|lines| lines[line_lo - 1] + col_lo); |
ff7c6d11 XL |
718 | let hi = lo + len; |
719 | ||
5099ac24 | 720 | Span::new(lo, hi, ctxt, parent) |
abe05a73 XL |
721 | } |
722 | } | |
723 | ||
f2b60f7d FG |
724 | // copy&paste impl from rustc_metadata |
725 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Symbol { | |
726 | fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { | |
727 | let tag = d.read_u8(); | |
728 | ||
729 | match tag { | |
730 | SYMBOL_STR => { | |
731 | let s = d.read_str(); | |
732 | Symbol::intern(s) | |
733 | } | |
734 | SYMBOL_OFFSET => { | |
735 | // read str offset | |
736 | let pos = d.read_usize(); | |
737 | let old_pos = d.opaque.position(); | |
738 | ||
739 | // move to str ofset and read | |
740 | d.opaque.set_position(pos); | |
741 | let s = d.read_str(); | |
742 | let sym = Symbol::intern(s); | |
743 | ||
744 | // restore position | |
745 | d.opaque.set_position(old_pos); | |
746 | ||
747 | sym | |
748 | } | |
749 | SYMBOL_PREINTERNED => { | |
750 | let symbol_index = d.read_u32(); | |
751 | Symbol::new_from_decoded(symbol_index) | |
752 | } | |
753 | _ => unreachable!(), | |
754 | } | |
755 | } | |
756 | } | |
757 | ||
3dfed10e | 758 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for CrateNum { |
5099ac24 FG |
759 | fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { |
760 | let stable_id = StableCrateId::decode(d); | |
c295e0f8 | 761 | let cnum = d.tcx.stable_crate_id_to_crate_num(stable_id); |
5099ac24 | 762 | cnum |
e1599b0c XL |
763 | } |
764 | } | |
765 | ||
abe05a73 | 766 | // This impl makes sure that we get a runtime error when we try decode a |
e1599b0c XL |
767 | // `DefIndex` that is not contained in a `DefId`. Such a case would be problematic |
768 | // because we would not know how to transform the `DefIndex` to the current | |
abe05a73 | 769 | // context. |
3dfed10e | 770 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefIndex { |
5099ac24 FG |
771 | fn decode(_d: &mut CacheDecoder<'a, 'tcx>) -> DefIndex { |
772 | panic!("trying to decode `DefIndex` outside the context of a `DefId`") | |
abe05a73 XL |
773 | } |
774 | } | |
775 | ||
e1599b0c XL |
776 | // Both the `CrateNum` and the `DefIndex` of a `DefId` can change in between two |
777 | // compilation sessions. We use the `DefPathHash`, which is stable across | |
778 | // sessions, to map the old `DefId` to the new one. | |
3dfed10e | 779 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefId { |
5099ac24 | 780 | fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { |
e1599b0c | 781 | // Load the `DefPathHash` which is was we encoded the `DefId` as. |
5099ac24 | 782 | let def_path_hash = DefPathHash::decode(d); |
abe05a73 | 783 | |
e1599b0c | 784 | // Using the `DefPathHash`, we can lookup the new `DefId`. |
fc512014 XL |
785 | // Subtle: We only encode a `DefId` as part of a query result. |
786 | // If we get to this point, then all of the query inputs were green, | |
787 | // which means that the definition with this hash is guaranteed to | |
788 | // still exist in the current compilation session. | |
923072b8 | 789 | d.tcx.def_path_hash_to_def_id(def_path_hash, &mut || { |
9c376795 | 790 | panic!("Failed to convert DefPathHash {def_path_hash:?}") |
5099ac24 | 791 | }) |
abe05a73 XL |
792 | } |
793 | } | |
794 | ||
2b03887a | 795 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx UnordSet<LocalDefId> { |
5099ac24 | 796 | fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { |
3dfed10e XL |
797 | RefDecodable::decode(d) |
798 | } | |
799 | } | |
800 | ||
f2b60f7d FG |
801 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx FxHashMap<DefId, Ty<'tcx>> { |
802 | fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { | |
803 | RefDecodable::decode(d) | |
804 | } | |
805 | } | |
806 | ||
3dfed10e XL |
807 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> |
808 | for &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>> | |
809 | { | |
5099ac24 | 810 | fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { |
3dfed10e XL |
811 | RefDecodable::decode(d) |
812 | } | |
813 | } | |
814 | ||
487cf647 | 815 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] { |
5099ac24 | 816 | fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { |
1b1a35ee XL |
817 | RefDecodable::decode(d) |
818 | } | |
819 | } | |
820 | ||
487cf647 | 821 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Clause<'tcx>, Span)] { |
5099ac24 | 822 | fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { |
3dfed10e XL |
823 | RefDecodable::decode(d) |
824 | } | |
825 | } | |
826 | ||
827 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [rustc_ast::InlineAsmTemplatePiece] { | |
5099ac24 | 828 | fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { |
3dfed10e XL |
829 | RefDecodable::decode(d) |
830 | } | |
831 | } | |
832 | ||
923072b8 FG |
833 | macro_rules! impl_ref_decoder { |
834 | (<$tcx:tt> $($ty:ty,)*) => { | |
835 | $(impl<'a, $tcx> Decodable<CacheDecoder<'a, $tcx>> for &$tcx [$ty] { | |
836 | fn decode(d: &mut CacheDecoder<'a, $tcx>) -> Self { | |
837 | RefDecodable::decode(d) | |
838 | } | |
839 | })* | |
840 | }; | |
2c00a5a8 XL |
841 | } |
842 | ||
923072b8 FG |
843 | impl_ref_decoder! {<'tcx> |
844 | Span, | |
845 | rustc_ast::Attribute, | |
846 | rustc_span::symbol::Ident, | |
847 | ty::Variance, | |
848 | rustc_span::def_id::DefId, | |
849 | rustc_span::def_id::LocalDefId, | |
850 | (rustc_middle::middle::exported_symbols::ExportedSymbol<'tcx>, rustc_middle::middle::exported_symbols::SymbolExportInfo), | |
2b03887a | 851 | ty::DeducedParamAttrs, |
5869c6ff XL |
852 | } |
853 | ||
923072b8 | 854 | //- ENCODING ------------------------------------------------------------------- |
5869c6ff | 855 | |
fc512014 | 856 | /// An encoder that can write to the incremental compilation cache. |
923072b8 | 857 | pub struct CacheEncoder<'a, 'tcx> { |
dc9dc135 | 858 | tcx: TyCtxt<'tcx>, |
923072b8 | 859 | encoder: FileEncoder, |
48663c56 | 860 | type_shorthands: FxHashMap<Ty<'tcx>, usize>, |
5869c6ff | 861 | predicate_shorthands: FxHashMap<ty::PredicateKind<'tcx>, usize>, |
3dfed10e | 862 | interpret_allocs: FxIndexSet<interpret::AllocId>, |
b7449926 XL |
863 | source_map: CachingSourceMapView<'tcx>, |
864 | file_to_file_index: FxHashMap<*const SourceFile, SourceFileIndex>, | |
3dfed10e | 865 | hygiene_context: &'a HygieneEncodeContext, |
f2b60f7d | 866 | symbol_table: FxHashMap<Symbol, usize>, |
abe05a73 XL |
867 | } |
868 | ||
923072b8 | 869 | impl<'a, 'tcx> CacheEncoder<'a, 'tcx> { |
b7449926 XL |
870 | fn source_file_index(&mut self, source_file: Lrc<SourceFile>) -> SourceFileIndex { |
871 | self.file_to_file_index[&(&*source_file as *const SourceFile)] | |
ff7c6d11 XL |
872 | } |
873 | ||
abe05a73 XL |
874 | /// Encode something with additional information that allows to do some |
875 | /// sanity checks when decoding the data again. This method will first | |
876 | /// encode the specified tag, then the given value, then the number of | |
877 | /// bytes taken up by tag and value. On decoding, we can then verify that | |
878 | /// we get the expected tag and read the expected number of bytes. | |
923072b8 | 879 | fn encode_tagged<T: Encodable<Self>, V: Encodable<Self>>(&mut self, tag: T, value: &V) { |
abe05a73 XL |
880 | let start_pos = self.position(); |
881 | ||
923072b8 FG |
882 | tag.encode(self); |
883 | value.encode(self); | |
abe05a73 XL |
884 | |
885 | let end_pos = self.position(); | |
923072b8 FG |
886 | ((end_pos - start_pos) as u64).encode(self); |
887 | } | |
888 | ||
889 | fn finish(self) -> Result<usize, io::Error> { | |
890 | self.encoder.finish() | |
abe05a73 XL |
891 | } |
892 | } | |
893 | ||
923072b8 FG |
894 | impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for SyntaxContext { |
895 | fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) { | |
896 | rustc_span::hygiene::raw_encode_syntax_context(*self, s.hygiene_context, s); | |
3dfed10e XL |
897 | } |
898 | } | |
0531ce1d | 899 | |
923072b8 FG |
900 | impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for ExpnId { |
901 | fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) { | |
136023e0 | 902 | s.hygiene_context.schedule_expn_data_for_encoding(*self); |
923072b8 | 903 | self.expn_hash().encode(s); |
0531ce1d XL |
904 | } |
905 | } | |
906 | ||
923072b8 FG |
907 | impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for Span { |
908 | fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) { | |
c295e0f8 | 909 | let span_data = self.data_untracked(); |
923072b8 FG |
910 | span_data.ctxt.encode(s); |
911 | span_data.parent.encode(s); | |
c295e0f8 XL |
912 | |
913 | if span_data.is_dummy() { | |
914 | return TAG_PARTIAL_SPAN.encode(s); | |
915 | } | |
916 | ||
917 | if let Some(parent) = span_data.parent { | |
923072b8 | 918 | let enclosing = s.tcx.source_span(parent).data_untracked(); |
c295e0f8 | 919 | if enclosing.contains(span_data) { |
923072b8 FG |
920 | TAG_RELATIVE_SPAN.encode(s); |
921 | (span_data.lo - enclosing.lo).to_u32().encode(s); | |
922 | (span_data.hi - enclosing.lo).to_u32().encode(s); | |
923 | return; | |
c295e0f8 | 924 | } |
ff7c6d11 XL |
925 | } |
926 | ||
5869c6ff XL |
927 | let pos = s.source_map.byte_pos_to_line_and_col(span_data.lo); |
928 | let partial_span = match &pos { | |
929 | Some((file_lo, _, _)) => !file_lo.contains(span_data.hi), | |
930 | None => true, | |
3dfed10e | 931 | }; |
ff7c6d11 | 932 | |
5869c6ff | 933 | if partial_span { |
c295e0f8 | 934 | return TAG_PARTIAL_SPAN.encode(s); |
ff7c6d11 XL |
935 | } |
936 | ||
5869c6ff XL |
937 | let (file_lo, line_lo, col_lo) = pos.unwrap(); |
938 | ||
ff7c6d11 XL |
939 | let len = span_data.hi - span_data.lo; |
940 | ||
3dfed10e | 941 | let source_file_index = s.source_file_index(file_lo); |
ff7c6d11 | 942 | |
923072b8 FG |
943 | TAG_FULL_SPAN.encode(s); |
944 | source_file_index.encode(s); | |
945 | line_lo.encode(s); | |
946 | col_lo.encode(s); | |
947 | len.encode(s); | |
ff7c6d11 XL |
948 | } |
949 | } | |
950 | ||
f2b60f7d FG |
951 | // copy&paste impl from rustc_metadata |
952 | impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for Symbol { | |
953 | fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) { | |
954 | // if symbol preinterned, emit tag and symbol index | |
955 | if self.is_preinterned() { | |
956 | s.encoder.emit_u8(SYMBOL_PREINTERNED); | |
957 | s.encoder.emit_u32(self.as_u32()); | |
958 | } else { | |
959 | // otherwise write it as string or as offset to it | |
960 | match s.symbol_table.entry(*self) { | |
961 | Entry::Vacant(o) => { | |
962 | s.encoder.emit_u8(SYMBOL_STR); | |
963 | let pos = s.encoder.position(); | |
964 | o.insert(pos); | |
965 | s.emit_str(self.as_str()); | |
966 | } | |
967 | Entry::Occupied(o) => { | |
9c376795 | 968 | let x = *o.get(); |
f2b60f7d FG |
969 | s.emit_u8(SYMBOL_OFFSET); |
970 | s.emit_usize(x); | |
971 | } | |
972 | } | |
973 | } | |
974 | } | |
975 | } | |
976 | ||
923072b8 FG |
977 | impl<'a, 'tcx> TyEncoder for CacheEncoder<'a, 'tcx> { |
978 | type I = TyCtxt<'tcx>; | |
3dfed10e | 979 | const CLEAR_CROSS_CRATE: bool = false; |
e1599b0c | 980 | |
abe05a73 | 981 | fn position(&self) -> usize { |
5869c6ff | 982 | self.encoder.position() |
abe05a73 | 983 | } |
3dfed10e XL |
984 | fn type_shorthands(&mut self) -> &mut FxHashMap<Ty<'tcx>, usize> { |
985 | &mut self.type_shorthands | |
abe05a73 | 986 | } |
5869c6ff | 987 | fn predicate_shorthands(&mut self) -> &mut FxHashMap<ty::PredicateKind<'tcx>, usize> { |
3dfed10e | 988 | &mut self.predicate_shorthands |
abe05a73 | 989 | } |
923072b8 | 990 | fn encode_alloc_id(&mut self, alloc_id: &interpret::AllocId) { |
3dfed10e | 991 | let (index, _) = self.interpret_allocs.insert_full(*alloc_id); |
abe05a73 | 992 | |
923072b8 | 993 | index.encode(self); |
abe05a73 XL |
994 | } |
995 | } | |
996 | ||
923072b8 FG |
997 | impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for CrateNum { |
998 | fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) { | |
999 | s.tcx.stable_crate_id(*self).encode(s); | |
17df50a5 XL |
1000 | } |
1001 | } | |
1002 | ||
923072b8 FG |
1003 | impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for DefId { |
1004 | fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) { | |
1005 | s.tcx.def_path_hash(*self).encode(s); | |
abe05a73 XL |
1006 | } |
1007 | } | |
1008 | ||
923072b8 FG |
1009 | impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for DefIndex { |
1010 | fn encode(&self, _: &mut CacheEncoder<'a, 'tcx>) { | |
e1599b0c | 1011 | bug!("encoding `DefIndex` without context"); |
abe05a73 XL |
1012 | } |
1013 | } | |
1014 | ||
abe05a73 XL |
1015 | macro_rules! encoder_methods { |
1016 | ($($name:ident($ty:ty);)*) => { | |
74b04a01 | 1017 | #[inline] |
923072b8 | 1018 | $(fn $name(&mut self, value: $ty) { |
abe05a73 XL |
1019 | self.encoder.$name(value) |
1020 | })* | |
1021 | } | |
1022 | } | |
1023 | ||
923072b8 | 1024 | impl<'a, 'tcx> Encoder for CacheEncoder<'a, 'tcx> { |
abe05a73 XL |
1025 | encoder_methods! { |
1026 | emit_usize(usize); | |
1027 | emit_u128(u128); | |
1028 | emit_u64(u64); | |
1029 | emit_u32(u32); | |
1030 | emit_u16(u16); | |
1031 | emit_u8(u8); | |
1032 | ||
1033 | emit_isize(isize); | |
1034 | emit_i128(i128); | |
1035 | emit_i64(i64); | |
1036 | emit_i32(i32); | |
1037 | emit_i16(i16); | |
1038 | emit_i8(i8); | |
1039 | ||
1040 | emit_bool(bool); | |
1041 | emit_f64(f64); | |
1042 | emit_f32(f32); | |
1043 | emit_char(char); | |
1044 | emit_str(&str); | |
cdc7bbd5 | 1045 | emit_raw_bytes(&[u8]); |
abe05a73 XL |
1046 | } |
1047 | } | |
1048 | ||
5869c6ff XL |
1049 | // This ensures that the `Encodable<opaque::FileEncoder>::encode` specialization for byte slices |
1050 | // is used when a `CacheEncoder` having an `opaque::FileEncoder` is passed to `Encodable::encode`. | |
1051 | // Unfortunately, we have to manually opt into specializations this way, given how `CacheEncoder` | |
1052 | // and the encoding traits currently work. | |
923072b8 FG |
1053 | impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for [u8] { |
1054 | fn encode(&self, e: &mut CacheEncoder<'a, 'tcx>) { | |
1055 | self.encode(&mut e.encoder); | |
5869c6ff XL |
1056 | } |
1057 | } | |
1058 | ||
6a06907d XL |
1059 | pub fn encode_query_results<'a, 'tcx, CTX, Q>( |
1060 | tcx: CTX, | |
923072b8 | 1061 | encoder: &mut CacheEncoder<'a, 'tcx>, |
94222f64 | 1062 | query_result_index: &mut EncodedDepNodeIndex, |
923072b8 | 1063 | ) where |
6a06907d | 1064 | CTX: QueryContext + 'tcx, |
487cf647 | 1065 | Q: super::QueryConfig<CTX>, |
923072b8 | 1066 | Q::Value: Encodable<CacheEncoder<'a, 'tcx>>, |
abe05a73 | 1067 | { |
74b04a01 | 1068 | let _timer = tcx |
6a06907d XL |
1069 | .dep_context() |
1070 | .profiler() | |
2b03887a | 1071 | .verbose_generic_activity_with_arg("encode_query_results_for", std::any::type_name::<Q>()); |
dfeec247 | 1072 | |
6a06907d XL |
1073 | assert!(Q::query_state(tcx).all_inactive()); |
1074 | let cache = Q::query_cache(tcx); | |
5e7ed085 | 1075 | cache.iter(&mut |key, value, dep_node| { |
3c0e092e | 1076 | if Q::cache_on_disk(*tcx.dep_context(), &key) { |
cdc7bbd5 XL |
1077 | let dep_node = SerializedDepNodeIndex::new(dep_node.index()); |
1078 | ||
1079 | // Record position of the cache entry. | |
1080 | query_result_index.push((dep_node, AbsoluteBytePos::new(encoder.encoder.position()))); | |
1081 | ||
1082 | // Encode the type check tables with the `SerializedDepNodeIndex` | |
1083 | // as tag. | |
923072b8 | 1084 | encoder.encode_tagged(dep_node, value); |
74b04a01 | 1085 | } |
cdc7bbd5 | 1086 | }); |
abe05a73 | 1087 | } |