Skip to content

Commit 11ad63a

Browse files
committed
Auto merge of #152835 - nnethercote:fix-query-state-query-cache, r=Zalathar
Improve how `QueryCache`/`QueryState`/`QueryEngine` are stored *[View all comments](https://triagebot.infra.rust-lang.org/gh-comments/rust-lang/rust/pull/152835)* `QueryVTable` has two fields `query_state` and `query_cache` that are *byte offsets* of fields in other structs. They are used in `unsafe` combination with `byte_add` and `cast` to access said fields. I don't like this at all and this PR replaces them with something sensible. r? @Zalathar
2 parents 859951e + 4a5ee04 commit 11ad63a

5 files changed

Lines changed: 71 additions & 142 deletions

File tree

compiler/rustc_middle/src/query/inner.rs

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@ where
3333
/// Shared implementation of `tcx.$query(..)` and `tcx.at(span).$query(..)`
3434
/// for all queries.
3535
#[inline(always)]
36-
pub(crate) fn query_get_at<'tcx, Cache>(
36+
pub(crate) fn query_get_at<'tcx, C>(
3737
tcx: TyCtxt<'tcx>,
38-
execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>,
39-
query_cache: &Cache,
38+
execute_query: fn(TyCtxt<'tcx>, Span, C::Key, QueryMode) -> Option<C::Value>,
39+
query_cache: &C,
4040
span: Span,
41-
key: Cache::Key,
42-
) -> Cache::Value
41+
key: C::Key,
42+
) -> C::Value
4343
where
44-
Cache: QueryCache,
44+
C: QueryCache,
4545
{
4646
match try_get_cached(tcx, query_cache, &key) {
4747
Some(value) => value,
@@ -52,14 +52,14 @@ where
5252
/// Shared implementation of `tcx.ensure_ok().$query(..)` for most queries,
5353
/// and `tcx.ensure_done().$query(..)` for all queries.
5454
#[inline]
55-
pub(crate) fn query_ensure<'tcx, Cache>(
55+
pub(crate) fn query_ensure<'tcx, C>(
5656
tcx: TyCtxt<'tcx>,
57-
execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>,
58-
query_cache: &Cache,
59-
key: Cache::Key,
57+
execute_query: fn(TyCtxt<'tcx>, Span, C::Key, QueryMode) -> Option<C::Value>,
58+
query_cache: &C,
59+
key: C::Key,
6060
ensure_mode: EnsureMode,
6161
) where
62-
Cache: QueryCache,
62+
C: QueryCache,
6363
{
6464
if try_get_cached(tcx, query_cache, &key).is_none() {
6565
execute_query(tcx, DUMMY_SP, key, QueryMode::Ensure { ensure_mode });
@@ -69,17 +69,17 @@ pub(crate) fn query_ensure<'tcx, Cache>(
6969
/// Shared implementation of `tcx.ensure_ok().$query(..)` for queries that
7070
/// have the `return_result_from_ensure_ok` modifier.
7171
#[inline]
72-
pub(crate) fn query_ensure_error_guaranteed<'tcx, Cache, T>(
72+
pub(crate) fn query_ensure_error_guaranteed<'tcx, C, T>(
7373
tcx: TyCtxt<'tcx>,
74-
execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>,
75-
query_cache: &Cache,
76-
key: Cache::Key,
74+
execute_query: fn(TyCtxt<'tcx>, Span, C::Key, QueryMode) -> Option<C::Value>,
75+
query_cache: &C,
76+
key: C::Key,
7777
// This arg is needed to match the signature of `query_ensure`,
7878
// but should always be `EnsureMode::Ok`.
7979
ensure_mode: EnsureMode,
8080
) -> Result<(), ErrorGuaranteed>
8181
where
82-
Cache: QueryCache<Value = Erased<Result<T, ErrorGuaranteed>>>,
82+
C: QueryCache<Value = Erased<Result<T, ErrorGuaranteed>>>,
8383
Result<T, ErrorGuaranteed>: Erasable,
8484
{
8585
assert_matches!(ensure_mode, EnsureMode::Ok);
@@ -101,21 +101,20 @@ where
101101
}
102102

103103
/// Common implementation of query feeding, used by `define_feedable!`.
104-
pub(crate) fn query_feed<'tcx, Cache>(
104+
pub(crate) fn query_feed<'tcx, C>(
105105
tcx: TyCtxt<'tcx>,
106106
dep_kind: DepKind,
107-
query_vtable: &QueryVTable<'tcx, Cache>,
108-
cache: &Cache,
109-
key: Cache::Key,
110-
value: Cache::Value,
107+
query_vtable: &QueryVTable<'tcx, C>,
108+
key: C::Key,
109+
value: C::Value,
111110
) where
112-
Cache: QueryCache,
113-
Cache::Key: DepNodeKey<'tcx>,
111+
C: QueryCache,
112+
C::Key: DepNodeKey<'tcx>,
114113
{
115114
let format_value = query_vtable.format_value;
116115

117116
// Check whether the in-memory cache already has a value for this key.
118-
match try_get_cached(tcx, cache, &key) {
117+
match try_get_cached(tcx, &query_vtable.cache, &key) {
119118
Some(old) => {
120119
// The query already has a cached value for this key.
121120
// That's OK if both values are the same, i.e. they have the same hash,
@@ -158,7 +157,7 @@ pub(crate) fn query_feed<'tcx, Cache>(
158157
query_vtable.hash_result,
159158
query_vtable.format_value,
160159
);
161-
cache.complete(key, value, dep_node_index);
160+
query_vtable.cache.complete(key, value, dep_node_index);
162161
}
163162
}
164163
}

compiler/rustc_middle/src/query/plumbing.rs

Lines changed: 14 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@ pub use sealed::IntoQueryParam;
1414
use crate::dep_graph;
1515
use crate::dep_graph::{DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex};
1616
use crate::ich::StableHashingContext;
17-
use crate::queries::{
18-
ExternProviders, PerQueryVTables, Providers, QueryArenas, QueryCaches, QueryEngine, QueryStates,
19-
};
17+
use crate::queries::{ExternProviders, Providers, QueryArenas, QueryVTables};
2018
use crate::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex, OnDiskCache};
2119
use crate::query::stack::{QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra};
2220
use crate::query::{QueryCache, QueryInfo, QueryJob};
@@ -113,7 +111,7 @@ pub enum EnsureMode {
113111
Done,
114112
}
115113

116-
/// Stores function pointers and other metadata for a particular query.
114+
/// Stores data and metadata (e.g. function pointers) for a particular query.
117115
pub struct QueryVTable<'tcx, C: QueryCache> {
118116
pub name: &'static str,
119117

@@ -129,10 +127,8 @@ pub struct QueryVTable<'tcx, C: QueryCache> {
129127
pub dep_kind: DepKind,
130128
/// How this query deals with query cycle errors.
131129
pub cycle_error_handling: CycleErrorHandling,
132-
// Offset of this query's state field in the QueryStates struct
133-
pub query_state: usize,
134-
// Offset of this query's cache field in the QueryCaches struct
135-
pub query_cache: usize,
130+
pub state: QueryState<'tcx, C::Key>,
131+
pub cache: C,
136132
pub will_cache_on_disk_for_key_fn: Option<WillCacheOnDiskForKeyFn<'tcx, C::Key>>,
137133

138134
/// Function pointer that calls `tcx.$query(key)` for this query and
@@ -161,6 +157,8 @@ pub struct QueryVTable<'tcx, C: QueryCache> {
161157
///
162158
/// Used when reporting query cycle errors and similar problems.
163159
pub description_fn: fn(TyCtxt<'tcx>, C::Key) -> String,
160+
161+
pub execute_query_fn: fn(TyCtxt<'tcx>, Span, C::Key, QueryMode) -> Option<C::Value>,
164162
}
165163

166164
impl<'tcx, C: QueryCache> fmt::Debug for QueryVTable<'tcx, C> {
@@ -181,30 +179,6 @@ impl<'tcx, C: QueryCache> QueryVTable<'tcx, C> {
181179
self.will_cache_on_disk_for_key_fn.map_or(false, |f| f(tcx, key))
182180
}
183181

184-
// Don't use this method to access query results, instead use the methods on TyCtxt.
185-
#[inline(always)]
186-
pub fn query_state(&self, tcx: TyCtxt<'tcx>) -> &'tcx QueryState<'tcx, C::Key> {
187-
// Safety:
188-
// This is just manually doing the subfield referencing through pointer math.
189-
unsafe {
190-
&*(&tcx.query_system.states as *const QueryStates<'tcx>)
191-
.byte_add(self.query_state)
192-
.cast::<QueryState<'tcx, C::Key>>()
193-
}
194-
}
195-
196-
// Don't use this method to access query results, instead use the methods on TyCtxt.
197-
#[inline(always)]
198-
pub fn query_cache(&self, tcx: TyCtxt<'tcx>) -> &'tcx C {
199-
// Safety:
200-
// This is just manually doing the subfield referencing through pointer math.
201-
unsafe {
202-
&*(&tcx.query_system.caches as *const QueryCaches<'tcx>)
203-
.byte_add(self.query_cache)
204-
.cast::<C>()
205-
}
206-
}
207-
208182
#[inline(always)]
209183
pub fn try_load_from_disk(
210184
&self,
@@ -243,7 +217,6 @@ impl<'tcx, C: QueryCache> QueryVTable<'tcx, C> {
243217
}
244218

245219
pub struct QuerySystemFns {
246-
pub engine: QueryEngine,
247220
pub local_providers: Providers,
248221
pub extern_providers: ExternProviders,
249222
pub encode_query_results: for<'tcx> fn(
@@ -255,10 +228,8 @@ pub struct QuerySystemFns {
255228
}
256229

257230
pub struct QuerySystem<'tcx> {
258-
pub states: QueryStates<'tcx>,
259231
pub arenas: WorkerLocal<QueryArenas<'tcx>>,
260-
pub caches: QueryCaches<'tcx>,
261-
pub query_vtables: PerQueryVTables<'tcx>,
232+
pub query_vtables: QueryVTables<'tcx>,
262233

263234
/// This provides access to the incremental compilation on-disk cache for query results.
264235
/// Do not access this directly. It is only meant to be used by
@@ -521,13 +492,6 @@ macro_rules! define_callbacks {
521492
)*
522493
}
523494

524-
#[derive(Default)]
525-
pub struct QueryCaches<'tcx> {
526-
$(
527-
pub $name: $name::Storage<'tcx>,
528-
)*
529-
}
530-
531495
impl<'tcx> $crate::query::TyCtxtEnsureOk<'tcx> {
532496
$(
533497
$(#[$attr])*
@@ -546,8 +510,8 @@ macro_rules! define_callbacks {
546510
(crate::query::inner::query_ensure)
547511
)(
548512
self.tcx,
549-
self.tcx.query_system.fns.engine.$name,
550-
&self.tcx.query_system.caches.$name,
513+
self.tcx.query_system.query_vtables.$name.execute_query_fn,
514+
&self.tcx.query_system.query_vtables.$name.cache,
551515
$crate::query::IntoQueryParam::into_query_param(key),
552516
$crate::query::EnsureMode::Ok,
553517
)
@@ -562,8 +526,8 @@ macro_rules! define_callbacks {
562526
pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
563527
crate::query::inner::query_ensure(
564528
self.tcx,
565-
self.tcx.query_system.fns.engine.$name,
566-
&self.tcx.query_system.caches.$name,
529+
self.tcx.query_system.query_vtables.$name.execute_query_fn,
530+
&self.tcx.query_system.query_vtables.$name.cache,
567531
$crate::query::IntoQueryParam::into_query_param(key),
568532
$crate::query::EnsureMode::Done,
569533
);
@@ -591,8 +555,8 @@ macro_rules! define_callbacks {
591555

592556
erase::restore_val::<$V>(inner::query_get_at(
593557
self.tcx,
594-
self.tcx.query_system.fns.engine.$name,
595-
&self.tcx.query_system.caches.$name,
558+
self.tcx.query_system.query_vtables.$name.execute_query_fn,
559+
&self.tcx.query_system.query_vtables.$name.cache,
596560
self.span,
597561
$crate::query::IntoQueryParam::into_query_param(key),
598562
))
@@ -615,7 +579,6 @@ macro_rules! define_callbacks {
615579
self.tcx,
616580
dep_graph::DepKind::$name,
617581
&self.tcx.query_system.query_vtables.$name,
618-
&self.tcx.query_system.caches.$name,
619582
key,
620583
erased_value,
621584
);
@@ -625,21 +588,12 @@ macro_rules! define_callbacks {
625588
)*
626589

627590
/// Holds a `QueryVTable` for each query.
628-
///
629-
/// ("Per" just makes this pluralized name more visually distinct.)
630-
pub struct PerQueryVTables<'tcx> {
591+
pub struct QueryVTables<'tcx> {
631592
$(
632593
pub $name: ::rustc_middle::query::plumbing::QueryVTable<'tcx, $name::Storage<'tcx>>,
633594
)*
634595
}
635596

636-
#[derive(Default)]
637-
pub struct QueryStates<'tcx> {
638-
$(
639-
pub $name: $crate::query::QueryState<'tcx, $name::Key<'tcx>>,
640-
)*
641-
}
642-
643597
pub struct Providers {
644598
$(
645599
/// This is the provider for the query. Use `Find references` on this to
@@ -699,17 +653,6 @@ macro_rules! define_callbacks {
699653
impl Clone for ExternProviders {
700654
fn clone(&self) -> Self { *self }
701655
}
702-
703-
pub struct QueryEngine {
704-
$(
705-
pub $name: for<'tcx> fn(
706-
TyCtxt<'tcx>,
707-
Span,
708-
$name::Key<'tcx>,
709-
$crate::query::QueryMode,
710-
) -> Option<$crate::query::erase::Erased<$V>>,
711-
)*
712-
}
713656
};
714657
}
715658

compiler/rustc_query_impl/src/execution.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -244,12 +244,12 @@ fn wait_for_query<'tcx, C: QueryCache>(
244244

245245
match result {
246246
Ok(()) => {
247-
let Some((v, index)) = query.query_cache(tcx).lookup(&key) else {
247+
let Some((v, index)) = query.cache.lookup(&key) else {
248248
outline(|| {
249249
// We didn't find the query result in the query cache. Check if it was
250250
// poisoned due to a panic instead.
251251
let key_hash = sharded::make_hash(&key);
252-
let shard = query.query_state(tcx).active.lock_shard_by_hash(key_hash);
252+
let shard = query.state.active.lock_shard_by_hash(key_hash);
253253
match shard.find(key_hash, equivalent_key(&key)) {
254254
// The query we waited on panicked. Continue unwinding here.
255255
Some((_, ActiveKeyStatus::Poisoned)) => FatalError.raise(),
@@ -280,9 +280,8 @@ fn try_execute_query<'tcx, C: QueryCache, const INCR: bool>(
280280
// query+key, which we should reuse instead of creating a new one.
281281
dep_node: Option<DepNode>,
282282
) -> (C::Value, Option<DepNodeIndex>) {
283-
let state = query.query_state(tcx);
284283
let key_hash = sharded::make_hash(&key);
285-
let mut state_lock = state.active.lock_shard_by_hash(key_hash);
284+
let mut state_lock = query.state.active.lock_shard_by_hash(key_hash);
286285

287286
// For the parallel compiler we need to check both the query cache and query state structures
288287
// while holding the state lock to ensure that 1) the query has not yet completed and 2) the
@@ -291,7 +290,7 @@ fn try_execute_query<'tcx, C: QueryCache, const INCR: bool>(
291290
// executing, but another thread may have already completed the query and stores it result
292291
// in the query cache.
293292
if tcx.sess.threads() > 1 {
294-
if let Some((value, index)) = query.query_cache(tcx).lookup(&key) {
293+
if let Some((value, index)) = query.cache.lookup(&key) {
295294
tcx.prof.query_cache_hit(index.into());
296295
return (value, Some(index));
297296
}
@@ -310,7 +309,7 @@ fn try_execute_query<'tcx, C: QueryCache, const INCR: bool>(
310309
// Drop the lock before we start executing the query
311310
drop(state_lock);
312311

313-
execute_job::<C, INCR>(query, tcx, state, key, key_hash, id, dep_node)
312+
execute_job::<C, INCR>(query, tcx, key, key_hash, id, dep_node)
314313
}
315314
Entry::Occupied(mut entry) => {
316315
match &mut entry.get_mut().1 {
@@ -342,15 +341,14 @@ fn try_execute_query<'tcx, C: QueryCache, const INCR: bool>(
342341
fn execute_job<'tcx, C: QueryCache, const INCR: bool>(
343342
query: &'tcx QueryVTable<'tcx, C>,
344343
tcx: TyCtxt<'tcx>,
345-
state: &'tcx QueryState<'tcx, C::Key>,
346344
key: C::Key,
347345
key_hash: u64,
348346
id: QueryJobId,
349347
dep_node: Option<DepNode>,
350348
) -> (C::Value, Option<DepNodeIndex>) {
351349
// Set up a guard object that will automatically poison the query if a
352350
// panic occurs while executing the query (or any intermediate plumbing).
353-
let job_guard = ActiveJobGuard { state, key, key_hash };
351+
let job_guard = ActiveJobGuard { state: &query.state, key, key_hash };
354352

355353
debug_assert_eq!(tcx.dep_graph.is_fully_enabled(), INCR);
356354

@@ -361,7 +359,7 @@ fn execute_job<'tcx, C: QueryCache, const INCR: bool>(
361359
execute_job_non_incr(query, tcx, key, id)
362360
};
363361

364-
let cache = query.query_cache(tcx);
362+
let cache = &query.cache;
365363
if query.feedable {
366364
// We should not compute queries that also got a value via feeding.
367365
// This can't happen, as query feeding adds the very dependencies to the fed query
@@ -706,7 +704,7 @@ pub(crate) fn force_query<'tcx, C: QueryCache>(
706704
) {
707705
// We may be concurrently trying both execute and force a query.
708706
// Ensure that only one of them runs the query.
709-
if let Some((_, index)) = query.query_cache(tcx).lookup(&key) {
707+
if let Some((_, index)) = query.cache.lookup(&key) {
710708
tcx.prof.query_cache_hit(index.into());
711709
return;
712710
}

compiler/rustc_query_impl/src/lib.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@
1010

1111
use rustc_data_structures::sync::AtomicU64;
1212
use rustc_middle::dep_graph;
13-
use rustc_middle::queries::{
14-
self, ExternProviders, Providers, QueryCaches, QueryEngine, QueryStates,
15-
};
13+
use rustc_middle::queries::{self, ExternProviders, Providers};
1614
use rustc_middle::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex, OnDiskCache};
1715
use rustc_middle::query::plumbing::{QuerySystem, QuerySystemFns, QueryVTable};
1816
use rustc_middle::query::{AsLocalKey, QueryCache, QueryMode};
@@ -58,13 +56,10 @@ pub fn query_system<'tcx>(
5856
incremental: bool,
5957
) -> QuerySystem<'tcx> {
6058
QuerySystem {
61-
states: Default::default(),
6259
arenas: Default::default(),
63-
caches: Default::default(),
64-
query_vtables: make_query_vtables(),
60+
query_vtables: make_query_vtables(incremental),
6561
on_disk_cache,
6662
fns: QuerySystemFns {
67-
engine: engine(incremental),
6863
local_providers,
6964
extern_providers,
7065
encode_query_results: encode_all_query_results,

0 commit comments

Comments
 (0)