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.
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.
11 use dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
12 use errors::Diagnostic;
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;
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;
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};
34 use ty::codec::{self as ty_codec, TyDecoder, TyEncoder};
35 use ty::context::TyCtxt;
37 const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE;
39 const TAG_CLEAR_CROSS_CRATE_CLEAR: u8 = 0;
40 const TAG_CLEAR_CROSS_CRATE_SET: u8 = 1;
42 const TAG_NO_EXPANSION_INFO: u8 = 0;
43 const TAG_EXPANSION_INFO_SHORTHAND: u8 = 1;
44 const TAG_EXPANSION_INFO_INLINE: u8 = 2;
46 const TAG_VALID_SPAN: u8 = 0;
47 const TAG_INVALID_SPAN: u8 = 1;
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> {
55 // The complete cache data in serialized form.
56 serialized_data: Vec<u8>,
58 // This field collects all Diagnostics emitted during the current
59 // compilation session.
60 current_diagnostics: RefCell<FxHashMap<DepNodeIndex, Vec<Diagnostic>>>,
62 prev_cnums: Vec<(u32, String, CrateDisambiguator)>,
63 cnum_map: RefCell<Option<IndexVec<CrateNum, Option<CrateNum>>>>,
65 codemap: &'sess CodeMap,
66 file_index_to_stable_id: FxHashMap<FileMapIndex, StableFilemapId>,
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>>,
72 // A map from dep-node to the position of the cached query result in
74 query_result_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
76 // A map from dep-node to the position of any associated diagnostics in
78 prev_diagnostics_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
81 // This type is used only for (de-)serialization.
82 #[derive(RustcEncodable, RustcDecodable)]
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,
90 type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
91 type EncodedDiagnosticsIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
92 type EncodedDiagnostics = Vec<Diagnostic>;
94 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
95 struct FileMapIndex(u32);
97 #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, RustcEncodable, RustcDecodable)]
98 struct AbsoluteBytePos(u32);
100 impl AbsoluteBytePos {
101 fn new(pos: usize) -> AbsoluteBytePos {
102 debug_assert!(pos <= ::std::u32::MAX as usize);
103 AbsoluteBytePos(pos as u32)
106 fn to_usize(self) -> usize {
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());
116 // Wrapping in a scope so we can borrow `data`
117 let footer: Footer = {
118 let mut decoder = opaque::Decoder::new(&data[..], start_pos);
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.")
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.")
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()),
147 pub fn new_empty(codemap: &'sess CodeMap) -> OnDiskCache<'sess> {
149 serialized_data: Vec::new(),
150 file_index_to_stable_id: FxHashMap(),
151 file_index_to_file: RefCell::new(FxHashMap()),
153 cnum_map: RefCell::new(None),
155 current_diagnostics: RefCell::new(FxHashMap()),
156 query_result_index: FxHashMap(),
157 prev_diagnostics_index: FxHashMap(),
158 synthetic_expansion_infos: RefCell::new(FxHashMap()),
162 pub fn serialize<'a, 'tcx, E>(&self,
163 tcx: TyCtxt<'a, 'tcx, 'tcx>,
165 -> Result<(), E::Error>
166 where E: ty_codec::TyEncoder
168 // Serializing the DepGraph should not modify it:
169 let _in_ignore = tcx.dep_graph.in_ignore();
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();
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));
183 (file_to_file_index, file_index_to_stable_id)
186 let mut encoder = CacheEncoder {
189 type_shorthands: FxHashMap(),
190 predicate_shorthands: FxHashMap(),
191 expn_info_shorthands: FxHashMap(),
192 codemap: CachingCodemapView::new(tcx.sess.codemap()),
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);
201 // Encode query results
202 let mut query_result_index = EncodedQueryResultIndex::new();
205 use ty::maps::queries::*;
206 let enc = &mut encoder;
207 let qri = &mut query_result_index;
209 // Encode TypeckTables
210 encode_query_results::<typeck_tables_of, _>(tcx, enc, qri)?;
213 // Encode diagnostics
214 let diagnostics_index = {
215 let mut diagnostics_index = EncodedDiagnosticsIndex::new();
217 for (dep_node_index, diagnostics) in self.current_diagnostics
220 let pos = AbsoluteBytePos::new(encoder.position());
221 // Let's make sure we get the expected type here:
222 let diagnostics: &EncodedDiagnostics = diagnostics;
224 SerializedDepNodeIndex::new(dep_node_index.index());
225 encoder.encode_tagged(dep_node_index, diagnostics)?;
226 diagnostics_index.push((dep_node_index, pos));
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)
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,
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)?;
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.
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...
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)
272 let diagnostics: Option<EncodedDiagnostics> = self.load_indexed(
275 &self.prev_diagnostics_index,
278 diagnostics.unwrap_or(Vec::new())
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());
292 pub fn load_query_result<'a, 'tcx, T>(&self,
293 tcx: TyCtxt<'a, 'tcx, 'tcx>,
294 dep_node_index: SerializedDepNodeIndex)
298 let result = self.load_indexed(tcx,
300 &self.query_result_index,
302 if let Some(result) = result {
305 bug!("Could not find query result for key {:?}", dep_node_index)
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();
318 let x = current_diagnostics.entry(dep_node_index).or_insert_with(|| {
319 mem::replace(&mut diagnostics, Vec::new())
322 x.extend(diagnostics.into_iter());
325 fn load_indexed<'a, 'tcx, T>(&self,
326 tcx: TyCtxt<'a, 'tcx, 'tcx>,
327 dep_node_index: SerializedDepNodeIndex,
328 index: &FxHashMap<SerializedDepNodeIndex,
330 debug_tag: &'static str)
334 let pos = if let Some(&pos) = index.get(&dep_node_index) {
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[..]));
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();
348 let mut decoder = CacheDecoder {
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,
358 match decode_tagged(&mut decoder, dep_node_index) {
363 bug!("Could not decode cached {}: {}", debug_tag, e)
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
372 fn compute_cnum_map(tcx: TyCtxt,
373 prev_cnums: &[(u32, String, CrateDisambiguator)])
374 -> IndexVec<CrateNum, Option<CrateNum>>
376 let _in_ignore = tcx.dep_graph.in_ignore();
378 let current_cnums = tcx.all_crate_nums(LOCAL_CRATE).iter().map(|&cnum| {
379 let crate_name = tcx.original_crate_name(cnum)
382 let crate_disambiguator = tcx.crate_disambiguator(cnum);
383 ((crate_name, crate_disambiguator), cnum)
384 }).collect::<FxHashMap<_,_>>();
386 let map_size = prev_cnums.iter()
387 .map(|&(cnum, ..)| cnum)
390 let mut map = IndexVec::new();
391 map.resize(map_size as usize, None);
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();
398 map[LOCAL_CRATE] = Some(LOCAL_CRATE);
404 //- DECODING -------------------------------------------------------------------
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>,
419 impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> {
420 fn file_index_to_file(&mut self, index: FileMapIndex) -> Rc<FileMap> {
422 ref mut file_index_to_file,
423 ref file_index_to_stable_id,
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.")
436 trait DecoderWithPosition: Decoder {
437 fn position(&self) -> usize;
440 impl<'enc> DecoderWithPosition for opaque::Decoder<'enc> {
441 fn position(&self) -> usize {
446 impl<'a, 'tcx, 'x> DecoderWithPosition for CacheDecoder<'a, 'tcx, 'x> {
447 fn position(&self) -> usize {
448 self.opaque.position()
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,
456 -> Result<V, D::Error>
457 where T: Decodable + Eq + ::std::fmt::Debug,
459 D: DecoderWithPosition,
462 let start_pos = decoder.position();
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();
469 let expected_len: u64 = Decodable::decode(decoder)?;
470 assert_eq!((end_pos - start_pos) as u64, expected_len);
476 impl<'a, 'tcx: 'a, 'x> ty_codec::TyDecoder<'a, 'tcx> for CacheDecoder<'a, 'tcx, 'x> {
479 fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
484 fn position(&self) -> usize {
485 self.opaque.position()
489 fn peek_byte(&self) -> u8 {
490 self.opaque.data[self.opaque.position()]
493 fn cached_ty_for_shorthand<F>(&mut self,
496 -> Result<ty::Ty<'tcx>, Self::Error>
497 where F: FnOnce(&mut Self) -> Result<ty::Ty<'tcx>, Self::Error>
499 let tcx = self.tcx();
501 let cache_key = ty::CReaderCacheKey {
502 cnum: RESERVED_FOR_INCR_COMP_CACHE,
506 if let Some(&ty) = tcx.rcache.borrow().get(&cache_key) {
510 let ty = or_insert_with(self)?;
511 tcx.rcache.borrow_mut().insert(cache_key, ty);
515 fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
516 where F: FnOnce(&mut Self) -> R
518 debug_assert!(pos < self.opaque.data.len());
520 let new_opaque = opaque::Decoder::new(self.opaque.data, pos);
521 let old_opaque = mem::replace(&mut self.opaque, new_opaque);
523 self.opaque = old_opaque;
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)
534 implement_ty_decoder!( CacheDecoder<'a, 'tcx, 'x> );
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)?;
540 if tag == TAG_INVALID_SPAN {
543 debug_assert_eq!(tag, TAG_VALID_SPAN);
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)?;
551 let file_lo = self.file_index_to_file(file_lo_index);
552 let lo = file_lo.lines.borrow()[line_lo - 1] + col_lo;
555 let expn_info_tag = u8::decode(self)?;
557 let ctxt = match expn_info_tag {
558 TAG_NO_EXPANSION_INFO => {
559 SyntaxContext::empty()
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);
568 TAG_EXPANSION_INFO_SHORTHAND => {
569 let pos = AbsoluteBytePos::decode(self)?;
570 if let Some(ctxt) = self.synthetic_expansion_infos.get(&pos).cloned() {
573 let expn_info = self.with_position(pos.to_usize(), |this| {
574 ExpnInfo::decode(this)
576 let ctxt = SyntaxContext::allocate_directly(expn_info);
577 self.synthetic_expansion_infos.insert(pos, ctxt);
586 Ok(Span::new(lo, hi, ctxt))
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
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")
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> {
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)?;
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])
614 impl<'a, 'tcx, 'x> SpecializedDecoder<LocalDefId> for CacheDecoder<'a, 'tcx, 'x> {
616 fn specialized_decode(&mut self) -> Result<LocalDefId, Self::Error> {
617 Ok(LocalDefId::from_def_id(DefId::decode(self)?))
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)?;
626 // Use the DefPathHash to map to the current DefId.
627 let def_id = self.tcx()
628 .def_path_hash_to_def_id
630 .unwrap()[&def_path_hash];
632 debug_assert!(def_id.is_local());
634 // The ItemLocalId needs no remapping.
635 let local_id = hir::ItemLocalId::decode(self)?;
637 // Reconstruct the HirId and look up the corresponding NodeId in the
638 // context of the current session.
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> {
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))
656 impl<'a, 'tcx, 'x, T: Decodable> SpecializedDecoder<mir::ClearCrossCrate<T>>
657 for CacheDecoder<'a, 'tcx, 'x> {
659 fn specialized_decode(&mut self) -> Result<mir::ClearCrossCrate<T>, Self::Error> {
660 let discr = u8::decode(self)?;
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))
675 //- ENCODING -------------------------------------------------------------------
677 struct CacheEncoder<'enc, 'a, 'tcx, E>
678 where E: 'enc + ty_codec::TyEncoder,
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>,
690 impl<'enc, 'a, 'tcx, E> CacheEncoder<'enc, 'a, 'tcx, E>
691 where E: 'enc + ty_codec::TyEncoder
693 fn filemap_index(&mut self, filemap: Rc<FileMap>) -> FileMapIndex {
694 self.file_to_file_index[&(&*filemap as *const FileMap)]
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,
705 -> Result<(), E::Error>
707 use ty::codec::TyEncoder;
708 let start_pos = self.position();
713 let end_pos = self.position();
714 ((end_pos - start_pos) as u64).encode(self)
718 impl<'enc, 'a, 'tcx, E> SpecializedEncoder<Span> for CacheEncoder<'enc, 'a, 'tcx, E>
719 where E: 'enc + ty_codec::TyEncoder
721 fn specialized_encode(&mut self, span: &Span) -> Result<(), Self::Error> {
723 if *span == DUMMY_SP {
724 return TAG_INVALID_SPAN.encode(self);
727 let span_data = span.data();
729 if span_data.hi < span_data.lo {
730 return TAG_INVALID_SPAN.encode(self);
733 let (file_lo, line_lo, col_lo) = match self.codemap
734 .byte_pos_to_line_and_col(span_data.lo) {
737 return TAG_INVALID_SPAN.encode(self);
741 if !file_lo.contains(span_data.hi) {
742 return TAG_INVALID_SPAN.encode(self);
745 let len = span_data.hi - span_data.lo;
747 let filemap_index = self.filemap_index(file_lo);
749 TAG_VALID_SPAN.encode(self)?;
750 filemap_index.encode(self)?;
751 line_lo.encode(self)?;
752 col_lo.encode(self)?;
755 if span_data.ctxt == SyntaxContext::empty() {
756 TAG_NO_EXPANSION_INFO.encode(self)
758 let mark = span_data.ctxt.outer();
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)?;
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)
771 TAG_NO_EXPANSION_INFO.encode(self)
777 impl<'enc, 'a, 'tcx, E> ty_codec::TyEncoder for CacheEncoder<'enc, 'a, 'tcx, E>
778 where E: 'enc + ty_codec::TyEncoder
781 fn position(&self) -> usize {
782 self.encoder.position()
786 impl<'enc, 'a, 'tcx, E> SpecializedEncoder<CrateNum> for CacheEncoder<'enc, 'a, 'tcx, E>
787 where E: 'enc + ty_codec::TyEncoder
790 fn specialized_encode(&mut self, cnum: &CrateNum) -> Result<(), Self::Error> {
791 self.emit_u32(cnum.as_u32())
795 impl<'enc, 'a, 'tcx, E> SpecializedEncoder<ty::Ty<'tcx>> for CacheEncoder<'enc, 'a, 'tcx, E>
796 where E: 'enc + ty_codec::TyEncoder
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)
805 impl<'enc, 'a, 'tcx, E> SpecializedEncoder<ty::GenericPredicates<'tcx>>
806 for CacheEncoder<'enc, 'a, 'tcx, E>
807 where E: 'enc + ty_codec::TyEncoder
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)
818 impl<'enc, 'a, 'tcx, E> SpecializedEncoder<hir::HirId> for CacheEncoder<'enc, 'a, 'tcx, E>
819 where E: 'enc + ty_codec::TyEncoder
822 fn specialized_encode(&mut self, id: &hir::HirId) -> Result<(), Self::Error> {
828 let def_path_hash = self.tcx.hir.definitions().def_path_hash(owner);
830 def_path_hash.encode(self)?;
831 local_id.encode(self)
836 impl<'enc, 'a, 'tcx, E> SpecializedEncoder<DefId> for CacheEncoder<'enc, 'a, 'tcx, E>
837 where E: 'enc + ty_codec::TyEncoder
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)
846 impl<'enc, 'a, 'tcx, E> SpecializedEncoder<LocalDefId> for CacheEncoder<'enc, 'a, 'tcx, E>
847 where E: 'enc + ty_codec::TyEncoder
850 fn specialized_encode(&mut self, id: &LocalDefId) -> Result<(), Self::Error> {
851 id.to_def_id().encode(self)
855 impl<'enc, 'a, 'tcx, E> SpecializedEncoder<DefIndex> for CacheEncoder<'enc, 'a, 'tcx, E>
856 where E: 'enc + ty_codec::TyEncoder
858 fn specialized_encode(&mut self, _: &DefIndex) -> Result<(), Self::Error> {
859 bug!("Encoding DefIndex without context.")
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
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);
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,
881 fn specialized_encode(&mut self,
882 val: &mir::ClearCrossCrate<T>)
883 -> Result<(), Self::Error> {
885 mir::ClearCrossCrate::Clear => {
886 TAG_CLEAR_CROSS_CRATE_CLEAR.encode(self)
888 mir::ClearCrossCrate::Set(ref val) => {
889 TAG_CLEAR_CROSS_CRATE_SET.encode(self)?;
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)
904 impl<'enc, 'a, 'tcx, E> Encoder for CacheEncoder<'enc, 'a, 'tcx, E>
905 where E: 'enc + ty_codec::TyEncoder
907 type Error = E::Error;
909 fn emit_nil(&mut self) -> Result<(), Self::Error> {
936 // An integer that will always encode to 8 bytes.
937 struct IntEncodedWithFixedSize(u64);
939 impl IntEncodedWithFixedSize {
940 pub const ENCODED_SIZE: usize = 8;
943 impl UseSpecializedEncodable for IntEncodedWithFixedSize {}
944 impl UseSpecializedDecodable for IntEncodedWithFixedSize {}
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)?;
952 let end_pos = self.position();
953 assert_eq!((end_pos - start_pos), IntEncodedWithFixedSize::ENCODED_SIZE);
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();
963 for i in 0 .. IntEncodedWithFixedSize::ENCODED_SIZE {
964 let byte: u8 = Decodable::decode(self)?;
965 value |= (byte as u64) << (i * 8);
968 let end_pos = self.position();
969 assert_eq!((end_pos - start_pos), IntEncodedWithFixedSize::ENCODED_SIZE);
971 Ok(IntEncodedWithFixedSize(value))
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>,
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());
987 // Record position of the cache entry
988 query_result_index.push((dep_node, AbsoluteBytePos::new(encoder.position())));
990 // Encode the type check tables with the SerializedDepNodeIndex
992 encoder.encode_tagged(dep_node, &entry.value)?;