Skip to content

Commit 6527b34

Browse files
committed
Move a lot of rustc_query_system::plumbing to rustc_query_impl::execution (part 1).
[Note: this commit conceptually moves 75% of a file to another location, and leaves 25% of it behind. It's impossible to preserve all the git history. To preserve git history of the moved 75%, in this commit we rename the file and remove the 25% from it, leaving the code in an incomplete (uncompilable) state. In the next commit we add back the 25% in the old location.] We are in the process of eliminating `rustc_query_system`. Chunks of it are unused by `rustc_middle`, and so can be moved into `rustc_query_impl`. This commit does some of that. Mostly it's just moving code from one file to a new file. There are a couple of non-trivial changes. - `QueryState` and `ActiveKeyStatus` must remain in `rustc_query_system` because they are used by `rustc_middle`. But their inherent methods are not used by `rustc_middle`. So these methods are moved and converted to free functions. - The visibility of some things must increase. This includes `DepGraphData` and some of its methods, which are now used in `rustc_query_impl`. This is a bit annoying but seems hard to avoid. What little is left behind in `compiler/rustc_query_system/src/query/plumbing.rs` will be able to moved into `rustc_query_impl` or `rustc_middle` in the future.
1 parent 25df79e commit 6527b34

8 files changed

Lines changed: 96 additions & 245 deletions

File tree

compiler/rustc_query_system/src/query/plumbing.rs renamed to compiler/rustc_query_impl/src/execution.rs

Lines changed: 65 additions & 215 deletions
Original file line numberDiff line numberDiff line change
@@ -1,133 +1,83 @@
1-
//! The implementation of the query system itself. This defines the macros that
2-
//! generate the actual methods on tcx which find and execute the provider,
3-
//! manage the caches, and so forth.
4-
5-
use std::cell::Cell;
6-
use std::fmt::Debug;
71
use std::hash::Hash;
82
use std::mem;
93

10-
use rustc_data_structures::fingerprint::Fingerprint;
11-
use rustc_data_structures::hash_table::{self, Entry, HashTable};
12-
use rustc_data_structures::sharded::{self, Sharded};
4+
use rustc_data_structures::hash_table::{Entry, HashTable};
135
use rustc_data_structures::stack::ensure_sufficient_stack;
14-
use rustc_data_structures::{outline, sync};
6+
use rustc_data_structures::{outline, sharded, sync};
157
use rustc_errors::{Diag, FatalError, StashKey};
8+
use rustc_query_system::dep_graph::{DepGraphData, DepNodeKey, HasDepContext};
9+
use rustc_query_system::query::{
10+
ActiveKeyStatus, CycleError, CycleErrorHandling, QueryCache, QueryContext, QueryDispatcher,
11+
QueryJob, QueryJobId, QueryJobInfo, QueryLatch, QueryMap, QueryMode, QueryStackDeferred,
12+
QueryStackFrame, QueryState, incremental_verify_ich, report_cycle,
13+
};
1614
use rustc_span::{DUMMY_SP, Span};
17-
use tracing::instrument;
1815

19-
use super::{QueryDispatcher, QueryStackDeferred, QueryStackFrameExtra};
20-
use crate::dep_graph::{
21-
DepContext, DepGraphData, DepNode, DepNodeIndex, DepNodeKey, HasDepContext,
22-
};
23-
use crate::ich::StableHashingContext;
24-
use crate::query::caches::QueryCache;
25-
use crate::query::job::{QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryLatch, report_cycle};
26-
use crate::query::{
27-
CycleErrorHandling, QueryContext, QueryMap, QueryStackFrame, SerializedDepNodeIndex,
28-
};
16+
use crate::dep_graph::{DepContext, DepNode, DepNodeIndex};
2917

3018
#[inline]
3119
fn equivalent_key<K: Eq, V>(k: &K) -> impl Fn(&(K, V)) -> bool + '_ {
3220
move |x| x.0 == *k
3321
}
3422

35-
/// For a particular query, keeps track of "active" keys, i.e. keys whose
36-
/// evaluation has started but has not yet finished successfully.
37-
///
38-
/// (Successful query evaluation for a key is represented by an entry in the
39-
/// query's in-memory cache.)
40-
pub struct QueryState<'tcx, K> {
41-
active: Sharded<hash_table::HashTable<(K, ActiveKeyStatus<'tcx>)>>,
42-
}
43-
44-
/// For a particular query and key, tracks the status of a query evaluation
45-
/// that has started, but has not yet finished successfully.
46-
///
47-
/// (Successful query evaluation for a key is represented by an entry in the
48-
/// query's in-memory cache.)
49-
enum ActiveKeyStatus<'tcx> {
50-
/// Some thread is already evaluating the query for this key.
51-
///
52-
/// The enclosed [`QueryJob`] can be used to wait for it to finish.
53-
Started(QueryJob<'tcx>),
54-
55-
/// The query panicked. Queries trying to wait on this will raise a fatal error which will
56-
/// silently panic.
57-
Poisoned,
58-
}
59-
60-
impl<'tcx> ActiveKeyStatus<'tcx> {
61-
/// Obtains the enclosed [`QueryJob`], or panics if this query evaluation
62-
/// was poisoned by a panic.
63-
fn expect_job(self) -> QueryJob<'tcx> {
64-
match self {
65-
Self::Started(job) => job,
66-
Self::Poisoned => {
67-
panic!("job for query failed to start and was poisoned")
68-
}
23+
/// Obtains the enclosed [`QueryJob`], or panics if this query evaluation
24+
/// was poisoned by a panic.
25+
fn expect_job<'tcx>(status: ActiveKeyStatus<'tcx>) -> QueryJob<'tcx> {
26+
match status {
27+
ActiveKeyStatus::Started(job) => job,
28+
ActiveKeyStatus::Poisoned => {
29+
panic!("job for query failed to start and was poisoned")
6930
}
7031
}
7132
}
7233

73-
impl<'tcx, K> QueryState<'tcx, K>
74-
where
75-
K: Eq + Hash + Copy + Debug,
76-
{
77-
pub fn all_inactive(&self) -> bool {
78-
self.active.lock_shards().all(|shard| shard.is_empty())
79-
}
80-
81-
/// Internal plumbing for collecting the set of active jobs for this query.
82-
///
83-
/// Should only be called from `gather_active_jobs`.
84-
pub fn gather_active_jobs_inner<Qcx: Copy>(
85-
&self,
86-
qcx: Qcx,
87-
make_frame: fn(Qcx, K) -> QueryStackFrame<QueryStackDeferred<'tcx>>,
88-
jobs: &mut QueryMap<'tcx>,
89-
require_complete: bool,
90-
) -> Option<()> {
91-
let mut active = Vec::new();
92-
93-
// Helper to gather active jobs from a single shard.
94-
let mut gather_shard_jobs = |shard: &HashTable<(K, ActiveKeyStatus<'tcx>)>| {
95-
for (k, v) in shard.iter() {
96-
if let ActiveKeyStatus::Started(ref job) = *v {
97-
active.push((*k, job.clone()));
98-
}
99-
}
100-
};
34+
pub(crate) fn all_inactive<'tcx, K>(state: &QueryState<'tcx, K>) -> bool {
35+
state.active.lock_shards().all(|shard| shard.is_empty())
36+
}
10137

102-
// Lock shards and gather jobs from each shard.
103-
if require_complete {
104-
for shard in self.active.lock_shards() {
105-
gather_shard_jobs(&shard);
106-
}
107-
} else {
108-
// We use try_lock_shards here since we are called from the
109-
// deadlock handler, and this shouldn't be locked.
110-
for shard in self.active.try_lock_shards() {
111-
let shard = shard?;
112-
gather_shard_jobs(&shard);
38+
/// Internal plumbing for collecting the set of active jobs for this query.
39+
///
40+
/// Should only be called from `gather_active_jobs`.
41+
pub(crate) fn gather_active_jobs_inner<'tcx, Qcx: Copy, K: Copy>(
42+
state: &QueryState<'tcx, K>,
43+
qcx: Qcx,
44+
make_frame: fn(Qcx, K) -> QueryStackFrame<QueryStackDeferred<'tcx>>,
45+
jobs: &mut QueryMap<'tcx>,
46+
require_complete: bool,
47+
) -> Option<()> {
48+
let mut active = Vec::new();
49+
50+
// Helper to gather active jobs from a single shard.
51+
let mut gather_shard_jobs = |shard: &HashTable<(K, ActiveKeyStatus<'tcx>)>| {
52+
for (k, v) in shard.iter() {
53+
if let ActiveKeyStatus::Started(ref job) = *v {
54+
active.push((*k, job.clone()));
11355
}
11456
}
57+
};
11558

116-
// Call `make_frame` while we're not holding a `self.active` lock as `make_frame` may call
117-
// queries leading to a deadlock.
118-
for (key, job) in active {
119-
let frame = make_frame(qcx, key);
120-
jobs.insert(job.id, QueryJobInfo { frame, job });
59+
// Lock shards and gather jobs from each shard.
60+
if require_complete {
61+
for shard in state.active.lock_shards() {
62+
gather_shard_jobs(&shard);
63+
}
64+
} else {
65+
// We use try_lock_shards here since we are called from the
66+
// deadlock handler, and this shouldn't be locked.
67+
for shard in state.active.try_lock_shards() {
68+
let shard = shard?;
69+
gather_shard_jobs(&shard);
12170
}
122-
123-
Some(())
12471
}
125-
}
12672

127-
impl<'tcx, K> Default for QueryState<'tcx, K> {
128-
fn default() -> QueryState<'tcx, K> {
129-
QueryState { active: Default::default() }
73+
// Call `make_frame` while we're not holding a `state.active` lock as `make_frame` may call
74+
// queries leading to a deadlock.
75+
for (key, job) in active {
76+
let frame = make_frame(qcx, key);
77+
jobs.insert(job.id, QueryJobInfo { frame, job });
13078
}
79+
80+
Some(())
13181
}
13282

13383
/// A type representing the responsibility to execute the job in the `job` field.
@@ -217,7 +167,7 @@ where
217167
Ok(occupied) => Some(occupied.remove().0.1),
218168
}
219169
};
220-
let job = job.expect("active query job entry").expect_job();
170+
let job = expect_job(job.expect("active query job entry"));
221171

222172
job.signal_complete();
223173
}
@@ -240,7 +190,7 @@ where
240190
Ok(occupied) => {
241191
let ((key, value), vacant) = occupied.remove();
242192
vacant.insert((key, ActiveKeyStatus::Poisoned));
243-
value.expect_job()
193+
expect_job(value)
244194
}
245195
}
246196
};
@@ -250,22 +200,6 @@ where
250200
}
251201
}
252202

253-
#[derive(Clone, Debug)]
254-
pub struct CycleError<I = QueryStackFrameExtra> {
255-
/// The query and related span that uses the cycle.
256-
pub usage: Option<(Span, QueryStackFrame<I>)>,
257-
pub cycle: Vec<QueryInfo<I>>,
258-
}
259-
260-
impl<'tcx> CycleError<QueryStackDeferred<'tcx>> {
261-
fn lift(&self) -> CycleError<QueryStackFrameExtra> {
262-
CycleError {
263-
usage: self.usage.as_ref().map(|(span, frame)| (*span, frame.lift())),
264-
cycle: self.cycle.iter().map(|info| info.lift()).collect(),
265-
}
266-
}
267-
}
268-
269203
#[cold]
270204
#[inline(never)]
271205
fn cycle_error<'tcx, Q>(
@@ -664,89 +598,6 @@ where
664598
Some((result, dep_node_index))
665599
}
666600

667-
#[inline]
668-
#[instrument(skip(tcx, dep_graph_data, result, hash_result, format_value), level = "debug")]
669-
pub(crate) fn incremental_verify_ich<Tcx, V>(
670-
tcx: Tcx,
671-
dep_graph_data: &DepGraphData<Tcx::Deps>,
672-
result: &V,
673-
prev_index: SerializedDepNodeIndex,
674-
hash_result: Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>,
675-
format_value: fn(&V) -> String,
676-
) where
677-
Tcx: DepContext,
678-
{
679-
if !dep_graph_data.is_index_green(prev_index) {
680-
incremental_verify_ich_not_green(tcx, prev_index)
681-
}
682-
683-
let new_hash = hash_result.map_or(Fingerprint::ZERO, |f| {
684-
tcx.with_stable_hashing_context(|mut hcx| f(&mut hcx, result))
685-
});
686-
687-
let old_hash = dep_graph_data.prev_fingerprint_of(prev_index);
688-
689-
if new_hash != old_hash {
690-
incremental_verify_ich_failed(tcx, prev_index, &|| format_value(result));
691-
}
692-
}
693-
694-
#[cold]
695-
#[inline(never)]
696-
fn incremental_verify_ich_not_green<Tcx>(tcx: Tcx, prev_index: SerializedDepNodeIndex)
697-
where
698-
Tcx: DepContext,
699-
{
700-
panic!(
701-
"fingerprint for green query instance not loaded from cache: {:?}",
702-
tcx.dep_graph().data().unwrap().prev_node_of(prev_index)
703-
)
704-
}
705-
706-
// Note that this is marked #[cold] and intentionally takes `dyn Debug` for `result`,
707-
// as we want to avoid generating a bunch of different implementations for LLVM to
708-
// chew on (and filling up the final binary, too).
709-
#[cold]
710-
#[inline(never)]
711-
fn incremental_verify_ich_failed<Tcx>(
712-
tcx: Tcx,
713-
prev_index: SerializedDepNodeIndex,
714-
result: &dyn Fn() -> String,
715-
) where
716-
Tcx: DepContext,
717-
{
718-
// When we emit an error message and panic, we try to debug-print the `DepNode`
719-
// and query result. Unfortunately, this can cause us to run additional queries,
720-
// which may result in another fingerprint mismatch while we're in the middle
721-
// of processing this one. To avoid a double-panic (which kills the process
722-
// before we can print out the query static), we print out a terse
723-
// but 'safe' message if we detect a reentrant call to this method.
724-
thread_local! {
725-
static INSIDE_VERIFY_PANIC: Cell<bool> = const { Cell::new(false) };
726-
};
727-
728-
let old_in_panic = INSIDE_VERIFY_PANIC.replace(true);
729-
730-
if old_in_panic {
731-
tcx.sess().dcx().emit_err(crate::error::Reentrant);
732-
} else {
733-
let run_cmd = if let Some(crate_name) = &tcx.sess().opts.crate_name {
734-
format!("`cargo clean -p {crate_name}` or `cargo clean`")
735-
} else {
736-
"`cargo clean`".to_string()
737-
};
738-
739-
let dep_node = tcx.dep_graph().data().unwrap().prev_node_of(prev_index);
740-
tcx.sess().dcx().emit_err(crate::error::IncrementCompilation {
741-
run_cmd,
742-
dep_node: format!("{dep_node:?}"),
743-
});
744-
panic!("Found unstable fingerprints for {dep_node:?}: {}", result());
745-
}
746-
747-
INSIDE_VERIFY_PANIC.set(old_in_panic);
748-
}
749-
750601
/// Ensure that either this query has all green inputs or been executed.
751602
/// Executing `query::ensure(D)` is considered a read of the dep-node `D`.
752603
/// Returns true if the query should still run.
@@ -801,14 +652,13 @@ where
801652
(!loadable, Some(dep_node))
802653
}
803654

804-
#[derive(Debug)]
805-
pub enum QueryMode {
806-
Get,
807-
Ensure { check_cache: bool },
808-
}
809-
810655
#[inline(always)]
811-
pub fn get_query_non_incr<'tcx, Q>(query: Q, qcx: Q::Qcx, span: Span, key: Q::Key) -> Q::Value
656+
pub(super) fn get_query_non_incr<'tcx, Q>(
657+
query: Q,
658+
qcx: Q::Qcx,
659+
span: Span,
660+
key: Q::Key,
661+
) -> Q::Value
812662
where
813663
Q: QueryDispatcher<'tcx>,
814664
{
@@ -818,7 +668,7 @@ where
818668
}
819669

820670
#[inline(always)]
821-
pub fn get_query_incr<'tcx, Q>(
671+
pub(super) fn get_query_incr<'tcx, Q>(
822672
query: Q,
823673
qcx: Q::Qcx,
824674
span: Span,
@@ -848,7 +698,7 @@ where
848698
Some(result)
849699
}
850700

851-
pub fn force_query<'tcx, Q>(query: Q, qcx: Q::Qcx, key: Q::Key, dep_node: DepNode)
701+
pub(super) fn force_query<'tcx, Q>(query: Q, qcx: Q::Qcx, key: Q::Key, dep_node: DepNode)
852702
where
853703
Q: QueryDispatcher<'tcx>,
854704
{

compiler/rustc_query_impl/src/lib.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// tidy-alphabetical-start
44
#![allow(internal_features)]
55
#![feature(adt_const_params)]
6+
#![feature(core_intrinsics)]
67
#![feature(min_specialization)]
78
#![feature(rustc_attrs)]
89
// tidy-alphabetical-end
@@ -25,21 +26,20 @@ use rustc_query_system::dep_graph::SerializedDepNodeIndex;
2526
use rustc_query_system::ich::StableHashingContext;
2627
use rustc_query_system::query::{
2728
CycleError, CycleErrorHandling, HashResult, QueryCache, QueryDispatcher, QueryMap, QueryMode,
28-
QueryState, get_query_incr, get_query_non_incr,
29+
QueryState,
2930
};
3031
use rustc_span::{ErrorGuaranteed, Span};
3132

33+
pub use crate::plumbing::{QueryCtxt, query_key_hash_verify_all};
3234
use crate::plumbing::{encode_all_query_results, try_mark_green};
3335
use crate::profiling_support::QueryKeyStringCache;
36+
pub use crate::profiling_support::alloc_self_profile_query_strings;
3437

38+
mod error;
39+
mod execution;
3540
#[macro_use]
3641
mod plumbing;
37-
pub use crate::plumbing::{QueryCtxt, query_key_hash_verify_all};
38-
3942
mod profiling_support;
40-
pub use self::profiling_support::alloc_self_profile_query_strings;
41-
42-
mod error;
4343

4444
#[derive(ConstParamTy)] // Allow this struct to be used for const-generic values.
4545
#[derive(Clone, Copy, Debug, PartialEq, Eq)]

0 commit comments

Comments
 (0)