From 409e39285d2189eb8bb656a93074473f9f186cc5 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 22 Nov 2017 13:41:27 +0100 Subject: [PATCH 1/7] incr.comp.: Properly hash and encode macro expansion information. --- src/librustc/ich/hcx.rs | 2 +- src/librustc/ich/impls_syntax.rs | 24 ++++++++ src/librustc/ty/maps/on_disk_cache.rs | 86 ++++++++++++++++++++++++++- src/libsyntax_pos/hygiene.rs | 33 ++++++++-- 4 files changed, 138 insertions(+), 7 deletions(-) diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index f204d352842..6d7322fdafd 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -419,7 +419,7 @@ impl<'gcx> HashStable> for Span { 0u8.hash_stable(hcx, hasher); } else { 1u8.hash_stable(hcx, hasher); - self.source_callsite().hash_stable(hcx, hasher); + span.ctxt.outer().expn_info().hash_stable(hcx, hasher); } } } diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index fea4e283db1..c414349c8ff 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -347,6 +347,30 @@ impl_stable_hash_for!(enum ::syntax::ast::MetaItemKind { NameValue(lit) }); +impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnInfo { + call_site, + callee +}); + +impl_stable_hash_for!(struct ::syntax_pos::hygiene::NameAndSpan { + format, + allow_internal_unstable, + allow_internal_unsafe, + span +}); + +impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat { + MacroAttribute(sym), + MacroBang(sym), + CompilerDesugaring(kind) +}); + +impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind { + BackArrow, + DotFill, + QuestionMark +}); + impl<'gcx> HashStable> for FileMap { fn hash_stable(&self, hcx: &mut StableHashingContext<'gcx>, diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index 01f2374033d..6ca787ad19e 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -27,7 +27,8 @@ use std::collections::BTreeMap; use std::mem; use syntax::ast::NodeId; use syntax::codemap::{CodeMap, StableFilemapId}; -use syntax_pos::{BytePos, Span, NO_EXPANSION, DUMMY_SP}; +use syntax_pos::{BytePos, Span, DUMMY_SP}; +use syntax_pos::hygiene::{Mark, SyntaxContext, ExpnInfo}; use ty; use ty::codec::{self as ty_codec, TyDecoder, TyEncoder}; use ty::context::TyCtxt; @@ -40,6 +41,10 @@ const QUERY_RESULT_INDEX_TAG: u64 = 0x1234_5678_C3C3_C3C3; const TAG_CLEAR_CROSS_CRATE_CLEAR: u8 = 0; const TAG_CLEAR_CROSS_CRATE_SET: u8 = 1; +const TAG_NO_EXPANSION_INFO: u8 = 0; +const TAG_EXPANSION_INFO_SHORTHAND: u8 = 1; +const TAG_EXPANSION_INFO_INLINE: u8 = 2; + /// `OnDiskCache` provides an interface to incr. comp. data cached from the /// previous compilation session. This data will eventually include the results /// of a few selected queries (like `typeck_tables_of` and `mir_optimized`) and @@ -61,6 +66,7 @@ pub struct OnDiskCache<'sess> { prev_filemap_starts: BTreeMap, codemap: &'sess CodeMap, + synthetic_expansion_infos: RefCell>, // A map from dep-node to the position of the cached query result in // `serialized_data`. @@ -90,6 +96,8 @@ impl<'sess> OnDiskCache<'sess> { (header, decoder.position()) }; + let mut synthetic_expansion_infos = FxHashMap(); + let (prev_diagnostics, query_result_index) = { let mut decoder = CacheDecoder { tcx: None, @@ -97,6 +105,7 @@ impl<'sess> OnDiskCache<'sess> { codemap: sess.codemap(), prev_filemap_starts: &header.prev_filemap_starts, cnum_map: &IndexVec::new(), + synthetic_expansion_infos: &mut synthetic_expansion_infos, }; // Decode Diagnostics @@ -135,6 +144,7 @@ impl<'sess> OnDiskCache<'sess> { codemap: sess.codemap(), current_diagnostics: RefCell::new(FxHashMap()), query_result_index: query_result_index.into_iter().collect(), + synthetic_expansion_infos: RefCell::new(synthetic_expansion_infos), } } @@ -148,6 +158,7 @@ impl<'sess> OnDiskCache<'sess> { codemap, current_diagnostics: RefCell::new(FxHashMap()), query_result_index: FxHashMap(), + synthetic_expansion_infos: RefCell::new(FxHashMap()), } } @@ -166,6 +177,7 @@ impl<'sess> OnDiskCache<'sess> { encoder, type_shorthands: FxHashMap(), predicate_shorthands: FxHashMap(), + expn_info_shorthands: FxHashMap(), }; @@ -269,12 +281,15 @@ impl<'sess> OnDiskCache<'sess> { *cnum_map = Some(Self::compute_cnum_map(tcx, &self.prev_cnums[..])); } + let mut synthetic_expansion_infos = self.synthetic_expansion_infos.borrow_mut(); + let mut decoder = CacheDecoder { tcx: Some(tcx), opaque: opaque::Decoder::new(&self.serialized_data[..], pos), codemap: self.codemap, prev_filemap_starts: &self.prev_filemap_starts, cnum_map: cnum_map.as_ref().unwrap(), + synthetic_expansion_infos: &mut *synthetic_expansion_infos, }; match decode_tagged(&mut decoder, dep_node_index) { @@ -350,6 +365,7 @@ struct CacheDecoder<'a, 'tcx: 'a, 'x> { codemap: &'x CodeMap, prev_filemap_starts: &'x BTreeMap, cnum_map: &'x IndexVec>, + synthetic_expansion_infos: &'x mut FxHashMap, } impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> { @@ -457,7 +473,39 @@ impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { if let Some(current_filemap) = self.codemap.filemap_by_stable_id(filemap_id) { let lo = (lo + current_filemap.start_pos) - prev_filemap_start; let hi = (hi + current_filemap.start_pos) - prev_filemap_start; - return Ok(Span::new(lo, hi, NO_EXPANSION)); + + let expn_info_tag = u8::decode(self)?; + + let ctxt = match expn_info_tag { + TAG_NO_EXPANSION_INFO => { + SyntaxContext::empty() + } + TAG_EXPANSION_INFO_INLINE => { + let pos = self.position(); + let expn_info: ExpnInfo = Decodable::decode(self)?; + let ctxt = SyntaxContext::allocate_directly(expn_info); + self.synthetic_expansion_infos.insert(pos, ctxt); + ctxt + } + TAG_EXPANSION_INFO_SHORTHAND => { + let pos = usize::decode(self)?; + if let Some(ctxt) = self.synthetic_expansion_infos.get(&pos).cloned() { + ctxt + } else { + let expn_info = self.with_position(pos, |this| { + ExpnInfo::decode(this) + })?; + let ctxt = SyntaxContext::allocate_directly(expn_info); + self.synthetic_expansion_infos.insert(pos, ctxt); + ctxt + } + } + _ => { + unreachable!() + } + }; + + return Ok(Span::new(lo, hi, ctxt)); } } @@ -479,6 +527,7 @@ impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { // compilation sessions. We use the DefPathHash, which is stable across // sessions, to map the old DefId to the new one. impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { + #[inline] fn specialized_decode(&mut self) -> Result { // Load the DefPathHash which is was we encoded the DefId as. let def_path_hash = DefPathHash::decode(self)?; @@ -489,6 +538,7 @@ impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { } impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { + #[inline] fn specialized_decode(&mut self) -> Result { Ok(LocalDefId::from_def_id(DefId::decode(self)?)) } @@ -558,6 +608,7 @@ struct CacheEncoder<'enc, 'a, 'tcx, E> encoder: &'enc mut E, type_shorthands: FxHashMap, usize>, predicate_shorthands: FxHashMap, usize>, + expn_info_shorthands: FxHashMap, } impl<'enc, 'a, 'tcx, E> CacheEncoder<'enc, 'a, 'tcx, E> @@ -584,6 +635,37 @@ impl<'enc, 'a, 'tcx, E> CacheEncoder<'enc, 'a, 'tcx, E> } } +impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'a, 'tcx, E> + where E: 'enc + ty_codec::TyEncoder +{ + fn specialized_encode(&mut self, span: &Span) -> Result<(), Self::Error> { + let span_data = span.data(); + + span_data.lo.encode(self)?; + span_data.hi.encode(self)?; + + if span_data.ctxt == SyntaxContext::empty() { + TAG_NO_EXPANSION_INFO.encode(self) + } else { + let mark = span_data.ctxt.outer(); + + if let Some(expn_info) = mark.expn_info() { + if let Some(pos) = self.expn_info_shorthands.get(&mark).cloned() { + TAG_EXPANSION_INFO_SHORTHAND.encode(self)?; + pos.encode(self) + } else { + TAG_EXPANSION_INFO_INLINE.encode(self)?; + let pos = self.position(); + self.expn_info_shorthands.insert(mark, pos); + expn_info.encode(self) + } + } else { + TAG_NO_EXPANSION_INFO.encode(self) + } + } + } +} + impl<'enc, 'a, 'tcx, E> ty_codec::TyEncoder for CacheEncoder<'enc, 'a, 'tcx, E> where E: 'enc + ty_codec::TyEncoder { diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 4790fa0a7ed..9358e654a9f 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -140,6 +140,31 @@ impl SyntaxContext { SyntaxContext(0) } + // Allocate a new SyntaxContext with the given ExpnInfo. This is used when + // deserializing Spans from the incr. comp. cache. + // FIXME(mw): This method does not restore MarkData::parent or + // SyntaxContextData::prev_ctxt or SyntaxContextData::modern. These things + // don't seem to be used after HIR lowering, so everything should be fine + // as long as incremental compilation does not kick in before that. + pub fn allocate_directly(expansion_info: ExpnInfo) -> Self { + HygieneData::with(|data| { + data.marks.push(MarkData { + parent: Mark::root(), + modern: false, + expn_info: Some(expansion_info) + }); + + let mark = Mark(data.marks.len() as u32 - 1); + + data.syntax_contexts.push(SyntaxContextData { + outer_mark: mark, + prev_ctxt: SyntaxContext::empty(), + modern: SyntaxContext::empty(), + }); + SyntaxContext(data.syntax_contexts.len() as u32 - 1) + }) + } + /// Extend a syntax context with a given mark pub fn apply_mark(self, mark: Mark) -> SyntaxContext { HygieneData::with(|data| { @@ -286,7 +311,7 @@ impl fmt::Debug for SyntaxContext { } /// Extra information for tracking spans of macro and syntax sugar expansion -#[derive(Clone, Hash, Debug)] +#[derive(Clone, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct ExpnInfo { /// The location of the actual macro invocation or syntax sugar , e.g. /// `let x = foo!();` or `if let Some(y) = x {}` @@ -302,7 +327,7 @@ pub struct ExpnInfo { pub callee: NameAndSpan } -#[derive(Clone, Hash, Debug)] +#[derive(Clone, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct NameAndSpan { /// The format with which the macro was invoked. pub format: ExpnFormat, @@ -330,7 +355,7 @@ impl NameAndSpan { } /// The source of expansion. -#[derive(Clone, Hash, Debug, PartialEq, Eq)] +#[derive(Clone, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum ExpnFormat { /// e.g. #[derive(...)] MacroAttribute(Symbol), @@ -341,7 +366,7 @@ pub enum ExpnFormat { } /// The kind of compiler desugaring. -#[derive(Clone, Hash, Debug, PartialEq, Eq)] +#[derive(Clone, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum CompilerDesugaringKind { BackArrow, DotFill, From 45439945c9cb1122c882cefbe0e38c3bb6f20514 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 24 Nov 2017 14:00:33 +0100 Subject: [PATCH 2/7] incr.comp.: Store Spans as (file,line,col,length) in incr.comp. cache. The previous method ran into problems because ICH would treat Spans as (file,line,col) but the cache contained byte offsets and its possible for the latter to change while the former stayed stable. --- src/librustc/ich/hcx.rs | 77 ++++------ src/librustc/ty/maps/on_disk_cache.rs | 208 +++++++++++++++++--------- src/libsyntax/codemap.rs | 2 +- src/libsyntax_pos/lib.rs | 5 + 4 files changed, 178 insertions(+), 114 deletions(-) diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index 6d7322fdafd..d95b825b9e5 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -28,7 +28,7 @@ use syntax::attr; use syntax::codemap::CodeMap; use syntax::ext::hygiene::SyntaxContext; use syntax::symbol::Symbol; -use syntax_pos::Span; +use syntax_pos::{Span, DUMMY_SP}; use rustc_data_structures::stable_hasher::{HashStable, StableHashingContextProvider, StableHasher, StableHasherResult, @@ -362,63 +362,52 @@ impl<'gcx> HashStable> for Span { fn hash_stable(&self, hcx: &mut StableHashingContext<'gcx>, hasher: &mut StableHasher) { - use syntax_pos::Pos; + const TAG_VALID_SPAN: u8 = 0; + const TAG_INVALID_SPAN: u8 = 1; + const TAG_EXPANSION: u8 = 0; + const TAG_NO_EXPANSION: u8 = 1; if !hcx.hash_spans { return } + if *self == DUMMY_SP { + return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher); + } + // If this is not an empty or invalid span, we want to hash the last // position that belongs to it, as opposed to hashing the first // position past it. let span = self.data(); - let span_hi = if span.hi > span.lo { - // We might end up in the middle of a multibyte character here, - // but that's OK, since we are not trying to decode anything at - // this position. - span.hi - ::syntax_pos::BytePos(1) - } else { - span.hi - }; - { - let loc1 = hcx.codemap().byte_pos_to_line_and_col(span.lo); - let loc1 = loc1.as_ref() - .map(|&(ref fm, line, col)| (&fm.name[..], line, col.to_usize())) - .unwrap_or(("???", 0, 0)); - - let loc2 = hcx.codemap().byte_pos_to_line_and_col(span_hi); - let loc2 = loc2.as_ref() - .map(|&(ref fm, line, col)| (&fm.name[..], line, col.to_usize())) - .unwrap_or(("???", 0, 0)); - - if loc1.0 == loc2.0 { - std_hash::Hash::hash(&0u8, hasher); - - std_hash::Hash::hash(loc1.0, hasher); - std_hash::Hash::hash(&loc1.1, hasher); - std_hash::Hash::hash(&loc1.2, hasher); - - // Do not hash the file name twice - std_hash::Hash::hash(&loc2.1, hasher); - std_hash::Hash::hash(&loc2.2, hasher); - } else { - std_hash::Hash::hash(&1u8, hasher); - - std_hash::Hash::hash(loc1.0, hasher); - std_hash::Hash::hash(&loc1.1, hasher); - std_hash::Hash::hash(&loc1.2, hasher); - - std_hash::Hash::hash(loc2.0, hasher); - std_hash::Hash::hash(&loc2.1, hasher); - std_hash::Hash::hash(&loc2.2, hasher); - } + if span.hi < span.lo { + return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher); } + let (file_lo, line_lo, col_lo) = match hcx.codemap() + .byte_pos_to_line_and_col(span.lo) { + Some(pos) => pos, + None => { + return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher); + } + }; + + if !file_lo.contains(span.hi) { + return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher); + } + + let len = span.hi - span.lo; + + std_hash::Hash::hash(&TAG_VALID_SPAN, hasher); + std_hash::Hash::hash(&file_lo.name, hasher); + std_hash::Hash::hash(&line_lo, hasher); + std_hash::Hash::hash(&col_lo, hasher); + std_hash::Hash::hash(&len, hasher); + if span.ctxt == SyntaxContext::empty() { - 0u8.hash_stable(hcx, hasher); + TAG_NO_EXPANSION.hash_stable(hcx, hasher); } else { - 1u8.hash_stable(hcx, hasher); + TAG_EXPANSION.hash_stable(hcx, hasher); span.ctxt.outer().expn_info().hash_stable(hcx, hasher); } } diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index 6ca787ad19e..40103571afa 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -14,6 +14,7 @@ use hir; use hir::def_id::{CrateNum, DefIndex, DefId, LocalDefId, RESERVED_FOR_INCR_COMP_CACHE, LOCAL_CRATE}; use hir::map::definitions::DefPathHash; +use ich::CachingCodemapView; use middle::cstore::CrateStore; use mir; use rustc_data_structures::fx::FxHashMap; @@ -23,11 +24,11 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque, UseSpecializedDecodable, UseSpecializedEncodable}; use session::{CrateDisambiguator, Session}; use std::cell::RefCell; -use std::collections::BTreeMap; use std::mem; +use std::rc::Rc; use syntax::ast::NodeId; use syntax::codemap::{CodeMap, StableFilemapId}; -use syntax_pos::{BytePos, Span, DUMMY_SP}; +use syntax_pos::{BytePos, Span, DUMMY_SP, FileMap}; use syntax_pos::hygiene::{Mark, SyntaxContext, ExpnInfo}; use ty; use ty::codec::{self as ty_codec, TyDecoder, TyEncoder}; @@ -45,6 +46,9 @@ const TAG_NO_EXPANSION_INFO: u8 = 0; const TAG_EXPANSION_INFO_SHORTHAND: u8 = 1; const TAG_EXPANSION_INFO_INLINE: u8 = 2; +const TAG_VALID_SPAN: u8 = 0; +const TAG_INVALID_SPAN: u8 = 1; + /// `OnDiskCache` provides an interface to incr. comp. data cached from the /// previous compilation session. This data will eventually include the results /// of a few selected queries (like `typeck_tables_of` and `mir_optimized`) and @@ -64,8 +68,11 @@ pub struct OnDiskCache<'sess> { prev_cnums: Vec<(u32, String, CrateDisambiguator)>, cnum_map: RefCell>>>, - prev_filemap_starts: BTreeMap, codemap: &'sess CodeMap, + file_index_to_stable_id: FxHashMap, + + // These two fields caches that are populated lazily during decoding. + file_index_to_file: RefCell>>, synthetic_expansion_infos: RefCell>, // A map from dep-node to the position of the cached query result in @@ -76,13 +83,16 @@ pub struct OnDiskCache<'sess> { // This type is used only for (de-)serialization. #[derive(RustcEncodable, RustcDecodable)] struct Header { - prev_filemap_starts: BTreeMap, + file_index_to_stable_id: FxHashMap, prev_cnums: Vec<(u32, String, CrateDisambiguator)>, } type EncodedPrevDiagnostics = Vec<(SerializedDepNodeIndex, Vec)>; type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, usize)>; +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +struct FileMapIndex(u32); + impl<'sess> OnDiskCache<'sess> { /// Create a new OnDiskCache instance from the serialized data in `data`. pub fn new(sess: &'sess Session, data: Vec, start_pos: usize) -> OnDiskCache<'sess> { @@ -97,15 +107,17 @@ impl<'sess> OnDiskCache<'sess> { }; let mut synthetic_expansion_infos = FxHashMap(); + let mut file_index_to_file = FxHashMap(); let (prev_diagnostics, query_result_index) = { let mut decoder = CacheDecoder { tcx: None, opaque: opaque::Decoder::new(&data[..], post_header_pos), codemap: sess.codemap(), - prev_filemap_starts: &header.prev_filemap_starts, cnum_map: &IndexVec::new(), synthetic_expansion_infos: &mut synthetic_expansion_infos, + file_index_to_file: &mut file_index_to_file, + file_index_to_stable_id: &header.file_index_to_stable_id, }; // Decode Diagnostics @@ -138,7 +150,8 @@ impl<'sess> OnDiskCache<'sess> { OnDiskCache { serialized_data: data, prev_diagnostics, - prev_filemap_starts: header.prev_filemap_starts, + file_index_to_stable_id: header.file_index_to_stable_id, + file_index_to_file: RefCell::new(file_index_to_file), prev_cnums: header.prev_cnums, cnum_map: RefCell::new(None), codemap: sess.codemap(), @@ -152,7 +165,8 @@ impl<'sess> OnDiskCache<'sess> { OnDiskCache { serialized_data: Vec::new(), prev_diagnostics: FxHashMap(), - prev_filemap_starts: BTreeMap::new(), + file_index_to_stable_id: FxHashMap(), + file_index_to_file: RefCell::new(FxHashMap()), prev_cnums: vec![], cnum_map: RefCell::new(None), codemap, @@ -172,23 +186,32 @@ impl<'sess> OnDiskCache<'sess> { // Serializing the DepGraph should not modify it: let _in_ignore = tcx.dep_graph.in_ignore(); + // Allocate FileMapIndices + let (file_to_file_index, file_index_to_stable_id) = { + let mut file_to_file_index = FxHashMap(); + let mut file_index_to_stable_id = FxHashMap(); + + for (index, file) in tcx.sess.codemap().files().iter().enumerate() { + let index = FileMapIndex(index as u32); + let file_ptr: *const FileMap = &**file as *const _; + file_to_file_index.insert(file_ptr, index); + file_index_to_stable_id.insert(index, StableFilemapId::new(&file)); + } + + (file_to_file_index, file_index_to_stable_id) + }; + let mut encoder = CacheEncoder { tcx, encoder, type_shorthands: FxHashMap(), predicate_shorthands: FxHashMap(), expn_info_shorthands: FxHashMap(), + codemap: CachingCodemapView::new(tcx.sess.codemap()), + file_to_file_index, }; - // Encode the file header - let prev_filemap_starts: BTreeMap<_, _> = self - .codemap - .files() - .iter() - .map(|fm| (fm.start_pos, StableFilemapId::new(fm))) - .collect(); - let sorted_cnums = sorted_cnums_including_local_crate(cstore); let prev_cnums: Vec<_> = sorted_cnums.iter().map(|&cnum| { @@ -198,7 +221,7 @@ impl<'sess> OnDiskCache<'sess> { }).collect(); Header { - prev_filemap_starts, + file_index_to_stable_id, prev_cnums, }.encode(&mut encoder)?; @@ -282,14 +305,16 @@ impl<'sess> OnDiskCache<'sess> { } let mut synthetic_expansion_infos = self.synthetic_expansion_infos.borrow_mut(); + let mut file_index_to_file = self.file_index_to_file.borrow_mut(); let mut decoder = CacheDecoder { tcx: Some(tcx), opaque: opaque::Decoder::new(&self.serialized_data[..], pos), codemap: self.codemap, - prev_filemap_starts: &self.prev_filemap_starts, cnum_map: cnum_map.as_ref().unwrap(), - synthetic_expansion_infos: &mut *synthetic_expansion_infos, + file_index_to_file: &mut file_index_to_file, + file_index_to_stable_id: &self.file_index_to_stable_id, + synthetic_expansion_infos: &mut synthetic_expansion_infos, }; match decode_tagged(&mut decoder, dep_node_index) { @@ -363,20 +388,26 @@ struct CacheDecoder<'a, 'tcx: 'a, 'x> { tcx: Option>, opaque: opaque::Decoder<'x>, codemap: &'x CodeMap, - prev_filemap_starts: &'x BTreeMap, cnum_map: &'x IndexVec>, synthetic_expansion_infos: &'x mut FxHashMap, + file_index_to_file: &'x mut FxHashMap>, + file_index_to_stable_id: &'x FxHashMap, } impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> { - fn find_filemap_prev_bytepos(&self, - prev_bytepos: BytePos) - -> Option<(BytePos, StableFilemapId)> { - for (start, id) in self.prev_filemap_starts.range(BytePos(0) ..= prev_bytepos).rev() { - return Some((*start, *id)) - } + fn file_index_to_file(&mut self, index: FileMapIndex) -> Rc { + let CacheDecoder { + ref mut file_index_to_file, + ref file_index_to_stable_id, + ref codemap, + .. + } = *self; - None + file_index_to_file.entry(index).or_insert_with(|| { + let stable_id = file_index_to_stable_id[&index]; + codemap.filemap_by_stable_id(stable_id) + .expect("Failed to lookup FileMap in new context.") + }).clone() } } @@ -466,50 +497,55 @@ implement_ty_decoder!( CacheDecoder<'a, 'tcx, 'x> ); impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { fn specialized_decode(&mut self) -> Result { - let lo = BytePos::decode(self)?; - let hi = BytePos::decode(self)?; + let tag: u8 = Decodable::decode(self)?; - if let Some((prev_filemap_start, filemap_id)) = self.find_filemap_prev_bytepos(lo) { - if let Some(current_filemap) = self.codemap.filemap_by_stable_id(filemap_id) { - let lo = (lo + current_filemap.start_pos) - prev_filemap_start; - let hi = (hi + current_filemap.start_pos) - prev_filemap_start; - - let expn_info_tag = u8::decode(self)?; - - let ctxt = match expn_info_tag { - TAG_NO_EXPANSION_INFO => { - SyntaxContext::empty() - } - TAG_EXPANSION_INFO_INLINE => { - let pos = self.position(); - let expn_info: ExpnInfo = Decodable::decode(self)?; - let ctxt = SyntaxContext::allocate_directly(expn_info); - self.synthetic_expansion_infos.insert(pos, ctxt); - ctxt - } - TAG_EXPANSION_INFO_SHORTHAND => { - let pos = usize::decode(self)?; - if let Some(ctxt) = self.synthetic_expansion_infos.get(&pos).cloned() { - ctxt - } else { - let expn_info = self.with_position(pos, |this| { - ExpnInfo::decode(this) - })?; - let ctxt = SyntaxContext::allocate_directly(expn_info); - self.synthetic_expansion_infos.insert(pos, ctxt); - ctxt - } - } - _ => { - unreachable!() - } - }; - - return Ok(Span::new(lo, hi, ctxt)); - } + if tag == TAG_INVALID_SPAN { + return Ok(DUMMY_SP); + } else { + debug_assert_eq!(tag, TAG_VALID_SPAN); } - Ok(DUMMY_SP) + let file_lo_index = FileMapIndex::decode(self)?; + let line_lo = usize::decode(self)?; + let col_lo = BytePos::decode(self)?; + let len = BytePos::decode(self)?; + + let file_lo = self.file_index_to_file(file_lo_index); + let lo = file_lo.lines.borrow()[line_lo - 1] + col_lo; + let hi = lo + len; + + let expn_info_tag = u8::decode(self)?; + + let ctxt = match expn_info_tag { + TAG_NO_EXPANSION_INFO => { + SyntaxContext::empty() + } + TAG_EXPANSION_INFO_INLINE => { + let pos = self.position(); + let expn_info: ExpnInfo = Decodable::decode(self)?; + let ctxt = SyntaxContext::allocate_directly(expn_info); + self.synthetic_expansion_infos.insert(pos, ctxt); + ctxt + } + TAG_EXPANSION_INFO_SHORTHAND => { + let pos = usize::decode(self)?; + if let Some(ctxt) = self.synthetic_expansion_infos.get(&pos).cloned() { + ctxt + } else { + let expn_info = self.with_position(pos, |this| { + ExpnInfo::decode(this) + })?; + let ctxt = SyntaxContext::allocate_directly(expn_info); + self.synthetic_expansion_infos.insert(pos, ctxt); + ctxt + } + } + _ => { + unreachable!() + } + }; + + Ok(Span::new(lo, hi, ctxt)) } } @@ -609,11 +645,17 @@ struct CacheEncoder<'enc, 'a, 'tcx, E> type_shorthands: FxHashMap, usize>, predicate_shorthands: FxHashMap, usize>, expn_info_shorthands: FxHashMap, + codemap: CachingCodemapView<'tcx>, + file_to_file_index: FxHashMap<*const FileMap, FileMapIndex>, } impl<'enc, 'a, 'tcx, E> CacheEncoder<'enc, 'a, 'tcx, E> where E: 'enc + ty_codec::TyEncoder { + fn filemap_index(&mut self, filemap: Rc) -> FileMapIndex { + self.file_to_file_index[&(&*filemap as *const FileMap)] + } + /// Encode something with additional information that allows to do some /// sanity checks when decoding the data again. This method will first /// encode the specified tag, then the given value, then the number of @@ -639,10 +681,38 @@ impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'a, 'tcx where E: 'enc + ty_codec::TyEncoder { fn specialized_encode(&mut self, span: &Span) -> Result<(), Self::Error> { + + if *span == DUMMY_SP { + return TAG_INVALID_SPAN.encode(self); + } + let span_data = span.data(); - span_data.lo.encode(self)?; - span_data.hi.encode(self)?; + if span_data.hi < span_data.lo { + return TAG_INVALID_SPAN.encode(self); + } + + let (file_lo, line_lo, col_lo) = match self.codemap + .byte_pos_to_line_and_col(span_data.lo) { + Some(pos) => pos, + None => { + return TAG_INVALID_SPAN.encode(self); + } + }; + + if !file_lo.contains(span_data.hi) { + return TAG_INVALID_SPAN.encode(self); + } + + let len = span_data.hi - span_data.lo; + + let filemap_index = self.filemap_index(file_lo); + + TAG_VALID_SPAN.encode(self)?; + filemap_index.encode(self)?; + line_lo.encode(self)?; + col_lo.encode(self)?; + len.encode(self)?; if span_data.ctxt == SyntaxContext::empty() { TAG_NO_EXPANSION_INFO.encode(self) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 3464db2a811..3aac5334a38 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -105,7 +105,7 @@ impl FileLoader for RealFileLoader { // This is a FileMap identifier that is used to correlate FileMaps between // subsequent compilation sessions (which is something we need to do during // incremental compilation). -#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)] pub struct StableFilemapId(u128); impl StableFilemapId { diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 47755dc1d54..bf059cac891 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -931,6 +931,11 @@ impl FileMap { (lines[line_index], lines[line_index + 1]) } } + + #[inline] + pub fn contains(&self, byte_pos: BytePos) -> bool { + byte_pos >= self.start_pos && byte_pos <= self.end_pos + } } /// Remove utf-8 BOM if any. From 64e109327dfd96cb8902b994b0a1e7f2d32215b0 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 28 Nov 2017 14:19:44 +0100 Subject: [PATCH 3/7] incr.comp.: Add a newtype for byte positions within the incr. comp. cache. --- src/librustc/ty/maps/on_disk_cache.rs | 36 +++++++++++++++++++-------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index 40103571afa..18304b7aa7d 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -73,11 +73,11 @@ pub struct OnDiskCache<'sess> { // These two fields caches that are populated lazily during decoding. file_index_to_file: RefCell>>, - synthetic_expansion_infos: RefCell>, + synthetic_expansion_infos: RefCell>, // A map from dep-node to the position of the cached query result in // `serialized_data`. - query_result_index: FxHashMap, + query_result_index: FxHashMap, } // This type is used only for (de-)serialization. @@ -88,11 +88,25 @@ struct Header { } type EncodedPrevDiagnostics = Vec<(SerializedDepNodeIndex, Vec)>; -type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, usize)>; +type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] struct FileMapIndex(u32); +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, RustcEncodable, RustcDecodable)] +struct AbsoluteBytePos(u32); + +impl AbsoluteBytePos { + fn new(pos: usize) -> AbsoluteBytePos { + debug_assert!(pos <= ::std::u32::MAX as usize); + AbsoluteBytePos(pos as u32) + } + + fn to_usize(self) -> usize { + self.0 as usize + } +} + impl<'sess> OnDiskCache<'sess> { /// Create a new OnDiskCache instance from the serialized data in `data`. pub fn new(sess: &'sess Session, data: Vec, start_pos: usize) -> OnDiskCache<'sess> { @@ -309,7 +323,7 @@ impl<'sess> OnDiskCache<'sess> { let mut decoder = CacheDecoder { tcx: Some(tcx), - opaque: opaque::Decoder::new(&self.serialized_data[..], pos), + opaque: opaque::Decoder::new(&self.serialized_data[..], pos.to_usize()), codemap: self.codemap, cnum_map: cnum_map.as_ref().unwrap(), file_index_to_file: &mut file_index_to_file, @@ -389,7 +403,7 @@ struct CacheDecoder<'a, 'tcx: 'a, 'x> { opaque: opaque::Decoder<'x>, codemap: &'x CodeMap, cnum_map: &'x IndexVec>, - synthetic_expansion_infos: &'x mut FxHashMap, + synthetic_expansion_infos: &'x mut FxHashMap, file_index_to_file: &'x mut FxHashMap>, file_index_to_stable_id: &'x FxHashMap, } @@ -521,18 +535,18 @@ impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { SyntaxContext::empty() } TAG_EXPANSION_INFO_INLINE => { - let pos = self.position(); + let pos = AbsoluteBytePos::new(self.position()); let expn_info: ExpnInfo = Decodable::decode(self)?; let ctxt = SyntaxContext::allocate_directly(expn_info); self.synthetic_expansion_infos.insert(pos, ctxt); ctxt } TAG_EXPANSION_INFO_SHORTHAND => { - let pos = usize::decode(self)?; + let pos = AbsoluteBytePos::decode(self)?; if let Some(ctxt) = self.synthetic_expansion_infos.get(&pos).cloned() { ctxt } else { - let expn_info = self.with_position(pos, |this| { + let expn_info = self.with_position(pos.to_usize(), |this| { ExpnInfo::decode(this) })?; let ctxt = SyntaxContext::allocate_directly(expn_info); @@ -644,7 +658,7 @@ struct CacheEncoder<'enc, 'a, 'tcx, E> encoder: &'enc mut E, type_shorthands: FxHashMap, usize>, predicate_shorthands: FxHashMap, usize>, - expn_info_shorthands: FxHashMap, + expn_info_shorthands: FxHashMap, codemap: CachingCodemapView<'tcx>, file_to_file_index: FxHashMap<*const FileMap, FileMapIndex>, } @@ -725,7 +739,7 @@ impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'a, 'tcx pos.encode(self) } else { TAG_EXPANSION_INFO_INLINE.encode(self)?; - let pos = self.position(); + let pos = AbsoluteBytePos::new(self.position()); self.expn_info_shorthands.insert(mark, pos); expn_info.encode(self) } @@ -951,7 +965,7 @@ fn encode_query_results<'enc, 'a, 'tcx, Q, E>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let dep_node = SerializedDepNodeIndex::new(entry.index.index()); // Record position of the cache entry - query_result_index.push((dep_node, encoder.position())); + query_result_index.push((dep_node, AbsoluteBytePos::new(encoder.position()))); // Encode the type check tables with the SerializedDepNodeIndex // as tag. From 059bd805262b3a9e90226eadc2262ee96619eacb Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 28 Nov 2017 16:58:02 +0100 Subject: [PATCH 4/7] incr.comp.: Load diagnostics from previous session lazily and clean up on-disk-cache persistence code. --- src/librustc/dep_graph/graph.rs | 10 +- src/librustc/ty/context.rs | 2 +- src/librustc/ty/maps/on_disk_cache.rs | 288 ++++++++++++++------------ src/librustc/ty/maps/plumbing.rs | 2 +- src/libserialize/opaque.rs | 4 + 5 files changed, 165 insertions(+), 141 deletions(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 32f40367fab..e8e284236c8 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -461,10 +461,10 @@ impl DepGraph { self.data.as_ref().and_then(|data| data.colors.borrow().get(dep_node).cloned()) } - pub fn try_mark_green(&self, - tcx: TyCtxt, - dep_node: &DepNode) - -> Option { + pub fn try_mark_green<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + dep_node: &DepNode) + -> Option { debug!("try_mark_green({:?}) - BEGIN", dep_node); let data = self.data.as_ref().unwrap(); @@ -621,7 +621,7 @@ impl DepGraph { // ... emitting any stored diagnostic ... { let diagnostics = tcx.on_disk_query_result_cache - .load_diagnostics(prev_dep_node_index); + .load_diagnostics(tcx, prev_dep_node_index); if diagnostics.len() > 0 { let handle = tcx.sess.diagnostic(); diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 385cf0ecd85..0ab769d4fe3 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1235,7 +1235,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { -> Result<(), E::Error> where E: ty::codec::TyEncoder { - self.on_disk_query_result_cache.serialize(self.global_tcx(), self.cstore, encoder) + self.on_disk_query_result_cache.serialize(self.global_tcx(), encoder) } } diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index 18304b7aa7d..0d09692bc35 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -34,10 +34,7 @@ use ty; use ty::codec::{self as ty_codec, TyDecoder, TyEncoder}; use ty::context::TyCtxt; -// Some magic values used for verifying that encoding and decoding. These are -// basically random numbers. -const PREV_DIAGNOSTICS_TAG: u64 = 0x1234_5678_A1A1_A1A1; -const QUERY_RESULT_INDEX_TAG: u64 = 0x1234_5678_C3C3_C3C3; +const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE; const TAG_CLEAR_CROSS_CRATE_CLEAR: u8 = 0; const TAG_CLEAR_CROSS_CRATE_SET: u8 = 1; @@ -58,9 +55,6 @@ pub struct OnDiskCache<'sess> { // The complete cache data in serialized form. serialized_data: Vec, - // The diagnostics emitted during the previous compilation session. - prev_diagnostics: FxHashMap>, - // This field collects all Diagnostics emitted during the current // compilation session. current_diagnostics: RefCell>>, @@ -78,17 +72,24 @@ pub struct OnDiskCache<'sess> { // A map from dep-node to the position of the cached query result in // `serialized_data`. query_result_index: FxHashMap, + + // A map from dep-node to the position of any associated diagnostics in + // `serialized_data`. + prev_diagnostics_index: FxHashMap, } // This type is used only for (de-)serialization. #[derive(RustcEncodable, RustcDecodable)] -struct Header { +struct Footer { file_index_to_stable_id: FxHashMap, prev_cnums: Vec<(u32, String, CrateDisambiguator)>, + query_result_index: EncodedQueryResultIndex, + diagnostics_index: EncodedQueryResultIndex, } -type EncodedPrevDiagnostics = Vec<(SerializedDepNodeIndex, Vec)>; type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; +type EncodedDiagnosticsIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; +type EncodedDiagnostics = Vec; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] struct FileMapIndex(u32); @@ -112,73 +113,40 @@ impl<'sess> OnDiskCache<'sess> { pub fn new(sess: &'sess Session, data: Vec, start_pos: usize) -> OnDiskCache<'sess> { debug_assert!(sess.opts.incremental.is_some()); - // Decode the header - let (header, post_header_pos) = { + // Wrapping in a scope so we can borrow `data` + let footer: Footer = { let mut decoder = opaque::Decoder::new(&data[..], start_pos); - let header = Header::decode(&mut decoder) - .expect("Error while trying to decode incr. comp. cache header."); - (header, decoder.position()) - }; - let mut synthetic_expansion_infos = FxHashMap(); - let mut file_index_to_file = FxHashMap(); + // Decode the *position* of the footer which can be found in the + // last 8 bytes of the file. + decoder.set_position(data.len() - IntEncodedWithFixedSize::ENCODED_SIZE); + let query_result_index_pos = IntEncodedWithFixedSize::decode(&mut decoder) + .expect("Error while trying to decode query result index position.") + .0 as usize; - let (prev_diagnostics, query_result_index) = { - let mut decoder = CacheDecoder { - tcx: None, - opaque: opaque::Decoder::new(&data[..], post_header_pos), - codemap: sess.codemap(), - cnum_map: &IndexVec::new(), - synthetic_expansion_infos: &mut synthetic_expansion_infos, - file_index_to_file: &mut file_index_to_file, - file_index_to_stable_id: &header.file_index_to_stable_id, - }; - - // Decode Diagnostics - let prev_diagnostics: FxHashMap<_, _> = { - let diagnostics: EncodedPrevDiagnostics = - decode_tagged(&mut decoder, PREV_DIAGNOSTICS_TAG) - .expect("Error while trying to decode previous session \ - diagnostics from incr. comp. cache."); - diagnostics.into_iter().collect() - }; - - // Decode the *position* of the query result index - let query_result_index_pos = { - let pos_pos = data.len() - IntEncodedWithFixedSize::ENCODED_SIZE; - decoder.with_position(pos_pos, |decoder| { - IntEncodedWithFixedSize::decode(decoder) - }).expect("Error while trying to decode query result index position.") - .0 as usize - }; - - // Decode the query result index itself - let query_result_index: EncodedQueryResultIndex = - decoder.with_position(query_result_index_pos, |decoder| { - decode_tagged(decoder, QUERY_RESULT_INDEX_TAG) - }).expect("Error while trying to decode query result index."); - - (prev_diagnostics, query_result_index) + // Decoder the file footer which contains all the lookup tables, etc. + decoder.set_position(query_result_index_pos); + decode_tagged(&mut decoder, TAG_FILE_FOOTER) + .expect("Error while trying to decode query result index position.") }; OnDiskCache { serialized_data: data, - prev_diagnostics, - file_index_to_stable_id: header.file_index_to_stable_id, - file_index_to_file: RefCell::new(file_index_to_file), - prev_cnums: header.prev_cnums, + file_index_to_stable_id: footer.file_index_to_stable_id, + file_index_to_file: RefCell::new(FxHashMap()), + prev_cnums: footer.prev_cnums, cnum_map: RefCell::new(None), codemap: sess.codemap(), current_diagnostics: RefCell::new(FxHashMap()), - query_result_index: query_result_index.into_iter().collect(), - synthetic_expansion_infos: RefCell::new(synthetic_expansion_infos), + query_result_index: footer.query_result_index.into_iter().collect(), + prev_diagnostics_index: footer.diagnostics_index.into_iter().collect(), + synthetic_expansion_infos: RefCell::new(FxHashMap()), } } pub fn new_empty(codemap: &'sess CodeMap) -> OnDiskCache<'sess> { OnDiskCache { serialized_data: Vec::new(), - prev_diagnostics: FxHashMap(), file_index_to_stable_id: FxHashMap(), file_index_to_file: RefCell::new(FxHashMap()), prev_cnums: vec![], @@ -186,13 +154,13 @@ impl<'sess> OnDiskCache<'sess> { codemap, current_diagnostics: RefCell::new(FxHashMap()), query_result_index: FxHashMap(), + prev_diagnostics_index: FxHashMap(), synthetic_expansion_infos: RefCell::new(FxHashMap()), } } pub fn serialize<'a, 'tcx, E>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - cstore: &CrateStore, encoder: &mut E) -> Result<(), E::Error> where E: ty_codec::TyEncoder @@ -225,31 +193,6 @@ impl<'sess> OnDiskCache<'sess> { file_to_file_index, }; - // Encode the file header - let sorted_cnums = sorted_cnums_including_local_crate(cstore); - - let prev_cnums: Vec<_> = sorted_cnums.iter().map(|&cnum| { - let crate_name = tcx.original_crate_name(cnum).as_str().to_string(); - let crate_disambiguator = tcx.crate_disambiguator(cnum); - (cnum.as_u32(), crate_name, crate_disambiguator) - }).collect(); - - Header { - file_index_to_stable_id, - prev_cnums, - }.encode(&mut encoder)?; - - - // Encode Diagnostics - let diagnostics: EncodedPrevDiagnostics = - self.current_diagnostics - .borrow() - .iter() - .map(|(k, v)| (SerializedDepNodeIndex::new(k.index()), v.clone())) - .collect(); - - encoder.encode_tagged(PREV_DIAGNOSTICS_TAG, &diagnostics)?; - // Load everything into memory so we can write it out to the on-disk // cache. The vast majority of cacheable query results should already // be in memory, so this should be a cheap operation. @@ -267,19 +210,53 @@ impl<'sess> OnDiskCache<'sess> { encode_query_results::(tcx, enc, qri)?; } - // Encode query result index - let query_result_index_pos = encoder.position() as u64; - encoder.encode_tagged(QUERY_RESULT_INDEX_TAG, &query_result_index)?; + // Encode diagnostics + let diagnostics_index = { + let mut diagnostics_index = EncodedDiagnosticsIndex::new(); - // Encode the position of the query result index as the last 8 bytes of + for (dep_node_index, diagnostics) in self.current_diagnostics + .borrow() + .iter() { + let pos = AbsoluteBytePos::new(encoder.position()); + // Let's make sure we get the expected type here: + let diagnostics: &EncodedDiagnostics = diagnostics; + let dep_node_index = + SerializedDepNodeIndex::new(dep_node_index.index()); + encoder.encode_tagged(dep_node_index, diagnostics)?; + diagnostics_index.push((dep_node_index, pos)); + } + + diagnostics_index + }; + + let sorted_cnums = sorted_cnums_including_local_crate(tcx); + let prev_cnums: Vec<_> = sorted_cnums.iter().map(|&cnum| { + let crate_name = tcx.original_crate_name(cnum).as_str().to_string(); + let crate_disambiguator = tcx.crate_disambiguator(cnum); + (cnum.as_u32(), crate_name, crate_disambiguator) + }).collect(); + + // Encode the file footer + let footer_pos = encoder.position() as u64; + encoder.encode_tagged(TAG_FILE_FOOTER, &Footer { + file_index_to_stable_id, + prev_cnums, + query_result_index, + diagnostics_index, + })?; + + // Encode the position of the footer as the last 8 bytes of the // file so we know where to look for it. - IntEncodedWithFixedSize(query_result_index_pos).encode(&mut encoder)?; + IntEncodedWithFixedSize(footer_pos).encode(encoder.encoder)?; + + // DO NOT WRITE ANYTHING TO THE ENCODER AFTER THIS POINT! The address + // of the footer must be the last thing in the data stream. return Ok(()); - fn sorted_cnums_including_local_crate(cstore: &CrateStore) -> Vec { + fn sorted_cnums_including_local_crate(tcx: TyCtxt) -> Vec { let mut cnums = vec![LOCAL_CRATE]; - cnums.extend_from_slice(&cstore.crates_untracked()[..]); + cnums.extend_from_slice(&tcx.crates()[..]); cnums.sort_unstable(); // Just to be sure... cnums.dedup(); @@ -288,10 +265,17 @@ impl<'sess> OnDiskCache<'sess> { } /// Load a diagnostic emitted during the previous compilation session. - pub fn load_diagnostics(&self, - dep_node_index: SerializedDepNodeIndex) - -> Vec { - self.prev_diagnostics.get(&dep_node_index).cloned().unwrap_or(vec![]) + pub fn load_diagnostics<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + dep_node_index: SerializedDepNodeIndex) + -> Vec { + let diagnostics: Option = self.load_indexed( + tcx, + dep_node_index, + &self.prev_diagnostics_index, + "diagnostics"); + + diagnostics.unwrap_or(Vec::new()) } /// Store a diagnostic emitted during the current compilation session. @@ -311,33 +295,14 @@ impl<'sess> OnDiskCache<'sess> { -> T where T: Decodable { - let pos = self.query_result_index[&dep_node_index]; - - let mut cnum_map = self.cnum_map.borrow_mut(); - if cnum_map.is_none() { - *cnum_map = Some(Self::compute_cnum_map(tcx, &self.prev_cnums[..])); - } - - let mut synthetic_expansion_infos = self.synthetic_expansion_infos.borrow_mut(); - let mut file_index_to_file = self.file_index_to_file.borrow_mut(); - - let mut decoder = CacheDecoder { - tcx: Some(tcx), - opaque: opaque::Decoder::new(&self.serialized_data[..], pos.to_usize()), - codemap: self.codemap, - cnum_map: cnum_map.as_ref().unwrap(), - file_index_to_file: &mut file_index_to_file, - file_index_to_stable_id: &self.file_index_to_stable_id, - synthetic_expansion_infos: &mut synthetic_expansion_infos, - }; - - match decode_tagged(&mut decoder, dep_node_index) { - Ok(value) => { - value - } - Err(e) => { - bug!("Could not decode cached query result: {}", e) - } + let result = self.load_indexed(tcx, + dep_node_index, + &self.query_result_index, + "query result"); + if let Some(result) = result { + result + } else { + bug!("Could not find query result for key {:?}", dep_node_index) } } @@ -357,6 +322,49 @@ impl<'sess> OnDiskCache<'sess> { x.extend(diagnostics.into_iter()); } + fn load_indexed<'a, 'tcx, T>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + dep_node_index: SerializedDepNodeIndex, + index: &FxHashMap, + debug_tag: &'static str) + -> Option + where T: Decodable + { + let pos = if let Some(&pos) = index.get(&dep_node_index) { + pos + } else { + return None + }; + + let mut cnum_map = self.cnum_map.borrow_mut(); + if cnum_map.is_none() { + *cnum_map = Some(Self::compute_cnum_map(tcx, &self.prev_cnums[..])); + } + + let mut synthetic_expansion_infos = self.synthetic_expansion_infos.borrow_mut(); + let mut file_index_to_file = self.file_index_to_file.borrow_mut(); + + let mut decoder = CacheDecoder { + tcx, + opaque: opaque::Decoder::new(&self.serialized_data[..], pos.to_usize()), + codemap: self.codemap, + cnum_map: cnum_map.as_ref().unwrap(), + file_index_to_file: &mut file_index_to_file, + file_index_to_stable_id: &self.file_index_to_stable_id, + synthetic_expansion_infos: &mut synthetic_expansion_infos, + }; + + match decode_tagged(&mut decoder, dep_node_index) { + Ok(value) => { + Some(value) + } + Err(e) => { + bug!("Could not decode cached {}: {}", debug_tag, e) + } + } + } + // This function builds mapping from previous-session-CrateNum to // current-session-CrateNum. There might be CrateNums from the previous // Session that don't occur in the current one. For these, the mapping @@ -399,7 +407,7 @@ impl<'sess> OnDiskCache<'sess> { /// we use for crate metadata decoding in that it can rebase spans and /// eventually will also handle things that contain `Ty` instances. struct CacheDecoder<'a, 'tcx: 'a, 'x> { - tcx: Option>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, opaque: opaque::Decoder<'x>, codemap: &'x CodeMap, cnum_map: &'x IndexVec>, @@ -425,6 +433,22 @@ impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> { } } +trait DecoderWithPosition: Decoder { + fn position(&self) -> usize; +} + +impl<'enc> DecoderWithPosition for opaque::Decoder<'enc> { + fn position(&self) -> usize { + self.position() + } +} + +impl<'a, 'tcx, 'x> DecoderWithPosition for CacheDecoder<'a, 'tcx, 'x> { + fn position(&self) -> usize { + self.opaque.position() + } +} + // Decode something that was encoded with encode_tagged() and verify that the // tag matches and the correct amount of bytes was read. fn decode_tagged<'a, 'tcx, D, T, V>(decoder: &mut D, @@ -432,7 +456,7 @@ fn decode_tagged<'a, 'tcx, D, T, V>(decoder: &mut D, -> Result where T: Decodable + Eq + ::std::fmt::Debug, V: Decodable, - D: Decoder + ty_codec::TyDecoder<'a, 'tcx>, + D: DecoderWithPosition, 'tcx: 'a, { let start_pos = decoder.position(); @@ -453,7 +477,7 @@ impl<'a, 'tcx: 'a, 'x> ty_codec::TyDecoder<'a, 'tcx> for CacheDecoder<'a, 'tcx, #[inline] fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { - self.tcx.expect("missing TyCtxt in CacheDecoder") + self.tcx } #[inline] @@ -535,7 +559,7 @@ impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { SyntaxContext::empty() } TAG_EXPANSION_INFO_INLINE => { - let pos = AbsoluteBytePos::new(self.position()); + let pos = AbsoluteBytePos::new(self.opaque.position()); let expn_info: ExpnInfo = Decodable::decode(self)?; let ctxt = SyntaxContext::allocate_directly(expn_info); self.synthetic_expansion_infos.insert(pos, ctxt); @@ -919,10 +943,7 @@ impl IntEncodedWithFixedSize { impl UseSpecializedEncodable for IntEncodedWithFixedSize {} impl UseSpecializedDecodable for IntEncodedWithFixedSize {} -impl<'enc, 'a, 'tcx, E> SpecializedEncoder -for CacheEncoder<'enc, 'a, 'tcx, E> - where E: 'enc + ty_codec::TyEncoder -{ +impl<'enc> SpecializedEncoder for opaque::Encoder<'enc> { fn specialized_encode(&mut self, x: &IntEncodedWithFixedSize) -> Result<(), Self::Error> { let start_pos = self.position(); for i in 0 .. IntEncodedWithFixedSize::ENCODED_SIZE { @@ -934,8 +955,7 @@ for CacheEncoder<'enc, 'a, 'tcx, E> } } -impl<'a, 'tcx, 'x> SpecializedDecoder -for CacheDecoder<'a, 'tcx, 'x> { +impl<'enc> SpecializedDecoder for opaque::Decoder<'enc> { fn specialized_decode(&mut self) -> Result { let mut value: u64 = 0; let start_pos = self.position(); diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 75df4dc524a..3121cceeea0 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -145,7 +145,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { if !self.dep_graph.is_fully_enabled() { return None; } - match self.dep_graph.try_mark_green(self, &dep_node) { + match self.dep_graph.try_mark_green(self.global_tcx(), &dep_node) { Some(dep_node_index) => { debug_assert!(self.dep_graph.is_green(dep_node_index)); self.dep_graph.read_index(dep_node_index); diff --git a/src/libserialize/opaque.rs b/src/libserialize/opaque.rs index f3475bd18ce..99557659b29 100644 --- a/src/libserialize/opaque.rs +++ b/src/libserialize/opaque.rs @@ -162,6 +162,10 @@ impl<'a> Decoder<'a> { self.position } + pub fn set_position(&mut self, pos: usize) { + self.position = pos + } + pub fn advance(&mut self, bytes: usize) { self.position += bytes; } From c531d9f733e504697309ba6b85ff18ec276da162 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 28 Nov 2017 17:32:28 +0100 Subject: [PATCH 5/7] incr.comp.: Allow for recovering from missing on-disk cache entries. --- src/librustc/ty/maps/config.rs | 20 +++++++++++--------- src/librustc/ty/maps/on_disk_cache.rs | 23 ++++++++++------------- src/librustc/ty/maps/plumbing.rs | 25 ++++++++++++++++++++++--- 3 files changed, 43 insertions(+), 25 deletions(-) diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index 066b80cefa4..ffddde557da 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -31,9 +31,9 @@ pub(super) trait QueryDescription<'tcx>: QueryConfig { false } - fn load_from_disk<'a>(_: TyCtxt<'a, 'tcx, 'tcx>, - _: SerializedDepNodeIndex) - -> Self::Value { + fn try_load_from_disk<'a>(_: TyCtxt<'a, 'tcx, 'tcx>, + _: SerializedDepNodeIndex) + -> Option { bug!("QueryDescription::load_from_disk() called for unsupport query.") } } @@ -556,12 +556,14 @@ impl<'tcx> QueryDescription<'tcx> for queries::typeck_tables_of<'tcx> { def_id.is_local() } - fn load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: SerializedDepNodeIndex) - -> Self::Value { - let typeck_tables: ty::TypeckTables<'tcx> = tcx.on_disk_query_result_cache - .load_query_result(tcx, id); - tcx.alloc_tables(typeck_tables) + fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + id: SerializedDepNodeIndex) + -> Option { + let typeck_tables: Option> = tcx + .on_disk_query_result_cache + .try_load_query_result(tcx, id); + + typeck_tables.map(|tables| tcx.alloc_tables(tables)) } } diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index 0d09692bc35..ca0c3bafea8 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -289,21 +289,18 @@ impl<'sess> OnDiskCache<'sess> { debug_assert!(prev.is_none()); } - pub fn load_query_result<'a, 'tcx, T>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - dep_node_index: SerializedDepNodeIndex) - -> T + /// Returns the cached query result if there is something in the cache for + /// the given SerializedDepNodeIndex. Otherwise returns None. + pub fn try_load_query_result<'a, 'tcx, T>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + dep_node_index: SerializedDepNodeIndex) + -> Option where T: Decodable { - let result = self.load_indexed(tcx, - dep_node_index, - &self.query_result_index, - "query result"); - if let Some(result) = result { - result - } else { - bug!("Could not find query result for key {:?}", dep_node_index) - } + self.load_indexed(tcx, + dep_node_index, + &self.query_result_index, + "query result") } /// Store a diagnostic emitted during computation of an anonymous query. diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 3121cceeea0..fdaa13e7fd1 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -392,12 +392,31 @@ macro_rules! define_maps { { debug_assert!(tcx.dep_graph.is_green(dep_node_index)); - let result = if tcx.sess.opts.debugging_opts.incremental_queries && - Self::cache_on_disk(key) { + // First we try to load the result from the on-disk cache + let result = if Self::cache_on_disk(key) && + tcx.sess.opts.debugging_opts.incremental_queries { let prev_dep_node_index = tcx.dep_graph.prev_dep_node_index_of(dep_node); - Self::load_from_disk(tcx.global_tcx(), prev_dep_node_index) + let result = Self::try_load_from_disk(tcx.global_tcx(), + prev_dep_node_index); + + // We always expect to find a cached result for things that + // can be forced from DepNode. + debug_assert!(!dep_node.kind.can_reconstruct_query_key() || + result.is_some(), + "Missing on-disk cache entry for {:?}", + dep_node); + result } else { + // Some things are never cached on disk. + None + }; + + let result = if let Some(result) = result { + result + } else { + // We could not load a result from the on-disk cache, so + // recompute. let (result, _ ) = tcx.cycle_check(span, Query::$name(key), || { // The diagnostics for this query have already been // promoted to the current session during From 410f8509b5ef5286195200eb5806e9fa1777b58e Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 29 Nov 2017 12:42:59 +0100 Subject: [PATCH 6/7] incr.comp.: Use the awesome new '_ in a few places. --- src/librustc/dep_graph/graph.rs | 8 ++++---- src/librustc/ty/maps/config.rs | 12 ++++++------ src/librustc/ty/maps/on_disk_cache.rs | 22 +++++++++++----------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index e8e284236c8..96d6b0f79cf 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -461,10 +461,10 @@ impl DepGraph { self.data.as_ref().and_then(|data| data.colors.borrow().get(dep_node).cloned()) } - pub fn try_mark_green<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - dep_node: &DepNode) - -> Option { + pub fn try_mark_green<'tcx>(&self, + tcx: TyCtxt<'_, 'tcx, 'tcx>, + dep_node: &DepNode) + -> Option { debug!("try_mark_green({:?}) - BEGIN", dep_node); let data = self.data.as_ref().unwrap(); diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index ffddde557da..496284ad9c9 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -31,9 +31,9 @@ pub(super) trait QueryDescription<'tcx>: QueryConfig { false } - fn try_load_from_disk<'a>(_: TyCtxt<'a, 'tcx, 'tcx>, - _: SerializedDepNodeIndex) - -> Option { + fn try_load_from_disk(_: TyCtxt<'_, 'tcx, 'tcx>, + _: SerializedDepNodeIndex) + -> Option { bug!("QueryDescription::load_from_disk() called for unsupport query.") } } @@ -556,9 +556,9 @@ impl<'tcx> QueryDescription<'tcx> for queries::typeck_tables_of<'tcx> { def_id.is_local() } - fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: SerializedDepNodeIndex) - -> Option { + fn try_load_from_disk(tcx: TyCtxt<'_, 'tcx, 'tcx>, + id: SerializedDepNodeIndex) + -> Option { let typeck_tables: Option> = tcx .on_disk_query_result_cache .try_load_query_result(tcx, id); diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index ca0c3bafea8..c0daba5cace 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -291,10 +291,10 @@ impl<'sess> OnDiskCache<'sess> { /// Returns the cached query result if there is something in the cache for /// the given SerializedDepNodeIndex. Otherwise returns None. - pub fn try_load_query_result<'a, 'tcx, T>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - dep_node_index: SerializedDepNodeIndex) - -> Option + pub fn try_load_query_result<'tcx, T>(&self, + tcx: TyCtxt<'_, 'tcx, 'tcx>, + dep_node_index: SerializedDepNodeIndex) + -> Option where T: Decodable { self.load_indexed(tcx, @@ -319,13 +319,13 @@ impl<'sess> OnDiskCache<'sess> { x.extend(diagnostics.into_iter()); } - fn load_indexed<'a, 'tcx, T>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - dep_node_index: SerializedDepNodeIndex, - index: &FxHashMap, - debug_tag: &'static str) - -> Option + fn load_indexed<'tcx, T>(&self, + tcx: TyCtxt<'_, 'tcx, 'tcx>, + dep_node_index: SerializedDepNodeIndex, + index: &FxHashMap, + debug_tag: &'static str) + -> Option where T: Decodable { let pos = if let Some(&pos) = index.get(&dep_node_index) { From 966eead9ec4d95f887d1eb5d0fc4b72b5779e952 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 1 Dec 2017 14:29:20 +0100 Subject: [PATCH 7/7] incr.comp.: Fix merge fallout. --- src/librustc/ty/maps/on_disk_cache.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index c0daba5cace..8dc9b0877a0 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -15,7 +15,6 @@ use hir::def_id::{CrateNum, DefIndex, DefId, LocalDefId, RESERVED_FOR_INCR_COMP_CACHE, LOCAL_CRATE}; use hir::map::definitions::DefPathHash; use ich::CachingCodemapView; -use middle::cstore::CrateStore; use mir; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::{IndexVec, Idx};