Create QuerySideEffects
and use it for diagnostics
This commit is contained in:
parent
5782f01a51
commit
e6a5231238
5 changed files with 102 additions and 117 deletions
|
@ -1,9 +1,7 @@
|
||||||
use crate::QueryCtxt;
|
use crate::QueryCtxt;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
|
||||||
use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, OnceCell};
|
use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, OnceCell};
|
||||||
use rustc_data_structures::thin_vec::ThinVec;
|
|
||||||
use rustc_data_structures::unhash::UnhashMap;
|
use rustc_data_structures::unhash::UnhashMap;
|
||||||
use rustc_errors::Diagnostic;
|
|
||||||
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, StableCrateId, LOCAL_CRATE};
|
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, StableCrateId, LOCAL_CRATE};
|
||||||
use rustc_hir::definitions::DefPathHash;
|
use rustc_hir::definitions::DefPathHash;
|
||||||
use rustc_index::vec::{Idx, IndexVec};
|
use rustc_index::vec::{Idx, IndexVec};
|
||||||
|
@ -13,7 +11,7 @@ use rustc_middle::mir::{self, interpret};
|
||||||
use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder};
|
use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder};
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_query_system::dep_graph::DepContext;
|
use rustc_query_system::dep_graph::DepContext;
|
||||||
use rustc_query_system::query::QueryContext;
|
use rustc_query_system::query::{QueryContext, QuerySideEffects};
|
||||||
use rustc_serialize::{
|
use rustc_serialize::{
|
||||||
opaque::{self, FileEncodeResult, FileEncoder, IntEncodedWithFixedSize},
|
opaque::{self, FileEncodeResult, FileEncoder, IntEncodedWithFixedSize},
|
||||||
Decodable, Decoder, Encodable, Encoder,
|
Decodable, Decoder, Encodable, Encoder,
|
||||||
|
@ -41,14 +39,14 @@ const TAG_EXPN_DATA: u8 = 1;
|
||||||
/// Provides an interface to incremental compilation data cached from the
|
/// Provides an interface to incremental compilation data cached from the
|
||||||
/// previous compilation session. This data will eventually include the results
|
/// previous compilation session. This data will eventually include the results
|
||||||
/// of a few selected queries (like `typeck` and `mir_optimized`) and
|
/// of a few selected queries (like `typeck` and `mir_optimized`) and
|
||||||
/// any diagnostics that have been emitted during a query.
|
/// any side effects that have been emitted during a query.
|
||||||
pub struct OnDiskCache<'sess> {
|
pub struct OnDiskCache<'sess> {
|
||||||
// The complete cache data in serialized form.
|
// The complete cache data in serialized form.
|
||||||
serialized_data: Vec<u8>,
|
serialized_data: Vec<u8>,
|
||||||
|
|
||||||
// Collects all `Diagnostic`s emitted during the current compilation
|
// Collects all `QuerySideEffects` created during the current compilation
|
||||||
// session.
|
// session.
|
||||||
current_diagnostics: Lock<FxHashMap<DepNodeIndex, Vec<Diagnostic>>>,
|
current_side_effects: Lock<FxHashMap<DepNodeIndex, QuerySideEffects>>,
|
||||||
|
|
||||||
cnum_map: OnceCell<UnhashMap<StableCrateId, CrateNum>>,
|
cnum_map: OnceCell<UnhashMap<StableCrateId, CrateNum>>,
|
||||||
|
|
||||||
|
@ -62,9 +60,9 @@ pub struct OnDiskCache<'sess> {
|
||||||
// `serialized_data`.
|
// `serialized_data`.
|
||||||
query_result_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
|
query_result_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
|
||||||
|
|
||||||
// A map from dep-node to the position of any associated diagnostics in
|
// A map from dep-node to the position of any associated `QuerySideEffects` in
|
||||||
// `serialized_data`.
|
// `serialized_data`.
|
||||||
prev_diagnostics_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
|
prev_side_effects_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
|
||||||
|
|
||||||
alloc_decoding_state: AllocDecodingState,
|
alloc_decoding_state: AllocDecodingState,
|
||||||
|
|
||||||
|
@ -113,8 +111,8 @@ pub struct OnDiskCache<'sess> {
|
||||||
#[derive(Encodable, Decodable)]
|
#[derive(Encodable, Decodable)]
|
||||||
struct Footer {
|
struct Footer {
|
||||||
file_index_to_stable_id: FxHashMap<SourceFileIndex, EncodedSourceFileId>,
|
file_index_to_stable_id: FxHashMap<SourceFileIndex, EncodedSourceFileId>,
|
||||||
query_result_index: EncodedQueryResultIndex,
|
query_result_index: EncodedDepNodeIndex,
|
||||||
diagnostics_index: EncodedQueryResultIndex,
|
side_effects_index: EncodedDepNodeIndex,
|
||||||
// The location of all allocations.
|
// The location of all allocations.
|
||||||
interpret_alloc_index: Vec<u32>,
|
interpret_alloc_index: Vec<u32>,
|
||||||
// See `OnDiskCache.syntax_contexts`
|
// See `OnDiskCache.syntax_contexts`
|
||||||
|
@ -125,9 +123,7 @@ struct Footer {
|
||||||
foreign_expn_data: UnhashMap<ExpnHash, u32>,
|
foreign_expn_data: UnhashMap<ExpnHash, u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
|
pub type EncodedDepNodeIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
|
||||||
type EncodedDiagnosticsIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
|
|
||||||
type EncodedDiagnostics = Vec<Diagnostic>;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable, Decodable)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable, Decodable)]
|
||||||
struct SourceFileIndex(u32);
|
struct SourceFileIndex(u32);
|
||||||
|
@ -213,9 +209,9 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
|
||||||
file_index_to_file: Default::default(),
|
file_index_to_file: Default::default(),
|
||||||
cnum_map: OnceCell::new(),
|
cnum_map: OnceCell::new(),
|
||||||
source_map: sess.source_map(),
|
source_map: sess.source_map(),
|
||||||
current_diagnostics: Default::default(),
|
current_side_effects: Default::default(),
|
||||||
query_result_index: footer.query_result_index.into_iter().collect(),
|
query_result_index: footer.query_result_index.into_iter().collect(),
|
||||||
prev_diagnostics_index: footer.diagnostics_index.into_iter().collect(),
|
prev_side_effects_index: footer.side_effects_index.into_iter().collect(),
|
||||||
alloc_decoding_state: AllocDecodingState::new(footer.interpret_alloc_index),
|
alloc_decoding_state: AllocDecodingState::new(footer.interpret_alloc_index),
|
||||||
syntax_contexts: footer.syntax_contexts,
|
syntax_contexts: footer.syntax_contexts,
|
||||||
expn_data: footer.expn_data,
|
expn_data: footer.expn_data,
|
||||||
|
@ -234,9 +230,9 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
|
||||||
file_index_to_file: Default::default(),
|
file_index_to_file: Default::default(),
|
||||||
cnum_map: OnceCell::new(),
|
cnum_map: OnceCell::new(),
|
||||||
source_map,
|
source_map,
|
||||||
current_diagnostics: Default::default(),
|
current_side_effects: Default::default(),
|
||||||
query_result_index: Default::default(),
|
query_result_index: Default::default(),
|
||||||
prev_diagnostics_index: Default::default(),
|
prev_side_effects_index: Default::default(),
|
||||||
alloc_decoding_state: AllocDecodingState::new(Vec::new()),
|
alloc_decoding_state: AllocDecodingState::new(Vec::new()),
|
||||||
syntax_contexts: FxHashMap::default(),
|
syntax_contexts: FxHashMap::default(),
|
||||||
expn_data: UnhashMap::default(),
|
expn_data: UnhashMap::default(),
|
||||||
|
@ -301,7 +297,7 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Encode query results.
|
// Encode query results.
|
||||||
let mut query_result_index = EncodedQueryResultIndex::new();
|
let mut query_result_index = EncodedDepNodeIndex::new();
|
||||||
|
|
||||||
tcx.sess.time("encode_query_results", || -> FileEncodeResult {
|
tcx.sess.time("encode_query_results", || -> FileEncodeResult {
|
||||||
let enc = &mut encoder;
|
let enc = &mut encoder;
|
||||||
|
@ -309,18 +305,16 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
|
||||||
QueryCtxt::from_tcx(tcx).encode_query_results(enc, qri)
|
QueryCtxt::from_tcx(tcx).encode_query_results(enc, qri)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Encode diagnostics.
|
// Encode side effects.
|
||||||
let diagnostics_index: EncodedDiagnosticsIndex = self
|
let side_effects_index: EncodedDepNodeIndex = self
|
||||||
.current_diagnostics
|
.current_side_effects
|
||||||
.borrow()
|
.borrow()
|
||||||
.iter()
|
.iter()
|
||||||
.map(
|
.map(
|
||||||
|(dep_node_index, diagnostics)| -> Result<_, <FileEncoder as Encoder>::Error> {
|
|(dep_node_index, side_effects)| -> Result<_, <FileEncoder as Encoder>::Error> {
|
||||||
let pos = AbsoluteBytePos::new(encoder.position());
|
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());
|
let dep_node_index = SerializedDepNodeIndex::new(dep_node_index.index());
|
||||||
encoder.encode_tagged(dep_node_index, diagnostics)?;
|
encoder.encode_tagged(dep_node_index, side_effects)?;
|
||||||
|
|
||||||
Ok((dep_node_index, pos))
|
Ok((dep_node_index, pos))
|
||||||
},
|
},
|
||||||
|
@ -386,7 +380,7 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
|
||||||
&Footer {
|
&Footer {
|
||||||
file_index_to_stable_id,
|
file_index_to_stable_id,
|
||||||
query_result_index,
|
query_result_index,
|
||||||
diagnostics_index,
|
side_effects_index,
|
||||||
interpret_alloc_index,
|
interpret_alloc_index,
|
||||||
syntax_contexts,
|
syntax_contexts,
|
||||||
expn_data,
|
expn_data,
|
||||||
|
@ -488,30 +482,26 @@ impl<'sess> OnDiskCache<'sess> {
|
||||||
self as _
|
self as _
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads a diagnostic emitted during the previous compilation session.
|
/// Loads a `QuerySideEffects` created during the previous compilation session.
|
||||||
pub fn load_diagnostics(
|
pub fn load_side_effects(
|
||||||
&self,
|
&self,
|
||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'_>,
|
||||||
dep_node_index: SerializedDepNodeIndex,
|
dep_node_index: SerializedDepNodeIndex,
|
||||||
) -> Vec<Diagnostic> {
|
) -> QuerySideEffects {
|
||||||
let diagnostics: Option<EncodedDiagnostics> =
|
let side_effects: Option<QuerySideEffects> =
|
||||||
self.load_indexed(tcx, dep_node_index, &self.prev_diagnostics_index, "diagnostics");
|
self.load_indexed(tcx, dep_node_index, &self.prev_side_effects_index, "side_effects");
|
||||||
|
|
||||||
diagnostics.unwrap_or_default()
|
side_effects.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores a diagnostic emitted during the current compilation session.
|
/// Stores a `QuerySideEffects` emitted during the current compilation session.
|
||||||
/// Anything stored like this will be available via `load_diagnostics` in
|
/// Anything stored like this will be available via `load_side_effects` in
|
||||||
/// the next compilation session.
|
/// the next compilation session.
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[cold]
|
#[cold]
|
||||||
pub fn store_diagnostics(
|
pub fn store_side_effects(&self, dep_node_index: DepNodeIndex, side_effects: QuerySideEffects) {
|
||||||
&self,
|
let mut current_side_effects = self.current_side_effects.borrow_mut();
|
||||||
dep_node_index: DepNodeIndex,
|
let prev = current_side_effects.insert(dep_node_index, side_effects);
|
||||||
diagnostics: ThinVec<Diagnostic>,
|
|
||||||
) {
|
|
||||||
let mut current_diagnostics = self.current_diagnostics.borrow_mut();
|
|
||||||
let prev = current_diagnostics.insert(dep_node_index, diagnostics.into());
|
|
||||||
debug_assert!(prev.is_none());
|
debug_assert!(prev.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -539,22 +529,21 @@ impl<'sess> OnDiskCache<'sess> {
|
||||||
self.load_indexed(tcx, dep_node_index, &self.query_result_index, "query result")
|
self.load_indexed(tcx, dep_node_index, &self.query_result_index, "query result")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores a diagnostic emitted during computation of an anonymous query.
|
/// Stores side effect emitted during computation of an anonymous query.
|
||||||
/// Since many anonymous queries can share the same `DepNode`, we aggregate
|
/// Since many anonymous queries can share the same `DepNode`, we aggregate
|
||||||
/// them -- as opposed to regular queries where we assume that there is a
|
/// them -- as opposed to regular queries where we assume that there is a
|
||||||
/// 1:1 relationship between query-key and `DepNode`.
|
/// 1:1 relationship between query-key and `DepNode`.
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[cold]
|
#[cold]
|
||||||
pub fn store_diagnostics_for_anon_node(
|
pub fn store_side_effects_for_anon_node(
|
||||||
&self,
|
&self,
|
||||||
dep_node_index: DepNodeIndex,
|
dep_node_index: DepNodeIndex,
|
||||||
diagnostics: ThinVec<Diagnostic>,
|
side_effects: QuerySideEffects,
|
||||||
) {
|
) {
|
||||||
let mut current_diagnostics = self.current_diagnostics.borrow_mut();
|
let mut current_side_effects = self.current_side_effects.borrow_mut();
|
||||||
|
|
||||||
let x = current_diagnostics.entry(dep_node_index).or_default();
|
let x = current_side_effects.entry(dep_node_index).or_default();
|
||||||
|
x.append(side_effects);
|
||||||
x.extend(Into::<Vec<_>>::into(diagnostics));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_indexed<'tcx, T>(
|
fn load_indexed<'tcx, T>(
|
||||||
|
@ -1155,7 +1144,7 @@ impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx, FileEncoder>> for [u8] {
|
||||||
pub fn encode_query_results<'a, 'tcx, CTX, Q>(
|
pub fn encode_query_results<'a, 'tcx, CTX, Q>(
|
||||||
tcx: CTX,
|
tcx: CTX,
|
||||||
encoder: &mut CacheEncoder<'a, 'tcx, FileEncoder>,
|
encoder: &mut CacheEncoder<'a, 'tcx, FileEncoder>,
|
||||||
query_result_index: &mut EncodedQueryResultIndex,
|
query_result_index: &mut EncodedDepNodeIndex,
|
||||||
) -> FileEncodeResult
|
) -> FileEncodeResult
|
||||||
where
|
where
|
||||||
CTX: QueryContext + 'tcx,
|
CTX: QueryContext + 'tcx,
|
||||||
|
|
|
@ -7,7 +7,9 @@ use rustc_middle::dep_graph::{DepKind, DepNode, DepNodeIndex, SerializedDepNodeI
|
||||||
use rustc_middle::ty::tls::{self, ImplicitCtxt};
|
use rustc_middle::ty::tls::{self, ImplicitCtxt};
|
||||||
use rustc_middle::ty::{self, TyCtxt};
|
use rustc_middle::ty::{self, TyCtxt};
|
||||||
use rustc_query_system::dep_graph::HasDepContext;
|
use rustc_query_system::dep_graph::HasDepContext;
|
||||||
use rustc_query_system::query::{QueryContext, QueryDescription, QueryJobId, QueryMap};
|
use rustc_query_system::query::{
|
||||||
|
QueryContext, QueryDescription, QueryJobId, QueryMap, QuerySideEffects,
|
||||||
|
};
|
||||||
|
|
||||||
use rustc_data_structures::sync::Lock;
|
use rustc_data_structures::sync::Lock;
|
||||||
use rustc_data_structures::thin_vec::ThinVec;
|
use rustc_data_structures::thin_vec::ThinVec;
|
||||||
|
@ -83,27 +85,27 @@ impl QueryContext for QueryCtxt<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interactions with on_disk_cache
|
// Interactions with on_disk_cache
|
||||||
fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec<Diagnostic> {
|
fn load_side_effects(&self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects {
|
||||||
self.queries
|
self.queries
|
||||||
.on_disk_cache
|
.on_disk_cache
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|c| c.load_diagnostics(**self, prev_dep_node_index))
|
.map(|c| c.load_side_effects(**self, prev_dep_node_index))
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn store_diagnostics(&self, dep_node_index: DepNodeIndex, diagnostics: ThinVec<Diagnostic>) {
|
fn store_side_effects(&self, dep_node_index: DepNodeIndex, side_effects: QuerySideEffects) {
|
||||||
if let Some(c) = self.queries.on_disk_cache.as_ref() {
|
if let Some(c) = self.queries.on_disk_cache.as_ref() {
|
||||||
c.store_diagnostics(dep_node_index, diagnostics)
|
c.store_side_effects(dep_node_index, side_effects)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn store_diagnostics_for_anon_node(
|
fn store_side_effects_for_anon_node(
|
||||||
&self,
|
&self,
|
||||||
dep_node_index: DepNodeIndex,
|
dep_node_index: DepNodeIndex,
|
||||||
diagnostics: ThinVec<Diagnostic>,
|
side_effects: QuerySideEffects,
|
||||||
) {
|
) {
|
||||||
if let Some(c) = self.queries.on_disk_cache.as_ref() {
|
if let Some(c) = self.queries.on_disk_cache.as_ref() {
|
||||||
c.store_diagnostics_for_anon_node(dep_node_index, diagnostics)
|
c.store_side_effects_for_anon_node(dep_node_index, side_effects)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,7 +165,7 @@ impl<'tcx> QueryCtxt<'tcx> {
|
||||||
pub(super) fn encode_query_results(
|
pub(super) fn encode_query_results(
|
||||||
self,
|
self,
|
||||||
encoder: &mut on_disk_cache::CacheEncoder<'a, 'tcx, opaque::FileEncoder>,
|
encoder: &mut on_disk_cache::CacheEncoder<'a, 'tcx, opaque::FileEncoder>,
|
||||||
query_result_index: &mut on_disk_cache::EncodedQueryResultIndex,
|
query_result_index: &mut on_disk_cache::EncodedDepNodeIndex,
|
||||||
) -> opaque::FileEncodeResult {
|
) -> opaque::FileEncodeResult {
|
||||||
macro_rules! encode_queries {
|
macro_rules! encode_queries {
|
||||||
($($query:ident,)*) => {
|
($($query:ident,)*) => {
|
||||||
|
|
|
@ -5,23 +5,20 @@ use rustc_data_structures::sharded::{self, Sharded};
|
||||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||||
use rustc_data_structures::steal::Steal;
|
use rustc_data_structures::steal::Steal;
|
||||||
use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering};
|
use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering};
|
||||||
use rustc_data_structures::unlikely;
|
|
||||||
use rustc_errors::Diagnostic;
|
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
|
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
|
||||||
|
|
||||||
use parking_lot::{Condvar, Mutex};
|
use parking_lot::Mutex;
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::mem;
|
|
||||||
use std::sync::atomic::Ordering::Relaxed;
|
use std::sync::atomic::Ordering::Relaxed;
|
||||||
|
|
||||||
use super::query::DepGraphQuery;
|
use super::query::DepGraphQuery;
|
||||||
use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex};
|
use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex};
|
||||||
use super::{DepContext, DepKind, DepNode, HasDepContext, WorkProductId};
|
use super::{DepContext, DepKind, DepNode, HasDepContext, WorkProductId};
|
||||||
use crate::query::QueryContext;
|
use crate::query::{QueryContext, QuerySideEffects};
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
use {super::debug::EdgeFilter, std::env};
|
use {super::debug::EdgeFilter, std::env};
|
||||||
|
@ -87,11 +84,7 @@ struct DepGraphData<K: DepKind> {
|
||||||
|
|
||||||
colors: DepNodeColorMap,
|
colors: DepNodeColorMap,
|
||||||
|
|
||||||
/// A set of loaded diagnostics that is in the progress of being emitted.
|
processed_side_effects: Mutex<FxHashSet<DepNodeIndex>>,
|
||||||
emitting_diagnostics: Mutex<FxHashSet<DepNodeIndex>>,
|
|
||||||
|
|
||||||
/// Used to wait for diagnostics to be emitted.
|
|
||||||
emitting_diagnostics_cond_var: Condvar,
|
|
||||||
|
|
||||||
/// When we load, there may be `.o` files, cached MIR, or other such
|
/// When we load, there may be `.o` files, cached MIR, or other such
|
||||||
/// things available to us. If we find that they are not dirty, we
|
/// things available to us. If we find that they are not dirty, we
|
||||||
|
@ -144,8 +137,7 @@ impl<K: DepKind> DepGraph<K> {
|
||||||
previous_work_products: prev_work_products,
|
previous_work_products: prev_work_products,
|
||||||
dep_node_debug: Default::default(),
|
dep_node_debug: Default::default(),
|
||||||
current,
|
current,
|
||||||
emitting_diagnostics: Default::default(),
|
processed_side_effects: Default::default(),
|
||||||
emitting_diagnostics_cond_var: Condvar::new(),
|
|
||||||
previous: prev_graph,
|
previous: prev_graph,
|
||||||
colors: DepNodeColorMap::new(prev_graph_node_count),
|
colors: DepNodeColorMap::new(prev_graph_node_count),
|
||||||
})),
|
})),
|
||||||
|
@ -691,7 +683,7 @@ impl<K: DepKind> DepGraph<K> {
|
||||||
|
|
||||||
// FIXME: Store the fact that a node has diagnostics in a bit in the dep graph somewhere
|
// FIXME: Store the fact that a node has diagnostics in a bit in the dep graph somewhere
|
||||||
// Maybe store a list on disk and encode this fact in the DepNodeState
|
// Maybe store a list on disk and encode this fact in the DepNodeState
|
||||||
let diagnostics = tcx.load_diagnostics(prev_dep_node_index);
|
let side_effects = tcx.load_side_effects(prev_dep_node_index);
|
||||||
|
|
||||||
#[cfg(not(parallel_compiler))]
|
#[cfg(not(parallel_compiler))]
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
|
@ -701,8 +693,8 @@ impl<K: DepKind> DepGraph<K> {
|
||||||
dep_node
|
dep_node
|
||||||
);
|
);
|
||||||
|
|
||||||
if unlikely!(!diagnostics.is_empty()) {
|
if unlikely!(!side_effects.is_empty()) {
|
||||||
self.emit_diagnostics(tcx, data, dep_node_index, prev_dep_node_index, diagnostics);
|
self.emit_side_effects(tcx, data, dep_node_index, side_effects);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ... and finally storing a "Green" entry in the color map.
|
// ... and finally storing a "Green" entry in the color map.
|
||||||
|
@ -717,54 +709,27 @@ impl<K: DepKind> DepGraph<K> {
|
||||||
/// This may be called concurrently on multiple threads for the same dep node.
|
/// This may be called concurrently on multiple threads for the same dep node.
|
||||||
#[cold]
|
#[cold]
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn emit_diagnostics<Ctxt: QueryContext<DepKind = K>>(
|
fn emit_side_effects<Ctxt: QueryContext<DepKind = K>>(
|
||||||
&self,
|
&self,
|
||||||
tcx: Ctxt,
|
tcx: Ctxt,
|
||||||
data: &DepGraphData<K>,
|
data: &DepGraphData<K>,
|
||||||
dep_node_index: DepNodeIndex,
|
dep_node_index: DepNodeIndex,
|
||||||
prev_dep_node_index: SerializedDepNodeIndex,
|
side_effects: QuerySideEffects,
|
||||||
diagnostics: Vec<Diagnostic>,
|
|
||||||
) {
|
) {
|
||||||
let mut emitting = data.emitting_diagnostics.lock();
|
let mut processed = data.processed_side_effects.lock();
|
||||||
|
|
||||||
if data.colors.get(prev_dep_node_index) == Some(DepNodeColor::Green(dep_node_index)) {
|
if processed.insert(dep_node_index) {
|
||||||
// The node is already green so diagnostics must have been emitted already
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if emitting.insert(dep_node_index) {
|
|
||||||
// We were the first to insert the node in the set so this thread
|
// We were the first to insert the node in the set so this thread
|
||||||
// must emit the diagnostics and signal other potentially waiting
|
// must process side effects
|
||||||
// threads after.
|
|
||||||
mem::drop(emitting);
|
|
||||||
|
|
||||||
// Promote the previous diagnostics to the current session.
|
// Promote the previous diagnostics to the current session.
|
||||||
tcx.store_diagnostics(dep_node_index, diagnostics.clone().into());
|
tcx.store_side_effects(dep_node_index, side_effects.clone());
|
||||||
|
|
||||||
let handle = tcx.dep_context().sess().diagnostic();
|
let handle = tcx.dep_context().sess().diagnostic();
|
||||||
|
|
||||||
for diagnostic in diagnostics {
|
for diagnostic in side_effects.diagnostics {
|
||||||
handle.emit_diagnostic(&diagnostic);
|
handle.emit_diagnostic(&diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark the node as green now that diagnostics are emitted
|
|
||||||
data.colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index));
|
|
||||||
|
|
||||||
// Remove the node from the set
|
|
||||||
data.emitting_diagnostics.lock().remove(&dep_node_index);
|
|
||||||
|
|
||||||
// Wake up waiters
|
|
||||||
data.emitting_diagnostics_cond_var.notify_all();
|
|
||||||
} else {
|
|
||||||
// We must wait for the other thread to finish emitting the diagnostic
|
|
||||||
|
|
||||||
loop {
|
|
||||||
data.emitting_diagnostics_cond_var.wait(&mut emitting);
|
|
||||||
if data.colors.get(prev_dep_node_index) == Some(DepNodeColor::Green(dep_node_index))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,31 @@ impl QueryStackFrame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tracks 'side effects' for a particular query.
|
||||||
|
/// This struct is saved to disk along with the query result,
|
||||||
|
/// and loaded from disk if we mark the query as green.
|
||||||
|
/// This allows us to 'replay' changes to global state
|
||||||
|
/// that would otherwise only occur if we actually
|
||||||
|
/// executed the query method.
|
||||||
|
#[derive(Debug, Clone, Default, Encodable, Decodable)]
|
||||||
|
pub struct QuerySideEffects {
|
||||||
|
/// Stores any diagnostics emitted during query execution.
|
||||||
|
/// These diagnostics will be re-emitted if we mark
|
||||||
|
/// the query as green.
|
||||||
|
pub diagnostics: ThinVec<Diagnostic>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl QuerySideEffects {
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
let QuerySideEffects { diagnostics } = self;
|
||||||
|
diagnostics.is_empty()
|
||||||
|
}
|
||||||
|
pub fn append(&mut self, other: QuerySideEffects) {
|
||||||
|
let QuerySideEffects { diagnostics } = self;
|
||||||
|
diagnostics.extend(other.diagnostics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait QueryContext: HasDepContext {
|
pub trait QueryContext: HasDepContext {
|
||||||
/// Get the query information from the TLS context.
|
/// Get the query information from the TLS context.
|
||||||
fn current_query_job(&self) -> Option<QueryJobId<Self::DepKind>>;
|
fn current_query_job(&self) -> Option<QueryJobId<Self::DepKind>>;
|
||||||
|
@ -74,17 +99,17 @@ pub trait QueryContext: HasDepContext {
|
||||||
/// Try to force a dep node to execute and see if it's green.
|
/// Try to force a dep node to execute and see if it's green.
|
||||||
fn try_force_from_dep_node(&self, dep_node: &DepNode<Self::DepKind>) -> bool;
|
fn try_force_from_dep_node(&self, dep_node: &DepNode<Self::DepKind>) -> bool;
|
||||||
|
|
||||||
/// Load diagnostics associated to the node in the previous session.
|
/// Load side effects associated to the node in the previous session.
|
||||||
fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec<Diagnostic>;
|
fn load_side_effects(&self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects;
|
||||||
|
|
||||||
/// Register diagnostics for the given node, for use in next session.
|
/// Register diagnostics for the given node, for use in next session.
|
||||||
fn store_diagnostics(&self, dep_node_index: DepNodeIndex, diagnostics: ThinVec<Diagnostic>);
|
fn store_side_effects(&self, dep_node_index: DepNodeIndex, side_effects: QuerySideEffects);
|
||||||
|
|
||||||
/// Register diagnostics for the given node, for use in next session.
|
/// Register diagnostics for the given node, for use in next session.
|
||||||
fn store_diagnostics_for_anon_node(
|
fn store_side_effects_for_anon_node(
|
||||||
&self,
|
&self,
|
||||||
dep_node_index: DepNodeIndex,
|
dep_node_index: DepNodeIndex,
|
||||||
diagnostics: ThinVec<Diagnostic>,
|
side_effects: QuerySideEffects,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Executes a job by changing the `ImplicitCtxt` to point to the
|
/// Executes a job by changing the `ImplicitCtxt` to point to the
|
||||||
|
|
|
@ -9,7 +9,7 @@ use crate::query::config::{QueryDescription, QueryVtable, QueryVtableExt};
|
||||||
use crate::query::job::{
|
use crate::query::job::{
|
||||||
report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryShardJobId,
|
report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryShardJobId,
|
||||||
};
|
};
|
||||||
use crate::query::{QueryContext, QueryMap, QueryStackFrame};
|
use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame};
|
||||||
|
|
||||||
use rustc_data_structures::fingerprint::Fingerprint;
|
use rustc_data_structures::fingerprint::Fingerprint;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHasher};
|
use rustc_data_structures::fx::{FxHashMap, FxHasher};
|
||||||
|
@ -479,8 +479,10 @@ where
|
||||||
|
|
||||||
dep_graph.read_index(dep_node_index);
|
dep_graph.read_index(dep_node_index);
|
||||||
|
|
||||||
if unlikely!(!diagnostics.is_empty()) {
|
let side_effects = QuerySideEffects { diagnostics };
|
||||||
tcx.store_diagnostics_for_anon_node(dep_node_index, diagnostics);
|
|
||||||
|
if unlikely!(!side_effects.is_empty()) {
|
||||||
|
tcx.store_side_effects_for_anon_node(dep_node_index, side_effects);
|
||||||
}
|
}
|
||||||
|
|
||||||
return job.complete(result, dep_node_index);
|
return job.complete(result, dep_node_index);
|
||||||
|
@ -677,8 +679,10 @@ where
|
||||||
|
|
||||||
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
|
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
|
||||||
|
|
||||||
if unlikely!(!diagnostics.is_empty()) && dep_node.kind != DepKind::NULL {
|
let side_effects = QuerySideEffects { diagnostics };
|
||||||
tcx.store_diagnostics(dep_node_index, diagnostics);
|
|
||||||
|
if unlikely!(!side_effects.is_empty()) && dep_node.kind != DepKind::NULL {
|
||||||
|
tcx.store_side_effects(dep_node_index, side_effects);
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = job.complete(result, dep_node_index);
|
let result = job.complete(result, dep_node_index);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue