]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/maps/on_disk_cache.rs
0d09692bc353000e70a75f19b00baf277841912f
[rust.git] / src / librustc / ty / maps / on_disk_cache.rs
1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
12 use errors::Diagnostic;
13 use hir;
14 use hir::def_id::{CrateNum, DefIndex, DefId, LocalDefId,
15                   RESERVED_FOR_INCR_COMP_CACHE, LOCAL_CRATE};
16 use hir::map::definitions::DefPathHash;
17 use ich::CachingCodemapView;
18 use middle::cstore::CrateStore;
19 use mir;
20 use rustc_data_structures::fx::FxHashMap;
21 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
22 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque,
23                       SpecializedDecoder, SpecializedEncoder,
24                       UseSpecializedDecodable, UseSpecializedEncodable};
25 use session::{CrateDisambiguator, Session};
26 use std::cell::RefCell;
27 use std::mem;
28 use std::rc::Rc;
29 use syntax::ast::NodeId;
30 use syntax::codemap::{CodeMap, StableFilemapId};
31 use syntax_pos::{BytePos, Span, DUMMY_SP, FileMap};
32 use syntax_pos::hygiene::{Mark, SyntaxContext, ExpnInfo};
33 use ty;
34 use ty::codec::{self as ty_codec, TyDecoder, TyEncoder};
35 use ty::context::TyCtxt;
36
37 const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE;
38
39 const TAG_CLEAR_CROSS_CRATE_CLEAR: u8 = 0;
40 const TAG_CLEAR_CROSS_CRATE_SET: u8 = 1;
41
42 const TAG_NO_EXPANSION_INFO: u8 = 0;
43 const TAG_EXPANSION_INFO_SHORTHAND: u8 = 1;
44 const TAG_EXPANSION_INFO_INLINE: u8 = 2;
45
46 const TAG_VALID_SPAN: u8 = 0;
47 const TAG_INVALID_SPAN: u8 = 1;
48
49 /// `OnDiskCache` provides an interface to incr. comp. data cached from the
50 /// previous compilation session. This data will eventually include the results
51 /// of a few selected queries (like `typeck_tables_of` and `mir_optimized`) and
52 /// any diagnostics that have been emitted during a query.
53 pub struct OnDiskCache<'sess> {
54
55     // The complete cache data in serialized form.
56     serialized_data: Vec<u8>,
57
58     // This field collects all Diagnostics emitted during the current
59     // compilation session.
60     current_diagnostics: RefCell<FxHashMap<DepNodeIndex, Vec<Diagnostic>>>,
61
62     prev_cnums: Vec<(u32, String, CrateDisambiguator)>,
63     cnum_map: RefCell<Option<IndexVec<CrateNum, Option<CrateNum>>>>,
64
65     codemap: &'sess CodeMap,
66     file_index_to_stable_id: FxHashMap<FileMapIndex, StableFilemapId>,
67
68     // These two fields caches that are populated lazily during decoding.
69     file_index_to_file: RefCell<FxHashMap<FileMapIndex, Rc<FileMap>>>,
70     synthetic_expansion_infos: RefCell<FxHashMap<AbsoluteBytePos, SyntaxContext>>,
71
72     // A map from dep-node to the position of the cached query result in
73     // `serialized_data`.
74     query_result_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
75
76     // A map from dep-node to the position of any associated diagnostics in
77     // `serialized_data`.
78     prev_diagnostics_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
79 }
80
81 // This type is used only for (de-)serialization.
82 #[derive(RustcEncodable, RustcDecodable)]
83 struct Footer {
84     file_index_to_stable_id: FxHashMap<FileMapIndex, StableFilemapId>,
85     prev_cnums: Vec<(u32, String, CrateDisambiguator)>,
86     query_result_index: EncodedQueryResultIndex,
87     diagnostics_index: EncodedQueryResultIndex,
88 }
89
90 type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
91 type EncodedDiagnosticsIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
92 type EncodedDiagnostics = Vec<Diagnostic>;
93
94 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
95 struct FileMapIndex(u32);
96
97 #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, RustcEncodable, RustcDecodable)]
98 struct AbsoluteBytePos(u32);
99
100 impl AbsoluteBytePos {
101     fn new(pos: usize) -> AbsoluteBytePos {
102         debug_assert!(pos <= ::std::u32::MAX as usize);
103         AbsoluteBytePos(pos as u32)
104     }
105
106     fn to_usize(self) -> usize {
107         self.0 as usize
108     }
109 }
110
111 impl<'sess> OnDiskCache<'sess> {
112     /// Create a new OnDiskCache instance from the serialized data in `data`.
113     pub fn new(sess: &'sess Session, data: Vec<u8>, start_pos: usize) -> OnDiskCache<'sess> {
114         debug_assert!(sess.opts.incremental.is_some());
115
116         // Wrapping in a scope so we can borrow `data`
117         let footer: Footer = {
118             let mut decoder = opaque::Decoder::new(&data[..], start_pos);
119
120             // Decode the *position* of the footer which can be found in the
121             // last 8 bytes of the file.
122             decoder.set_position(data.len() - IntEncodedWithFixedSize::ENCODED_SIZE);
123             let query_result_index_pos = IntEncodedWithFixedSize::decode(&mut decoder)
124                 .expect("Error while trying to decode query result index position.")
125                 .0 as usize;
126
127             // Decoder the file footer which contains all the lookup tables, etc.
128             decoder.set_position(query_result_index_pos);
129             decode_tagged(&mut decoder, TAG_FILE_FOOTER)
130                 .expect("Error while trying to decode query result index position.")
131         };
132
133         OnDiskCache {
134             serialized_data: data,
135             file_index_to_stable_id: footer.file_index_to_stable_id,
136             file_index_to_file: RefCell::new(FxHashMap()),
137             prev_cnums: footer.prev_cnums,
138             cnum_map: RefCell::new(None),
139             codemap: sess.codemap(),
140             current_diagnostics: RefCell::new(FxHashMap()),
141             query_result_index: footer.query_result_index.into_iter().collect(),
142             prev_diagnostics_index: footer.diagnostics_index.into_iter().collect(),
143             synthetic_expansion_infos: RefCell::new(FxHashMap()),
144         }
145     }
146
147     pub fn new_empty(codemap: &'sess CodeMap) -> OnDiskCache<'sess> {
148         OnDiskCache {
149             serialized_data: Vec::new(),
150             file_index_to_stable_id: FxHashMap(),
151             file_index_to_file: RefCell::new(FxHashMap()),
152             prev_cnums: vec![],
153             cnum_map: RefCell::new(None),
154             codemap,
155             current_diagnostics: RefCell::new(FxHashMap()),
156             query_result_index: FxHashMap(),
157             prev_diagnostics_index: FxHashMap(),
158             synthetic_expansion_infos: RefCell::new(FxHashMap()),
159         }
160     }
161
162     pub fn serialize<'a, 'tcx, E>(&self,
163                                   tcx: TyCtxt<'a, 'tcx, 'tcx>,
164                                   encoder: &mut E)
165                                   -> Result<(), E::Error>
166         where E: ty_codec::TyEncoder
167      {
168         // Serializing the DepGraph should not modify it:
169         let _in_ignore = tcx.dep_graph.in_ignore();
170
171         // Allocate FileMapIndices
172         let (file_to_file_index, file_index_to_stable_id) = {
173             let mut file_to_file_index = FxHashMap();
174             let mut file_index_to_stable_id = FxHashMap();
175
176             for (index, file) in tcx.sess.codemap().files().iter().enumerate() {
177                 let index = FileMapIndex(index as u32);
178                 let file_ptr: *const FileMap = &**file as *const _;
179                 file_to_file_index.insert(file_ptr, index);
180                 file_index_to_stable_id.insert(index, StableFilemapId::new(&file));
181             }
182
183             (file_to_file_index, file_index_to_stable_id)
184         };
185
186         let mut encoder = CacheEncoder {
187             tcx,
188             encoder,
189             type_shorthands: FxHashMap(),
190             predicate_shorthands: FxHashMap(),
191             expn_info_shorthands: FxHashMap(),
192             codemap: CachingCodemapView::new(tcx.sess.codemap()),
193             file_to_file_index,
194         };
195
196         // Load everything into memory so we can write it out to the on-disk
197         // cache. The vast majority of cacheable query results should already
198         // be in memory, so this should be a cheap operation.
199         tcx.dep_graph.exec_cache_promotions(tcx);
200
201         // Encode query results
202         let mut query_result_index = EncodedQueryResultIndex::new();
203
204         {
205             use ty::maps::queries::*;
206             let enc = &mut encoder;
207             let qri = &mut query_result_index;
208
209             // Encode TypeckTables
210             encode_query_results::<typeck_tables_of, _>(tcx, enc, qri)?;
211         }
212
213         // Encode diagnostics
214         let diagnostics_index = {
215             let mut diagnostics_index = EncodedDiagnosticsIndex::new();
216
217             for (dep_node_index, diagnostics) in self.current_diagnostics
218                                                      .borrow()
219                                                      .iter() {
220                 let pos = AbsoluteBytePos::new(encoder.position());
221                 // Let's make sure we get the expected type here:
222                 let diagnostics: &EncodedDiagnostics = diagnostics;
223                 let dep_node_index =
224                     SerializedDepNodeIndex::new(dep_node_index.index());
225                 encoder.encode_tagged(dep_node_index, diagnostics)?;
226                 diagnostics_index.push((dep_node_index, pos));
227             }
228
229             diagnostics_index
230         };
231
232         let sorted_cnums = sorted_cnums_including_local_crate(tcx);
233         let prev_cnums: Vec<_> = sorted_cnums.iter().map(|&cnum| {
234             let crate_name = tcx.original_crate_name(cnum).as_str().to_string();
235             let crate_disambiguator = tcx.crate_disambiguator(cnum);
236             (cnum.as_u32(), crate_name, crate_disambiguator)
237         }).collect();
238
239         // Encode the file footer
240         let footer_pos = encoder.position() as u64;
241         encoder.encode_tagged(TAG_FILE_FOOTER, &Footer {
242             file_index_to_stable_id,
243             prev_cnums,
244             query_result_index,
245             diagnostics_index,
246         })?;
247
248         // Encode the position of the footer as the last 8 bytes of the
249         // file so we know where to look for it.
250         IntEncodedWithFixedSize(footer_pos).encode(encoder.encoder)?;
251
252         // DO NOT WRITE ANYTHING TO THE ENCODER AFTER THIS POINT! The address
253         // of the footer must be the last thing in the data stream.
254
255         return Ok(());
256
257         fn sorted_cnums_including_local_crate(tcx: TyCtxt) -> Vec<CrateNum> {
258             let mut cnums = vec![LOCAL_CRATE];
259             cnums.extend_from_slice(&tcx.crates()[..]);
260             cnums.sort_unstable();
261             // Just to be sure...
262             cnums.dedup();
263             cnums
264         }
265     }
266
267     /// Load a diagnostic emitted during the previous compilation session.
268     pub fn load_diagnostics<'a, 'tcx>(&self,
269                                       tcx: TyCtxt<'a, 'tcx, 'tcx>,
270                                       dep_node_index: SerializedDepNodeIndex)
271                                       -> Vec<Diagnostic> {
272         let diagnostics: Option<EncodedDiagnostics> = self.load_indexed(
273             tcx,
274             dep_node_index,
275             &self.prev_diagnostics_index,
276             "diagnostics");
277
278         diagnostics.unwrap_or(Vec::new())
279     }
280
281     /// Store a diagnostic emitted during the current compilation session.
282     /// Anything stored like this will be available via `load_diagnostics` in
283     /// the next compilation session.
284     pub fn store_diagnostics(&self,
285                              dep_node_index: DepNodeIndex,
286                              diagnostics: Vec<Diagnostic>) {
287         let mut current_diagnostics = self.current_diagnostics.borrow_mut();
288         let prev = current_diagnostics.insert(dep_node_index, diagnostics);
289         debug_assert!(prev.is_none());
290     }
291
292     pub fn load_query_result<'a, 'tcx, T>(&self,
293                                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
294                                           dep_node_index: SerializedDepNodeIndex)
295                                           -> T
296         where T: Decodable
297     {
298         let result = self.load_indexed(tcx,
299                                        dep_node_index,
300                                        &self.query_result_index,
301                                        "query result");
302         if let Some(result) = result {
303             result
304         } else {
305             bug!("Could not find query result for key {:?}", dep_node_index)
306         }
307     }
308
309     /// Store a diagnostic emitted during computation of an anonymous query.
310     /// Since many anonymous queries can share the same `DepNode`, we aggregate
311     /// them -- as opposed to regular queries where we assume that there is a
312     /// 1:1 relationship between query-key and `DepNode`.
313     pub fn store_diagnostics_for_anon_node(&self,
314                                            dep_node_index: DepNodeIndex,
315                                            mut diagnostics: Vec<Diagnostic>) {
316         let mut current_diagnostics = self.current_diagnostics.borrow_mut();
317
318         let x = current_diagnostics.entry(dep_node_index).or_insert_with(|| {
319             mem::replace(&mut diagnostics, Vec::new())
320         });
321
322         x.extend(diagnostics.into_iter());
323     }
324
325     fn load_indexed<'a, 'tcx, T>(&self,
326                                  tcx: TyCtxt<'a, 'tcx, 'tcx>,
327                                  dep_node_index: SerializedDepNodeIndex,
328                                  index: &FxHashMap<SerializedDepNodeIndex,
329                                                    AbsoluteBytePos>,
330                                  debug_tag: &'static str)
331                                  -> Option<T>
332         where T: Decodable
333     {
334         let pos = if let Some(&pos) = index.get(&dep_node_index) {
335             pos
336         } else {
337             return None
338         };
339
340         let mut cnum_map = self.cnum_map.borrow_mut();
341         if cnum_map.is_none() {
342             *cnum_map = Some(Self::compute_cnum_map(tcx, &self.prev_cnums[..]));
343         }
344
345         let mut synthetic_expansion_infos = self.synthetic_expansion_infos.borrow_mut();
346         let mut file_index_to_file = self.file_index_to_file.borrow_mut();
347
348         let mut decoder = CacheDecoder {
349             tcx,
350             opaque: opaque::Decoder::new(&self.serialized_data[..], pos.to_usize()),
351             codemap: self.codemap,
352             cnum_map: cnum_map.as_ref().unwrap(),
353             file_index_to_file: &mut file_index_to_file,
354             file_index_to_stable_id: &self.file_index_to_stable_id,
355             synthetic_expansion_infos: &mut synthetic_expansion_infos,
356         };
357
358         match decode_tagged(&mut decoder, dep_node_index) {
359             Ok(value) => {
360                 Some(value)
361             }
362             Err(e) => {
363                 bug!("Could not decode cached {}: {}", debug_tag, e)
364             }
365         }
366     }
367
368     // This function builds mapping from previous-session-CrateNum to
369     // current-session-CrateNum. There might be CrateNums from the previous
370     // Session that don't occur in the current one. For these, the mapping
371     // maps to None.
372     fn compute_cnum_map(tcx: TyCtxt,
373                         prev_cnums: &[(u32, String, CrateDisambiguator)])
374                         -> IndexVec<CrateNum, Option<CrateNum>>
375     {
376         let _in_ignore = tcx.dep_graph.in_ignore();
377
378         let current_cnums = tcx.all_crate_nums(LOCAL_CRATE).iter().map(|&cnum| {
379             let crate_name = tcx.original_crate_name(cnum)
380                                 .as_str()
381                                 .to_string();
382             let crate_disambiguator = tcx.crate_disambiguator(cnum);
383             ((crate_name, crate_disambiguator), cnum)
384         }).collect::<FxHashMap<_,_>>();
385
386         let map_size = prev_cnums.iter()
387                                  .map(|&(cnum, ..)| cnum)
388                                  .max()
389                                  .unwrap_or(0) + 1;
390         let mut map = IndexVec::new();
391         map.resize(map_size as usize, None);
392
393         for &(prev_cnum, ref crate_name, crate_disambiguator) in prev_cnums {
394             let key = (crate_name.clone(), crate_disambiguator);
395             map[CrateNum::from_u32(prev_cnum)] = current_cnums.get(&key).cloned();
396         }
397
398         map[LOCAL_CRATE] = Some(LOCAL_CRATE);
399         map
400     }
401 }
402
403
404 //- DECODING -------------------------------------------------------------------
405
406 /// A decoder that can read the incr. comp. cache. It is similar to the one
407 /// we use for crate metadata decoding in that it can rebase spans and
408 /// eventually will also handle things that contain `Ty` instances.
409 struct CacheDecoder<'a, 'tcx: 'a, 'x> {
410     tcx: TyCtxt<'a, 'tcx, 'tcx>,
411     opaque: opaque::Decoder<'x>,
412     codemap: &'x CodeMap,
413     cnum_map: &'x IndexVec<CrateNum, Option<CrateNum>>,
414     synthetic_expansion_infos: &'x mut FxHashMap<AbsoluteBytePos, SyntaxContext>,
415     file_index_to_file: &'x mut FxHashMap<FileMapIndex, Rc<FileMap>>,
416     file_index_to_stable_id: &'x FxHashMap<FileMapIndex, StableFilemapId>,
417 }
418
419 impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> {
420     fn file_index_to_file(&mut self, index: FileMapIndex) -> Rc<FileMap> {
421         let CacheDecoder {
422             ref mut file_index_to_file,
423             ref file_index_to_stable_id,
424             ref codemap,
425             ..
426         } = *self;
427
428         file_index_to_file.entry(index).or_insert_with(|| {
429             let stable_id = file_index_to_stable_id[&index];
430             codemap.filemap_by_stable_id(stable_id)
431                    .expect("Failed to lookup FileMap in new context.")
432         }).clone()
433     }
434 }
435
436 trait DecoderWithPosition: Decoder {
437     fn position(&self) -> usize;
438 }
439
440 impl<'enc> DecoderWithPosition for opaque::Decoder<'enc> {
441     fn position(&self) -> usize {
442         self.position()
443     }
444 }
445
446 impl<'a, 'tcx, 'x> DecoderWithPosition for CacheDecoder<'a, 'tcx, 'x> {
447     fn position(&self) -> usize {
448         self.opaque.position()
449     }
450 }
451
452 // Decode something that was encoded with encode_tagged() and verify that the
453 // tag matches and the correct amount of bytes was read.
454 fn decode_tagged<'a, 'tcx, D, T, V>(decoder: &mut D,
455                                     expected_tag: T)
456                                     -> Result<V, D::Error>
457     where T: Decodable + Eq + ::std::fmt::Debug,
458           V: Decodable,
459           D: DecoderWithPosition,
460           'tcx: 'a,
461 {
462     let start_pos = decoder.position();
463
464     let actual_tag = T::decode(decoder)?;
465     assert_eq!(actual_tag, expected_tag);
466     let value = V::decode(decoder)?;
467     let end_pos = decoder.position();
468
469     let expected_len: u64 = Decodable::decode(decoder)?;
470     assert_eq!((end_pos - start_pos) as u64, expected_len);
471
472     Ok(value)
473 }
474
475
476 impl<'a, 'tcx: 'a, 'x> ty_codec::TyDecoder<'a, 'tcx> for CacheDecoder<'a, 'tcx, 'x> {
477
478     #[inline]
479     fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
480         self.tcx
481     }
482
483     #[inline]
484     fn position(&self) -> usize {
485         self.opaque.position()
486     }
487
488     #[inline]
489     fn peek_byte(&self) -> u8 {
490         self.opaque.data[self.opaque.position()]
491     }
492
493     fn cached_ty_for_shorthand<F>(&mut self,
494                                   shorthand: usize,
495                                   or_insert_with: F)
496                                   -> Result<ty::Ty<'tcx>, Self::Error>
497         where F: FnOnce(&mut Self) -> Result<ty::Ty<'tcx>, Self::Error>
498     {
499         let tcx = self.tcx();
500
501         let cache_key = ty::CReaderCacheKey {
502             cnum: RESERVED_FOR_INCR_COMP_CACHE,
503             pos: shorthand,
504         };
505
506         if let Some(&ty) = tcx.rcache.borrow().get(&cache_key) {
507             return Ok(ty);
508         }
509
510         let ty = or_insert_with(self)?;
511         tcx.rcache.borrow_mut().insert(cache_key, ty);
512         Ok(ty)
513     }
514
515     fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
516         where F: FnOnce(&mut Self) -> R
517     {
518         debug_assert!(pos < self.opaque.data.len());
519
520         let new_opaque = opaque::Decoder::new(self.opaque.data, pos);
521         let old_opaque = mem::replace(&mut self.opaque, new_opaque);
522         let r = f(self);
523         self.opaque = old_opaque;
524         r
525     }
526
527     fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum {
528         self.cnum_map[cnum].unwrap_or_else(|| {
529             bug!("Could not find new CrateNum for {:?}", cnum)
530         })
531     }
532 }
533
534 implement_ty_decoder!( CacheDecoder<'a, 'tcx, 'x> );
535
536 impl<'a, 'tcx, 'x> SpecializedDecoder<Span> for CacheDecoder<'a, 'tcx, 'x> {
537     fn specialized_decode(&mut self) -> Result<Span, Self::Error> {
538         let tag: u8 = Decodable::decode(self)?;
539
540         if tag == TAG_INVALID_SPAN {
541             return Ok(DUMMY_SP);
542         } else {
543             debug_assert_eq!(tag, TAG_VALID_SPAN);
544         }
545
546         let file_lo_index = FileMapIndex::decode(self)?;
547         let line_lo = usize::decode(self)?;
548         let col_lo = BytePos::decode(self)?;
549         let len = BytePos::decode(self)?;
550
551         let file_lo = self.file_index_to_file(file_lo_index);
552         let lo = file_lo.lines.borrow()[line_lo - 1] + col_lo;
553         let hi = lo + len;
554
555         let expn_info_tag = u8::decode(self)?;
556
557         let ctxt = match expn_info_tag {
558             TAG_NO_EXPANSION_INFO => {
559                 SyntaxContext::empty()
560             }
561             TAG_EXPANSION_INFO_INLINE => {
562                 let pos = AbsoluteBytePos::new(self.opaque.position());
563                 let expn_info: ExpnInfo = Decodable::decode(self)?;
564                 let ctxt = SyntaxContext::allocate_directly(expn_info);
565                 self.synthetic_expansion_infos.insert(pos, ctxt);
566                 ctxt
567             }
568             TAG_EXPANSION_INFO_SHORTHAND => {
569                 let pos = AbsoluteBytePos::decode(self)?;
570                 if let Some(ctxt) = self.synthetic_expansion_infos.get(&pos).cloned() {
571                     ctxt
572                 } else {
573                     let expn_info = self.with_position(pos.to_usize(), |this| {
574                          ExpnInfo::decode(this)
575                     })?;
576                     let ctxt = SyntaxContext::allocate_directly(expn_info);
577                     self.synthetic_expansion_infos.insert(pos, ctxt);
578                     ctxt
579                 }
580             }
581             _ => {
582                 unreachable!()
583             }
584         };
585
586         Ok(Span::new(lo, hi, ctxt))
587     }
588 }
589
590 // This impl makes sure that we get a runtime error when we try decode a
591 // DefIndex that is not contained in a DefId. Such a case would be problematic
592 // because we would not know how to transform the DefIndex to the current
593 // context.
594 impl<'a, 'tcx, 'x> SpecializedDecoder<DefIndex> for CacheDecoder<'a, 'tcx, 'x> {
595     fn specialized_decode(&mut self) -> Result<DefIndex, Self::Error> {
596         bug!("Trying to decode DefIndex outside the context of a DefId")
597     }
598 }
599
600 // Both the CrateNum and the DefIndex of a DefId can change in between two
601 // compilation sessions. We use the DefPathHash, which is stable across
602 // sessions, to map the old DefId to the new one.
603 impl<'a, 'tcx, 'x> SpecializedDecoder<DefId> for CacheDecoder<'a, 'tcx, 'x> {
604     #[inline]
605     fn specialized_decode(&mut self) -> Result<DefId, Self::Error> {
606         // Load the DefPathHash which is was we encoded the DefId as.
607         let def_path_hash = DefPathHash::decode(self)?;
608
609         // Using the DefPathHash, we can lookup the new DefId
610         Ok(self.tcx().def_path_hash_to_def_id.as_ref().unwrap()[&def_path_hash])
611     }
612 }
613
614 impl<'a, 'tcx, 'x> SpecializedDecoder<LocalDefId> for CacheDecoder<'a, 'tcx, 'x> {
615     #[inline]
616     fn specialized_decode(&mut self) -> Result<LocalDefId, Self::Error> {
617         Ok(LocalDefId::from_def_id(DefId::decode(self)?))
618     }
619 }
620
621 impl<'a, 'tcx, 'x> SpecializedDecoder<hir::HirId> for CacheDecoder<'a, 'tcx, 'x> {
622     fn specialized_decode(&mut self) -> Result<hir::HirId, Self::Error> {
623         // Load the DefPathHash which is was we encoded the DefIndex as.
624         let def_path_hash = DefPathHash::decode(self)?;
625
626         // Use the DefPathHash to map to the current DefId.
627         let def_id = self.tcx()
628                          .def_path_hash_to_def_id
629                          .as_ref()
630                          .unwrap()[&def_path_hash];
631
632         debug_assert!(def_id.is_local());
633
634         // The ItemLocalId needs no remapping.
635         let local_id = hir::ItemLocalId::decode(self)?;
636
637         // Reconstruct the HirId and look up the corresponding NodeId in the
638         // context of the current session.
639         Ok(hir::HirId {
640             owner: def_id.index,
641             local_id
642         })
643     }
644 }
645
646 // NodeIds are not stable across compilation sessions, so we store them in their
647 // HirId representation. This allows use to map them to the current NodeId.
648 impl<'a, 'tcx, 'x> SpecializedDecoder<NodeId> for CacheDecoder<'a, 'tcx, 'x> {
649     #[inline]
650     fn specialized_decode(&mut self) -> Result<NodeId, Self::Error> {
651         let hir_id = hir::HirId::decode(self)?;
652         Ok(self.tcx().hir.hir_to_node_id(hir_id))
653     }
654 }
655
656 impl<'a, 'tcx, 'x, T: Decodable> SpecializedDecoder<mir::ClearCrossCrate<T>>
657 for CacheDecoder<'a, 'tcx, 'x> {
658     #[inline]
659     fn specialized_decode(&mut self) -> Result<mir::ClearCrossCrate<T>, Self::Error> {
660         let discr = u8::decode(self)?;
661
662         match discr {
663             TAG_CLEAR_CROSS_CRATE_CLEAR => Ok(mir::ClearCrossCrate::Clear),
664             TAG_CLEAR_CROSS_CRATE_SET => {
665                 let val = T::decode(self)?;
666                 Ok(mir::ClearCrossCrate::Set(val))
667             }
668             _ => {
669                 unreachable!()
670             }
671         }
672     }
673 }
674
675 //- ENCODING -------------------------------------------------------------------
676
677 struct CacheEncoder<'enc, 'a, 'tcx, E>
678     where E: 'enc + ty_codec::TyEncoder,
679           'tcx: 'a,
680 {
681     tcx: TyCtxt<'a, 'tcx, 'tcx>,
682     encoder: &'enc mut E,
683     type_shorthands: FxHashMap<ty::Ty<'tcx>, usize>,
684     predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>,
685     expn_info_shorthands: FxHashMap<Mark, AbsoluteBytePos>,
686     codemap: CachingCodemapView<'tcx>,
687     file_to_file_index: FxHashMap<*const FileMap, FileMapIndex>,
688 }
689
690 impl<'enc, 'a, 'tcx, E> CacheEncoder<'enc, 'a, 'tcx, E>
691     where E: 'enc + ty_codec::TyEncoder
692 {
693     fn filemap_index(&mut self, filemap: Rc<FileMap>) -> FileMapIndex {
694         self.file_to_file_index[&(&*filemap as *const FileMap)]
695     }
696
697     /// Encode something with additional information that allows to do some
698     /// sanity checks when decoding the data again. This method will first
699     /// encode the specified tag, then the given value, then the number of
700     /// bytes taken up by tag and value. On decoding, we can then verify that
701     /// we get the expected tag and read the expected number of bytes.
702     fn encode_tagged<T: Encodable, V: Encodable>(&mut self,
703                                                  tag: T,
704                                                  value: &V)
705                                                  -> Result<(), E::Error>
706     {
707         use ty::codec::TyEncoder;
708         let start_pos = self.position();
709
710         tag.encode(self)?;
711         value.encode(self)?;
712
713         let end_pos = self.position();
714         ((end_pos - start_pos) as u64).encode(self)
715     }
716 }
717
718 impl<'enc, 'a, 'tcx, E> SpecializedEncoder<Span> for CacheEncoder<'enc, 'a, 'tcx, E>
719     where E: 'enc + ty_codec::TyEncoder
720 {
721     fn specialized_encode(&mut self, span: &Span) -> Result<(), Self::Error> {
722
723         if *span == DUMMY_SP {
724             return TAG_INVALID_SPAN.encode(self);
725         }
726
727         let span_data = span.data();
728
729         if span_data.hi < span_data.lo {
730             return TAG_INVALID_SPAN.encode(self);
731         }
732
733         let (file_lo, line_lo, col_lo) = match self.codemap
734                                                    .byte_pos_to_line_and_col(span_data.lo) {
735             Some(pos) => pos,
736             None => {
737                 return TAG_INVALID_SPAN.encode(self);
738             }
739         };
740
741         if !file_lo.contains(span_data.hi) {
742             return TAG_INVALID_SPAN.encode(self);
743         }
744
745         let len = span_data.hi - span_data.lo;
746
747         let filemap_index = self.filemap_index(file_lo);
748
749         TAG_VALID_SPAN.encode(self)?;
750         filemap_index.encode(self)?;
751         line_lo.encode(self)?;
752         col_lo.encode(self)?;
753         len.encode(self)?;
754
755         if span_data.ctxt == SyntaxContext::empty() {
756             TAG_NO_EXPANSION_INFO.encode(self)
757         } else {
758             let mark = span_data.ctxt.outer();
759
760             if let Some(expn_info) = mark.expn_info() {
761                 if let Some(pos) = self.expn_info_shorthands.get(&mark).cloned() {
762                     TAG_EXPANSION_INFO_SHORTHAND.encode(self)?;
763                     pos.encode(self)
764                 } else {
765                     TAG_EXPANSION_INFO_INLINE.encode(self)?;
766                     let pos = AbsoluteBytePos::new(self.position());
767                     self.expn_info_shorthands.insert(mark, pos);
768                     expn_info.encode(self)
769                 }
770             } else {
771                 TAG_NO_EXPANSION_INFO.encode(self)
772             }
773         }
774     }
775 }
776
777 impl<'enc, 'a, 'tcx, E> ty_codec::TyEncoder for CacheEncoder<'enc, 'a, 'tcx, E>
778     where E: 'enc + ty_codec::TyEncoder
779 {
780     #[inline]
781     fn position(&self) -> usize {
782         self.encoder.position()
783     }
784 }
785
786 impl<'enc, 'a, 'tcx, E> SpecializedEncoder<CrateNum> for CacheEncoder<'enc, 'a, 'tcx, E>
787     where E: 'enc + ty_codec::TyEncoder
788 {
789     #[inline]
790     fn specialized_encode(&mut self, cnum: &CrateNum) -> Result<(), Self::Error> {
791         self.emit_u32(cnum.as_u32())
792     }
793 }
794
795 impl<'enc, 'a, 'tcx, E> SpecializedEncoder<ty::Ty<'tcx>> for CacheEncoder<'enc, 'a, 'tcx, E>
796     where E: 'enc + ty_codec::TyEncoder
797 {
798     #[inline]
799     fn specialized_encode(&mut self, ty: &ty::Ty<'tcx>) -> Result<(), Self::Error> {
800         ty_codec::encode_with_shorthand(self, ty,
801             |encoder| &mut encoder.type_shorthands)
802     }
803 }
804
805 impl<'enc, 'a, 'tcx, E> SpecializedEncoder<ty::GenericPredicates<'tcx>>
806     for CacheEncoder<'enc, 'a, 'tcx, E>
807     where E: 'enc + ty_codec::TyEncoder
808 {
809     #[inline]
810     fn specialized_encode(&mut self,
811                           predicates: &ty::GenericPredicates<'tcx>)
812                           -> Result<(), Self::Error> {
813         ty_codec::encode_predicates(self, predicates,
814             |encoder| &mut encoder.predicate_shorthands)
815     }
816 }
817
818 impl<'enc, 'a, 'tcx, E> SpecializedEncoder<hir::HirId> for CacheEncoder<'enc, 'a, 'tcx, E>
819     where E: 'enc + ty_codec::TyEncoder
820 {
821     #[inline]
822     fn specialized_encode(&mut self, id: &hir::HirId) -> Result<(), Self::Error> {
823         let hir::HirId {
824             owner,
825             local_id,
826         } = *id;
827
828         let def_path_hash = self.tcx.hir.definitions().def_path_hash(owner);
829
830         def_path_hash.encode(self)?;
831         local_id.encode(self)
832     }
833 }
834
835
836 impl<'enc, 'a, 'tcx, E> SpecializedEncoder<DefId> for CacheEncoder<'enc, 'a, 'tcx, E>
837     where E: 'enc + ty_codec::TyEncoder
838 {
839     #[inline]
840     fn specialized_encode(&mut self, id: &DefId) -> Result<(), Self::Error> {
841         let def_path_hash = self.tcx.def_path_hash(*id);
842         def_path_hash.encode(self)
843     }
844 }
845
846 impl<'enc, 'a, 'tcx, E> SpecializedEncoder<LocalDefId> for CacheEncoder<'enc, 'a, 'tcx, E>
847     where E: 'enc + ty_codec::TyEncoder
848 {
849     #[inline]
850     fn specialized_encode(&mut self, id: &LocalDefId) -> Result<(), Self::Error> {
851         id.to_def_id().encode(self)
852     }
853 }
854
855 impl<'enc, 'a, 'tcx, E> SpecializedEncoder<DefIndex> for CacheEncoder<'enc, 'a, 'tcx, E>
856     where E: 'enc + ty_codec::TyEncoder
857 {
858     fn specialized_encode(&mut self, _: &DefIndex) -> Result<(), Self::Error> {
859         bug!("Encoding DefIndex without context.")
860     }
861 }
862
863 // NodeIds are not stable across compilation sessions, so we store them in their
864 // HirId representation. This allows use to map them to the current NodeId.
865 impl<'enc, 'a, 'tcx, E> SpecializedEncoder<NodeId> for CacheEncoder<'enc, 'a, 'tcx, E>
866     where E: 'enc + ty_codec::TyEncoder
867 {
868     #[inline]
869     fn specialized_encode(&mut self, node_id: &NodeId) -> Result<(), Self::Error> {
870         let hir_id = self.tcx.hir.node_to_hir_id(*node_id);
871         hir_id.encode(self)
872     }
873 }
874
875 impl<'enc, 'a, 'tcx, E, T> SpecializedEncoder<mir::ClearCrossCrate<T>>
876 for CacheEncoder<'enc, 'a, 'tcx, E>
877     where E: 'enc + ty_codec::TyEncoder,
878           T: Encodable,
879 {
880     #[inline]
881     fn specialized_encode(&mut self,
882                           val: &mir::ClearCrossCrate<T>)
883                           -> Result<(), Self::Error> {
884         match *val {
885             mir::ClearCrossCrate::Clear => {
886                 TAG_CLEAR_CROSS_CRATE_CLEAR.encode(self)
887             }
888             mir::ClearCrossCrate::Set(ref val) => {
889                 TAG_CLEAR_CROSS_CRATE_SET.encode(self)?;
890                 val.encode(self)
891             }
892         }
893     }
894 }
895
896 macro_rules! encoder_methods {
897     ($($name:ident($ty:ty);)*) => {
898         $(fn $name(&mut self, value: $ty) -> Result<(), Self::Error> {
899             self.encoder.$name(value)
900         })*
901     }
902 }
903
904 impl<'enc, 'a, 'tcx, E> Encoder for CacheEncoder<'enc, 'a, 'tcx, E>
905     where E: 'enc + ty_codec::TyEncoder
906 {
907     type Error = E::Error;
908
909     fn emit_nil(&mut self) -> Result<(), Self::Error> {
910         Ok(())
911     }
912
913     encoder_methods! {
914         emit_usize(usize);
915         emit_u128(u128);
916         emit_u64(u64);
917         emit_u32(u32);
918         emit_u16(u16);
919         emit_u8(u8);
920
921         emit_isize(isize);
922         emit_i128(i128);
923         emit_i64(i64);
924         emit_i32(i32);
925         emit_i16(i16);
926         emit_i8(i8);
927
928         emit_bool(bool);
929         emit_f64(f64);
930         emit_f32(f32);
931         emit_char(char);
932         emit_str(&str);
933     }
934 }
935
936 // An integer that will always encode to 8 bytes.
937 struct IntEncodedWithFixedSize(u64);
938
939 impl IntEncodedWithFixedSize {
940     pub const ENCODED_SIZE: usize = 8;
941 }
942
943 impl UseSpecializedEncodable for IntEncodedWithFixedSize {}
944 impl UseSpecializedDecodable for IntEncodedWithFixedSize {}
945
946 impl<'enc> SpecializedEncoder<IntEncodedWithFixedSize> for opaque::Encoder<'enc> {
947     fn specialized_encode(&mut self, x: &IntEncodedWithFixedSize) -> Result<(), Self::Error> {
948         let start_pos = self.position();
949         for i in 0 .. IntEncodedWithFixedSize::ENCODED_SIZE {
950             ((x.0 >> i * 8) as u8).encode(self)?;
951         }
952         let end_pos = self.position();
953         assert_eq!((end_pos - start_pos), IntEncodedWithFixedSize::ENCODED_SIZE);
954         Ok(())
955     }
956 }
957
958 impl<'enc> SpecializedDecoder<IntEncodedWithFixedSize> for opaque::Decoder<'enc> {
959     fn specialized_decode(&mut self) -> Result<IntEncodedWithFixedSize, Self::Error> {
960         let mut value: u64 = 0;
961         let start_pos = self.position();
962
963         for i in 0 .. IntEncodedWithFixedSize::ENCODED_SIZE {
964             let byte: u8 = Decodable::decode(self)?;
965             value |= (byte as u64) << (i * 8);
966         }
967
968         let end_pos = self.position();
969         assert_eq!((end_pos - start_pos), IntEncodedWithFixedSize::ENCODED_SIZE);
970
971         Ok(IntEncodedWithFixedSize(value))
972     }
973 }
974
975 fn encode_query_results<'enc, 'a, 'tcx, Q, E>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
976                                               encoder: &mut CacheEncoder<'enc, 'a, 'tcx, E>,
977                                               query_result_index: &mut EncodedQueryResultIndex)
978                                               -> Result<(), E::Error>
979     where Q: super::plumbing::GetCacheInternal<'tcx>,
980           E: 'enc + TyEncoder,
981           Q::Value: Encodable,
982 {
983     for (key, entry) in Q::get_cache_internal(tcx).map.iter() {
984         if Q::cache_on_disk(key.clone()) {
985             let dep_node = SerializedDepNodeIndex::new(entry.index.index());
986
987             // Record position of the cache entry
988             query_result_index.push((dep_node, AbsoluteBytePos::new(encoder.position())));
989
990             // Encode the type check tables with the SerializedDepNodeIndex
991             // as tag.
992             encoder.encode_tagged(dep_node, &entry.value)?;
993         }
994     }
995
996     Ok(())
997 }