Skip to content

Commit 563a2f0

Browse files
committed
Move a lot of rustc_query_system::plumbing to rustc_query_impl::execution (part 2).
[Note: see the previous commit to understand this commit.]
1 parent 6527b34 commit 563a2f0

1 file changed

Lines changed: 150 additions & 0 deletions

File tree

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
use std::cell::Cell;
2+
use std::fmt::Debug;
3+
4+
use rustc_data_structures::fingerprint::Fingerprint;
5+
use rustc_data_structures::hash_table::HashTable;
6+
use rustc_data_structures::sharded::Sharded;
7+
use rustc_span::Span;
8+
use tracing::instrument;
9+
10+
use super::{QueryStackDeferred, QueryStackFrameExtra};
11+
use crate::dep_graph::{DepContext, DepGraphData};
12+
use crate::ich::StableHashingContext;
13+
use crate::query::job::{QueryInfo, QueryJob};
14+
use crate::query::{QueryStackFrame, SerializedDepNodeIndex};
15+
16+
/// For a particular query, keeps track of "active" keys, i.e. keys whose
17+
/// evaluation has started but has not yet finished successfully.
18+
///
19+
/// (Successful query evaluation for a key is represented by an entry in the
20+
/// query's in-memory cache.)
21+
pub struct QueryState<'tcx, K> {
22+
pub active: Sharded<HashTable<(K, ActiveKeyStatus<'tcx>)>>,
23+
}
24+
25+
/// For a particular query and key, tracks the status of a query evaluation
26+
/// that has started, but has not yet finished successfully.
27+
///
28+
/// (Successful query evaluation for a key is represented by an entry in the
29+
/// query's in-memory cache.)
30+
pub enum ActiveKeyStatus<'tcx> {
31+
/// Some thread is already evaluating the query for this key.
32+
///
33+
/// The enclosed [`QueryJob`] can be used to wait for it to finish.
34+
Started(QueryJob<'tcx>),
35+
36+
/// The query panicked. Queries trying to wait on this will raise a fatal error which will
37+
/// silently panic.
38+
Poisoned,
39+
}
40+
41+
impl<'tcx, K> Default for QueryState<'tcx, K> {
42+
fn default() -> QueryState<'tcx, K> {
43+
QueryState { active: Default::default() }
44+
}
45+
}
46+
47+
#[derive(Clone, Debug)]
48+
pub struct CycleError<I = QueryStackFrameExtra> {
49+
/// The query and related span that uses the cycle.
50+
pub usage: Option<(Span, QueryStackFrame<I>)>,
51+
pub cycle: Vec<QueryInfo<I>>,
52+
}
53+
54+
impl<'tcx> CycleError<QueryStackDeferred<'tcx>> {
55+
pub fn lift(&self) -> CycleError<QueryStackFrameExtra> {
56+
CycleError {
57+
usage: self.usage.as_ref().map(|(span, frame)| (*span, frame.lift())),
58+
cycle: self.cycle.iter().map(|info| info.lift()).collect(),
59+
}
60+
}
61+
}
62+
63+
#[inline]
64+
#[instrument(skip(tcx, dep_graph_data, result, hash_result, format_value), level = "debug")]
65+
pub fn incremental_verify_ich<Tcx, V>(
66+
tcx: Tcx,
67+
dep_graph_data: &DepGraphData<Tcx::Deps>,
68+
result: &V,
69+
prev_index: SerializedDepNodeIndex,
70+
hash_result: Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>,
71+
format_value: fn(&V) -> String,
72+
) where
73+
Tcx: DepContext,
74+
{
75+
if !dep_graph_data.is_index_green(prev_index) {
76+
incremental_verify_ich_not_green(tcx, prev_index)
77+
}
78+
79+
let new_hash = hash_result.map_or(Fingerprint::ZERO, |f| {
80+
tcx.with_stable_hashing_context(|mut hcx| f(&mut hcx, result))
81+
});
82+
83+
let old_hash = dep_graph_data.prev_fingerprint_of(prev_index);
84+
85+
if new_hash != old_hash {
86+
incremental_verify_ich_failed(tcx, prev_index, &|| format_value(result));
87+
}
88+
}
89+
90+
#[cold]
91+
#[inline(never)]
92+
fn incremental_verify_ich_not_green<Tcx>(tcx: Tcx, prev_index: SerializedDepNodeIndex)
93+
where
94+
Tcx: DepContext,
95+
{
96+
panic!(
97+
"fingerprint for green query instance not loaded from cache: {:?}",
98+
tcx.dep_graph().data().unwrap().prev_node_of(prev_index)
99+
)
100+
}
101+
102+
// Note that this is marked #[cold] and intentionally takes `dyn Debug` for `result`,
103+
// as we want to avoid generating a bunch of different implementations for LLVM to
104+
// chew on (and filling up the final binary, too).
105+
#[cold]
106+
#[inline(never)]
107+
fn incremental_verify_ich_failed<Tcx>(
108+
tcx: Tcx,
109+
prev_index: SerializedDepNodeIndex,
110+
result: &dyn Fn() -> String,
111+
) where
112+
Tcx: DepContext,
113+
{
114+
// When we emit an error message and panic, we try to debug-print the `DepNode`
115+
// and query result. Unfortunately, this can cause us to run additional queries,
116+
// which may result in another fingerprint mismatch while we're in the middle
117+
// of processing this one. To avoid a double-panic (which kills the process
118+
// before we can print out the query static), we print out a terse
119+
// but 'safe' message if we detect a reentrant call to this method.
120+
thread_local! {
121+
static INSIDE_VERIFY_PANIC: Cell<bool> = const { Cell::new(false) };
122+
};
123+
124+
let old_in_panic = INSIDE_VERIFY_PANIC.replace(true);
125+
126+
if old_in_panic {
127+
tcx.sess().dcx().emit_err(crate::error::Reentrant);
128+
} else {
129+
let run_cmd = if let Some(crate_name) = &tcx.sess().opts.crate_name {
130+
format!("`cargo clean -p {crate_name}` or `cargo clean`")
131+
} else {
132+
"`cargo clean`".to_string()
133+
};
134+
135+
let dep_node = tcx.dep_graph().data().unwrap().prev_node_of(prev_index);
136+
tcx.sess().dcx().emit_err(crate::error::IncrementCompilation {
137+
run_cmd,
138+
dep_node: format!("{dep_node:?}"),
139+
});
140+
panic!("Found unstable fingerprints for {dep_node:?}: {}", result());
141+
}
142+
143+
INSIDE_VERIFY_PANIC.set(old_in_panic);
144+
}
145+
146+
#[derive(Debug)]
147+
pub enum QueryMode {
148+
Get,
149+
Ensure { check_cache: bool },
150+
}

0 commit comments

Comments
 (0)