diff options
Diffstat (limited to 'compiler/rustc_query_impl/src')
| -rw-r--r-- | compiler/rustc_query_impl/src/keys.rs | 48 | ||||
| -rw-r--r-- | compiler/rustc_query_impl/src/lib.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_query_impl/src/on_disk_cache.rs | 112 | ||||
| -rw-r--r-- | compiler/rustc_query_impl/src/plumbing.rs | 9 | ||||
| -rw-r--r-- | compiler/rustc_query_impl/src/util.rs | 18 |
5 files changed, 143 insertions, 46 deletions
diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs index ace7cffd16d..42e8b4023cf 100644 --- a/compiler/rustc_query_impl/src/keys.rs +++ b/compiler/rustc_query_impl/src/keys.rs @@ -20,6 +20,12 @@ pub trait Key { /// In the event that a cycle occurs, if no explicit span has been /// given for a query with key `self`, what span should we use? fn default_span(&self, tcx: TyCtxt<'_>) -> Span; + + /// If the key is a [`DefId`] or `DefId`--equivalent, return that `DefId`. + /// Otherwise, return `None`. + fn key_as_def_id(&self) -> Option<DefId> { + None + } } impl Key for () { @@ -95,6 +101,9 @@ impl Key for LocalDefId { fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.to_def_id().default_span(tcx) } + fn key_as_def_id(&self) -> Option<DefId> { + Some(self.to_def_id()) + } } impl Key for DefId { @@ -105,6 +114,10 @@ impl Key for DefId { fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(*self) } + #[inline(always)] + fn key_as_def_id(&self) -> Option<DefId> { + Some(*self) + } } impl Key for ty::WithOptConstParam<LocalDefId> { @@ -165,6 +178,10 @@ impl Key for (DefId, Option<Ident>) { fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.0) } + #[inline(always)] + fn key_as_def_id(&self) -> Option<DefId> { + Some(self.0) + } } impl Key for (DefId, LocalDefId, Ident) { @@ -217,18 +234,13 @@ impl<'tcx> Key for (DefId, SubstsRef<'tcx>) { } } -impl<'tcx> Key - for ( - (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>), - (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>), - ) -{ +impl<'tcx> Key for (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>) { #[inline(always)] fn query_crate_is_local(&self) -> bool { - (self.0).0.did.krate == LOCAL_CRATE + (self.0).def.did.krate == LOCAL_CRATE } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { - (self.0).0.did.default_span(tcx) + (self.0).def.did.default_span(tcx) } } @@ -282,6 +294,16 @@ impl<'tcx> Key for ty::PolyTraitRef<'tcx> { } } +impl<'tcx> Key for ty::PolyExistentialTraitRef<'tcx> { + #[inline(always)] + fn query_crate_is_local(&self) -> bool { + self.def_id().krate == LOCAL_CRATE + } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + tcx.def_span(self.def_id()) + } +} + impl<'tcx> Key for (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>) { #[inline(always)] fn query_crate_is_local(&self) -> bool { @@ -332,6 +354,16 @@ impl<'tcx> Key for Ty<'tcx> { } } +impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) { + #[inline(always)] + fn query_crate_is_local(&self) -> bool { + true + } + fn default_span(&self, _: TyCtxt<'_>) -> Span { + DUMMY_SP + } +} + impl<'tcx> Key for &'tcx ty::List<ty::Predicate<'tcx>> { #[inline(always)] fn query_crate_is_local(&self) -> bool { diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 5022bf26532..bb0e6511159 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -51,6 +51,8 @@ pub use on_disk_cache::OnDiskCache; mod profiling_support; pub use self::profiling_support::alloc_self_profile_query_strings; +mod util; + rustc_query_append! { [define_queries!][<'tcx>] } impl<'tcx> Queries<'tcx> { diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs index ee64f22618e..bfd36bfb2db 100644 --- a/compiler/rustc_query_impl/src/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -1,6 +1,7 @@ use crate::QueryCtxt; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; -use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, OnceCell}; +use rustc_data_structures::memmap::Mmap; +use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, OnceCell, RwLock}; use rustc_data_structures::unhash::UnhashMap; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::DefPathHash; @@ -8,6 +9,7 @@ use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex}; use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_middle::mir::{self, interpret}; +use rustc_middle::thir; use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_query_system::dep_graph::DepContext; @@ -22,7 +24,7 @@ use rustc_span::hygiene::{ }; use rustc_span::source_map::{SourceMap, StableSourceFileId}; use rustc_span::CachingSourceMapView; -use rustc_span::{BytePos, ExpnData, ExpnHash, SourceFile, Span, DUMMY_SP}; +use rustc_span::{BytePos, ExpnData, ExpnHash, Pos, SourceFile, Span}; use std::collections::hash_map::Entry; use std::mem; @@ -32,6 +34,7 @@ const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE; const TAG_FULL_SPAN: u8 = 0; // A partial span with no location information, encoded only with a `SyntaxContext` const TAG_PARTIAL_SPAN: u8 = 1; +const TAG_RELATIVE_SPAN: u8 = 2; const TAG_SYNTAX_CONTEXT: u8 = 0; const TAG_EXPN_DATA: u8 = 1; @@ -42,7 +45,7 @@ const TAG_EXPN_DATA: u8 = 1; /// any side effects that have been emitted during a query. pub struct OnDiskCache<'sess> { // The complete cache data in serialized form. - serialized_data: Vec<u8>, + serialized_data: RwLock<Option<Mmap>>, // Collects all `QuerySideEffects` created during the current compilation // session. @@ -182,7 +185,8 @@ impl EncodedSourceFileId { } impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> { - fn new(sess: &'sess Session, data: Vec<u8>, start_pos: usize) -> Self { + /// Creates a new `OnDiskCache` instance from the serialized data in `data`. + fn new(sess: &'sess Session, data: Mmap, start_pos: usize) -> Self { debug_assert!(sess.opts.incremental.is_some()); // Wrap in a scope so we can borrow `data`. @@ -204,7 +208,7 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> { }; Self { - serialized_data: data, + serialized_data: RwLock::new(Some(data)), file_index_to_stable_id: footer.file_index_to_stable_id, file_index_to_file: Default::default(), cnum_map: OnceCell::new(), @@ -225,7 +229,7 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> { fn new_empty(source_map: &'sess SourceMap) -> Self { Self { - serialized_data: Vec::new(), + serialized_data: RwLock::new(None), file_index_to_stable_id: Default::default(), file_index_to_file: Default::default(), cnum_map: OnceCell::new(), @@ -244,7 +248,31 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> { } } - fn serialize(&self, tcx: TyCtxt<'sess>, encoder: &mut FileEncoder) -> FileEncodeResult { + /// Execute all cache promotions and release the serialized backing Mmap. + /// + /// Cache promotions require invoking queries, which needs to read the serialized data. + /// In order to serialize the new on-disk cache, the former on-disk cache file needs to be + /// deleted, hence we won't be able to refer to its memmapped data. + fn drop_serialized_data(&self, tcx: TyCtxt<'tcx>) { + // Register any dep nodes that we reused from the previous session, + // but didn't `DepNode::construct` in this session. This ensures + // that their `DefPathHash` to `RawDefId` mappings are registered + // in 'latest_foreign_def_path_hashes' if necessary, since that + // normally happens in `DepNode::construct`. + tcx.dep_graph.register_reused_dep_nodes(tcx); + + // 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. + // Do this *before* we clone 'latest_foreign_def_path_hashes', since + // loading existing queries may cause us to create new DepNodes, which + // may in turn end up invoking `store_foreign_def_id_hash` + tcx.dep_graph.exec_cache_promotions(QueryCtxt::from_tcx(tcx)); + + *self.serialized_data.write() = None; + } + + fn serialize<'tcx>(&self, tcx: TyCtxt<'tcx>, encoder: &mut FileEncoder) -> FileEncodeResult { // Serializing the `DepGraph` should not modify it. tcx.dep_graph.with_ignore(|| { // Allocate `SourceFileIndex`es. @@ -266,21 +294,6 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> { (file_to_file_index, file_index_to_stable_id) }; - // Register any dep nodes that we reused from the previous session, - // but didn't `DepNode::construct` in this session. This ensures - // that their `DefPathHash` to `RawDefId` mappings are registered - // in 'latest_foreign_def_path_hashes' if necessary, since that - // normally happens in `DepNode::construct`. - tcx.dep_graph.register_reused_dep_nodes(tcx); - - // 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. - // Do this *before* we clone 'latest_foreign_def_path_hashes', since - // loading existing queries may cause us to create new DepNodes, which - // may in turn end up invoking `store_foreign_def_id_hash` - tcx.dep_graph.exec_cache_promotions(QueryCtxt::from_tcx(tcx)); - let latest_foreign_def_path_hashes = self.latest_foreign_def_path_hashes.lock().clone(); let hygiene_encode_context = HygieneEncodeContext::default(); @@ -564,7 +577,7 @@ impl<'sess> OnDiskCache<'sess> { }) } - fn with_decoder<'a, 'tcx, T, F: FnOnce(&mut CacheDecoder<'sess, 'tcx>) -> T>( + fn with_decoder<'a, 'tcx, T, F: for<'s> FnOnce(&mut CacheDecoder<'s, 'tcx>) -> T>( &'sess self, tcx: TyCtxt<'tcx>, pos: AbsoluteBytePos, @@ -575,9 +588,10 @@ impl<'sess> OnDiskCache<'sess> { { let cnum_map = self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx)); + let serialized_data = self.serialized_data.read(); let mut decoder = CacheDecoder { tcx, - opaque: opaque::Decoder::new(&self.serialized_data[..], pos.to_usize()), + opaque: opaque::Decoder::new(serialized_data.as_deref().unwrap_or(&[]), pos.to_usize()), source_map: self.source_map, cnum_map, file_index_to_file: &self.file_index_to_file, @@ -817,11 +831,26 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId { impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span { fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { + let ctxt = SyntaxContext::decode(decoder)?; + let parent = Option::<LocalDefId>::decode(decoder)?; let tag: u8 = Decodable::decode(decoder)?; if tag == TAG_PARTIAL_SPAN { - let ctxt = SyntaxContext::decode(decoder)?; - return Ok(DUMMY_SP.with_ctxt(ctxt)); + return Ok(Span::new(BytePos(0), BytePos(0), ctxt, parent)); + } else if tag == TAG_RELATIVE_SPAN { + let dlo = u32::decode(decoder)?; + let dto = u32::decode(decoder)?; + + let enclosing = + decoder.tcx.definitions_untracked().def_span(parent.unwrap()).data_untracked(); + let span = Span::new( + enclosing.lo + BytePos::from_u32(dlo), + enclosing.lo + BytePos::from_u32(dto), + ctxt, + parent, + ); + + return Ok(span); } else { debug_assert_eq!(tag, TAG_FULL_SPAN); } @@ -830,13 +859,12 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span { let line_lo = usize::decode(decoder)?; let col_lo = BytePos::decode(decoder)?; let len = BytePos::decode(decoder)?; - let ctxt = SyntaxContext::decode(decoder)?; let file_lo = decoder.file_index_to_file(file_lo_index); let lo = file_lo.lines[line_lo - 1] + col_lo; let hi = lo + len; - Ok(Span::new(lo, hi, ctxt)) + Ok(Span::new(lo, hi, ctxt, parent)) } } @@ -894,7 +922,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> } } -impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] { +impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [thir::abstract_const::Node<'tcx>] { fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { RefDecodable::decode(d) } @@ -996,10 +1024,22 @@ where E: 'a + OpaqueEncoder, { fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> { - let span_data = self.data(); - if self.is_dummy() { - TAG_PARTIAL_SPAN.encode(s)?; - return span_data.ctxt.encode(s); + let span_data = self.data_untracked(); + span_data.ctxt.encode(s)?; + span_data.parent.encode(s)?; + + if span_data.is_dummy() { + return TAG_PARTIAL_SPAN.encode(s); + } + + if let Some(parent) = span_data.parent { + let enclosing = s.tcx.definitions_untracked().def_span(parent).data_untracked(); + if enclosing.contains(span_data) { + TAG_RELATIVE_SPAN.encode(s)?; + (span_data.lo - enclosing.lo).to_u32().encode(s)?; + (span_data.hi - enclosing.lo).to_u32().encode(s)?; + return Ok(()); + } } let pos = s.source_map.byte_pos_to_line_and_col(span_data.lo); @@ -1009,8 +1049,7 @@ where }; if partial_span { - TAG_PARTIAL_SPAN.encode(s)?; - return span_data.ctxt.encode(s); + return TAG_PARTIAL_SPAN.encode(s); } let (file_lo, line_lo, col_lo) = pos.unwrap(); @@ -1023,8 +1062,7 @@ where source_file_index.encode(s)?; line_lo.encode(s)?; col_lo.encode(s)?; - len.encode(s)?; - span_data.ctxt.encode(s) + len.encode(s) } } diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 5774d021373..90a6ba474b4 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -337,6 +337,13 @@ macro_rules! define_queries { } else { Some(key.default_span(*tcx)) }; + let def_id = key.key_as_def_id(); + let def_kind = def_id + .and_then(|def_id| def_id.as_local()) + // Use `tcx.hir().opt_def_kind()` to reduce the chance of + // accidentally triggering an infinite query loop. + .and_then(|def_id| tcx.hir().opt_def_kind(def_id)) + .map(|def_kind| $crate::util::def_kind_to_simple_def_kind(def_kind)); let hash = || { let mut hcx = tcx.create_stable_hashing_context(); let mut hasher = StableHasher::new(); @@ -345,7 +352,7 @@ macro_rules! define_queries { hasher.finish::<u64>() }; - QueryStackFrame::new(name, description, span, hash) + QueryStackFrame::new(name, description, span, def_kind, hash) })* } diff --git a/compiler/rustc_query_impl/src/util.rs b/compiler/rustc_query_impl/src/util.rs new file mode 100644 index 00000000000..517c107b5d9 --- /dev/null +++ b/compiler/rustc_query_impl/src/util.rs @@ -0,0 +1,18 @@ +use rustc_hir::def::DefKind; +use rustc_query_system::query::SimpleDefKind; + +/// Convert a [`DefKind`] to a [`SimpleDefKind`]. +/// +/// *See [`SimpleDefKind`]'s docs for more information.* +pub(crate) fn def_kind_to_simple_def_kind(def_kind: DefKind) -> SimpleDefKind { + match def_kind { + DefKind::Struct => SimpleDefKind::Struct, + DefKind::Enum => SimpleDefKind::Enum, + DefKind::Union => SimpleDefKind::Union, + DefKind::Trait => SimpleDefKind::Trait, + DefKind::TyAlias => SimpleDefKind::TyAlias, + DefKind::TraitAlias => SimpleDefKind::TraitAlias, + + _ => SimpleDefKind::Other, + } +} |
