@@ -12,26 +12,27 @@ use crate::query::job::{report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobI
12
12
use crate :: query:: SerializedDepNodeIndex ;
13
13
use crate :: query:: { QueryContext , QueryMap , QuerySideEffects , QueryStackFrame } ;
14
14
use crate :: HandleCycleError ;
15
+ use hashbrown:: hash_map:: RawEntryMut ;
15
16
use rustc_data_structures:: fingerprint:: Fingerprint ;
16
- use rustc_data_structures:: fx:: FxHashMap ;
17
- use rustc_data_structures:: sharded:: Sharded ;
17
+ use rustc_data_structures:: sharded:: { self , Sharded } ;
18
18
use rustc_data_structures:: stack:: ensure_sufficient_stack;
19
19
use rustc_data_structures:: sync:: Lock ;
20
20
#[ cfg( parallel_compiler) ]
21
21
use rustc_data_structures:: { cold_path, sync} ;
22
22
use rustc_errors:: { DiagnosticBuilder , ErrorGuaranteed , FatalError } ;
23
+ use rustc_hash:: FxHasher ;
23
24
use rustc_span:: { Span , DUMMY_SP } ;
24
25
use std:: cell:: Cell ;
25
- use std:: collections:: hash_map:: Entry ;
26
26
use std:: fmt:: Debug ;
27
+ use std:: hash:: BuildHasherDefault ;
27
28
use std:: hash:: Hash ;
28
29
use std:: mem;
29
30
use thin_vec:: ThinVec ;
30
31
31
32
use super :: QueryConfig ;
32
33
33
34
pub struct QueryState < K , D : DepKind > {
34
- active : Sharded < FxHashMap < K , QueryResult < D > > > ,
35
+ active : Sharded < hashbrown :: HashMap < K , QueryResult < D > , BuildHasherDefault < FxHasher > > > ,
35
36
}
36
37
37
38
/// Indicates the state of a query for a given key in a query map.
@@ -143,7 +144,7 @@ where
143
144
{
144
145
/// Completes the query by updating the query cache with the `result`,
145
146
/// signals the waiter and forgets the JobOwner, so it won't poison the query
146
- fn complete < C > ( self , cache : & C , result : C :: Value , dep_node_index : DepNodeIndex )
147
+ fn complete < C > ( self , cache : & C , key_hash : u64 , result : C :: Value , dep_node_index : DepNodeIndex )
147
148
where
148
149
C : QueryCache < Key = K > ,
149
150
{
@@ -155,13 +156,17 @@ where
155
156
156
157
// Mark as complete before we remove the job from the active state
157
158
// so no other thread can re-execute this query.
158
- cache. complete ( key, result, dep_node_index) ;
159
+ cache. complete ( key, key_hash , result, dep_node_index) ;
159
160
160
161
let job = {
161
- let mut lock = state. active . lock_shard_by_value ( & key) ;
162
- match lock. remove ( & key) . unwrap ( ) {
163
- QueryResult :: Started ( job) => job,
164
- QueryResult :: Poisoned => panic ! ( ) ,
162
+ let mut lock = state. active . lock_shard_by_hash ( key_hash) ;
163
+
164
+ match lock. raw_entry_mut ( ) . from_key_hashed_nocheck ( key_hash, & key) {
165
+ RawEntryMut :: Vacant ( _) => panic ! ( ) ,
166
+ RawEntryMut :: Occupied ( occupied) => match occupied. remove ( ) {
167
+ QueryResult :: Started ( job) => job,
168
+ QueryResult :: Poisoned => panic ! ( ) ,
169
+ } ,
165
170
}
166
171
} ;
167
172
@@ -211,7 +216,8 @@ where
211
216
C : QueryCache ,
212
217
Tcx : DepContext ,
213
218
{
214
- match cache. lookup ( & key) {
219
+ let key_hash = sharded:: make_hash ( key) ;
220
+ match cache. lookup ( & key, key_hash) {
215
221
Some ( ( value, index) ) => {
216
222
tcx. profiler ( ) . query_cache_hit ( index. into ( ) ) ;
217
223
tcx. dep_graph ( ) . read_index ( index) ;
@@ -248,6 +254,7 @@ fn wait_for_query<Q, Qcx>(
248
254
qcx : Qcx ,
249
255
span : Span ,
250
256
key : Q :: Key ,
257
+ key_hash : u64 ,
251
258
latch : QueryLatch < Qcx :: DepKind > ,
252
259
current : Option < QueryJobId > ,
253
260
) -> ( Q :: Value , Option < DepNodeIndex > )
@@ -266,7 +273,7 @@ where
266
273
267
274
match result {
268
275
Ok ( ( ) ) => {
269
- let Some ( ( v, index) ) = query. query_cache ( qcx) . lookup ( & key) else {
276
+ let Some ( ( v, index) ) = query. query_cache ( qcx) . lookup ( & key, key_hash ) else {
270
277
cold_path ( || {
271
278
// We didn't find the query result in the query cache. Check if it was
272
279
// poisoned due to a panic instead.
@@ -303,7 +310,8 @@ where
303
310
Qcx : QueryContext ,
304
311
{
305
312
let state = query. query_state ( qcx) ;
306
- let mut state_lock = state. active . lock_shard_by_value ( & key) ;
313
+ let key_hash = sharded:: make_hash ( & key) ;
314
+ let mut state_lock = state. active . lock_shard_by_hash ( key_hash) ;
307
315
308
316
// For the parallel compiler we need to check both the query cache and query state structures
309
317
// while holding the state lock to ensure that 1) the query has not yet completed and 2) the
@@ -312,29 +320,46 @@ where
312
320
// executing, but another thread may have already completed the query and stores it result
313
321
// in the query cache.
314
322
if cfg ! ( parallel_compiler) && qcx. dep_context ( ) . sess ( ) . threads ( ) > 1 {
315
- if let Some ( ( value, index) ) = query. query_cache ( qcx) . lookup ( & key) {
323
+ if let Some ( ( value, index) ) = query. query_cache ( qcx) . lookup ( & key, key_hash ) {
316
324
qcx. dep_context ( ) . profiler ( ) . query_cache_hit ( index. into ( ) ) ;
317
325
return ( value, Some ( index) ) ;
318
326
}
319
327
}
320
328
321
329
let current_job_id = qcx. current_query_job ( ) ;
322
330
323
- match state_lock. entry ( key) {
324
- Entry :: Vacant ( entry) => {
331
+ match state_lock. raw_table_mut ( ) . find_or_find_insert_slot (
332
+ key_hash,
333
+ |( k, _) | * k == key,
334
+ |( k, _) | sharded:: make_hash ( k) ,
335
+ ) {
336
+ Err ( free_slot) => {
325
337
// Nothing has computed or is computing the query, so we start a new job and insert it in the
326
338
// state map.
327
339
let id = qcx. next_job_id ( ) ;
328
340
let job = QueryJob :: new ( id, span, current_job_id) ;
329
- entry. insert ( QueryResult :: Started ( job) ) ;
341
+
342
+ // SAFETY: The slot is still valid as there's
343
+ // been no mutation to the table since we hold the lock.
344
+ unsafe {
345
+ state_lock. raw_table_mut ( ) . insert_in_slot (
346
+ key_hash,
347
+ free_slot,
348
+ ( key, QueryResult :: Started ( job) ) ,
349
+ ) ;
350
+ }
330
351
331
352
// Drop the lock before we start executing the query
332
353
drop ( state_lock) ;
333
354
334
- execute_job :: < _ , _ , INCR > ( query, qcx, state, key, id, dep_node)
355
+ execute_job :: < _ , _ , INCR > ( query, qcx, state, key, key_hash , id, dep_node)
335
356
}
336
- Entry :: Occupied ( mut entry) => {
337
- match entry. get_mut ( ) {
357
+ Ok ( bucket) => {
358
+ // SAFETY: We know this bucket is still valid
359
+ // since we just got it from `find_or_find_insert_slot`.
360
+ let entry = unsafe { & mut bucket. as_mut ( ) . 1 } ;
361
+
362
+ match entry {
338
363
QueryResult :: Started ( job) => {
339
364
#[ cfg( parallel_compiler) ]
340
365
if sync:: is_dyn_thread_safe ( ) {
@@ -344,7 +369,15 @@ where
344
369
345
370
// Only call `wait_for_query` if we're using a Rayon thread pool
346
371
// as it will attempt to mark the worker thread as blocked.
347
- return wait_for_query ( query, qcx, span, key, latch, current_job_id) ;
372
+ return wait_for_query (
373
+ query,
374
+ qcx,
375
+ span,
376
+ key,
377
+ key_hash,
378
+ latch,
379
+ current_job_id,
380
+ ) ;
348
381
}
349
382
350
383
let id = job. id ;
@@ -366,6 +399,7 @@ fn execute_job<Q, Qcx, const INCR: bool>(
366
399
qcx : Qcx ,
367
400
state : & QueryState < Q :: Key , Qcx :: DepKind > ,
368
401
key : Q :: Key ,
402
+ key_hash : u64 ,
369
403
id : QueryJobId ,
370
404
dep_node : Option < DepNode < Qcx :: DepKind > > ,
371
405
) -> ( Q :: Value , Option < DepNodeIndex > )
@@ -397,7 +431,7 @@ where
397
431
// This can't happen, as query feeding adds the very dependencies to the fed query
398
432
// as its feeding query had. So if the fed query is red, so is its feeder, which will
399
433
// get evaluated first, and re-feed the query.
400
- if let Some ( ( cached_result, _) ) = cache. lookup ( & key) {
434
+ if let Some ( ( cached_result, _) ) = cache. lookup ( & key, key_hash ) {
401
435
let Some ( hasher) = query. hash_result ( ) else {
402
436
panic ! (
403
437
"no_hash fed query later has its value computed.\n \
@@ -429,7 +463,7 @@ where
429
463
}
430
464
}
431
465
}
432
- job_owner. complete ( cache, result, dep_node_index) ;
466
+ job_owner. complete ( cache, key_hash , result, dep_node_index) ;
433
467
434
468
( result, Some ( dep_node_index) )
435
469
}
@@ -832,7 +866,7 @@ pub fn force_query<Q, Qcx>(
832
866
{
833
867
// We may be concurrently trying both execute and force a query.
834
868
// Ensure that only one of them runs the query.
835
- if let Some ( ( _, index) ) = query. query_cache ( qcx) . lookup ( & key) {
869
+ if let Some ( ( _, index) ) = query. query_cache ( qcx) . lookup ( & key, sharded :: make_hash ( & key ) ) {
836
870
qcx. dep_context ( ) . profiler ( ) . query_cache_hit ( index. into ( ) ) ;
837
871
return ;
838
872
}
0 commit comments