@@ -12,26 +12,27 @@ use crate::query::job::{report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobI
1212use crate :: query:: SerializedDepNodeIndex ;
1313use crate :: query:: { QueryContext , QueryMap , QuerySideEffects , QueryStackFrame } ;
1414use crate :: HandleCycleError ;
15+ use hashbrown:: hash_map:: RawEntryMut ;
1516use 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 } ;
1818use rustc_data_structures:: stack:: ensure_sufficient_stack;
1919use rustc_data_structures:: sync:: Lock ;
2020#[ cfg( parallel_compiler) ]
2121use rustc_data_structures:: { cold_path, sync} ;
2222use rustc_errors:: { DiagnosticBuilder , ErrorGuaranteed , FatalError } ;
23+ use rustc_hash:: FxHasher ;
2324use rustc_span:: { Span , DUMMY_SP } ;
2425use std:: cell:: Cell ;
25- use std:: collections:: hash_map:: Entry ;
2626use std:: fmt:: Debug ;
27+ use std:: hash:: BuildHasherDefault ;
2728use std:: hash:: Hash ;
2829use std:: mem;
2930use thin_vec:: ThinVec ;
3031
3132use super :: QueryConfig ;
3233
3334pub struct QueryState < K > {
34- active : Sharded < FxHashMap < K , QueryResult > > ,
35+ active : Sharded < hashbrown :: HashMap < K , QueryResult , BuildHasherDefault < FxHasher > > > ,
3536}
3637
3738/// Indicates the state of a query for a given key in a query map.
@@ -142,7 +143,7 @@ where
142143{
143144 /// Completes the query by updating the query cache with the `result`,
144145 /// signals the waiter and forgets the JobOwner, so it won't poison the query
145- fn complete < C > ( self , cache : & C , result : C :: Value , dep_node_index : DepNodeIndex )
146+ fn complete < C > ( self , cache : & C , key_hash : u64 , result : C :: Value , dep_node_index : DepNodeIndex )
146147 where
147148 C : QueryCache < Key = K > ,
148149 {
@@ -154,13 +155,17 @@ where
154155
155156 // Mark as complete before we remove the job from the active state
156157 // so no other thread can re-execute this query.
157- cache. complete ( key, result, dep_node_index) ;
158+ cache. complete ( key, key_hash , result, dep_node_index) ;
158159
159160 let job = {
160- let mut lock = state. active . lock_shard_by_value ( & key) ;
161- match lock. remove ( & key) . unwrap ( ) {
162- QueryResult :: Started ( job) => job,
163- QueryResult :: Poisoned => panic ! ( ) ,
161+ let mut lock = state. active . lock_shard_by_hash ( key_hash) ;
162+
163+ match lock. raw_entry_mut ( ) . from_key_hashed_nocheck ( key_hash, & key) {
164+ RawEntryMut :: Vacant ( _) => panic ! ( ) ,
165+ RawEntryMut :: Occupied ( occupied) => match occupied. remove ( ) {
166+ QueryResult :: Started ( job) => job,
167+ QueryResult :: Poisoned => panic ! ( ) ,
168+ } ,
164169 }
165170 } ;
166171
@@ -209,7 +214,8 @@ where
209214 C : QueryCache ,
210215 Tcx : DepContext ,
211216{
212- match cache. lookup ( & key) {
217+ let key_hash = sharded:: make_hash ( key) ;
218+ match cache. lookup ( & key, key_hash) {
213219 Some ( ( value, index) ) => {
214220 tcx. profiler ( ) . query_cache_hit ( index. into ( ) ) ;
215221 tcx. dep_graph ( ) . read_index ( index) ;
@@ -246,6 +252,7 @@ fn wait_for_query<Q, Qcx>(
246252 qcx : Qcx ,
247253 span : Span ,
248254 key : Q :: Key ,
255+ key_hash : u64 ,
249256 latch : QueryLatch ,
250257 current : Option < QueryJobId > ,
251258) -> ( Q :: Value , Option < DepNodeIndex > )
@@ -264,7 +271,7 @@ where
264271
265272 match result {
266273 Ok ( ( ) ) => {
267- let Some ( ( v, index) ) = query. query_cache ( qcx) . lookup ( & key) else {
274+ let Some ( ( v, index) ) = query. query_cache ( qcx) . lookup ( & key, key_hash ) else {
268275 cold_path ( || {
269276 // We didn't find the query result in the query cache. Check if it was
270277 // poisoned due to a panic instead.
@@ -301,7 +308,8 @@ where
301308 Qcx : QueryContext ,
302309{
303310 let state = query. query_state ( qcx) ;
304- let mut state_lock = state. active . lock_shard_by_value ( & key) ;
311+ let key_hash = sharded:: make_hash ( & key) ;
312+ let mut state_lock = state. active . lock_shard_by_hash ( key_hash) ;
305313
306314 // For the parallel compiler we need to check both the query cache and query state structures
307315 // while holding the state lock to ensure that 1) the query has not yet completed and 2) the
@@ -310,29 +318,46 @@ where
310318 // executing, but another thread may have already completed the query and stores it result
311319 // in the query cache.
312320 if cfg ! ( parallel_compiler) && qcx. dep_context ( ) . sess ( ) . threads ( ) > 1 {
313- if let Some ( ( value, index) ) = query. query_cache ( qcx) . lookup ( & key) {
321+ if let Some ( ( value, index) ) = query. query_cache ( qcx) . lookup ( & key, key_hash ) {
314322 qcx. dep_context ( ) . profiler ( ) . query_cache_hit ( index. into ( ) ) ;
315323 return ( value, Some ( index) ) ;
316324 }
317325 }
318326
319327 let current_job_id = qcx. current_query_job ( ) ;
320328
321- match state_lock. entry ( key) {
322- Entry :: Vacant ( entry) => {
329+ match state_lock. raw_table_mut ( ) . find_or_find_insert_slot (
330+ key_hash,
331+ |( k, _) | * k == key,
332+ |( k, _) | sharded:: make_hash ( k) ,
333+ ) {
334+ Err ( free_slot) => {
323335 // Nothing has computed or is computing the query, so we start a new job and insert it in the
324336 // state map.
325337 let id = qcx. next_job_id ( ) ;
326338 let job = QueryJob :: new ( id, span, current_job_id) ;
327- entry. insert ( QueryResult :: Started ( job) ) ;
339+
340+ // SAFETY: The slot is still valid as there's
341+ // been no mutation to the table since we hold the lock.
342+ unsafe {
343+ state_lock. raw_table_mut ( ) . insert_in_slot (
344+ key_hash,
345+ free_slot,
346+ ( key, QueryResult :: Started ( job) ) ,
347+ ) ;
348+ }
328349
329350 // Drop the lock before we start executing the query
330351 drop ( state_lock) ;
331352
332- execute_job :: < _ , _ , INCR > ( query, qcx, state, key, id, dep_node)
353+ execute_job :: < _ , _ , INCR > ( query, qcx, state, key, key_hash , id, dep_node)
333354 }
334- Entry :: Occupied ( mut entry) => {
335- match entry. get_mut ( ) {
355+ Ok ( bucket) => {
356+ // SAFETY: We know this bucket is still valid
357+ // since we just got it from `find_or_find_insert_slot`.
358+ let entry = unsafe { & mut bucket. as_mut ( ) . 1 } ;
359+
360+ match entry {
336361 QueryResult :: Started ( job) => {
337362 #[ cfg( parallel_compiler) ]
338363 if sync:: is_dyn_thread_safe ( ) {
@@ -342,7 +367,15 @@ where
342367
343368 // Only call `wait_for_query` if we're using a Rayon thread pool
344369 // as it will attempt to mark the worker thread as blocked.
345- return wait_for_query ( query, qcx, span, key, latch, current_job_id) ;
370+ return wait_for_query (
371+ query,
372+ qcx,
373+ span,
374+ key,
375+ key_hash,
376+ latch,
377+ current_job_id,
378+ ) ;
346379 }
347380
348381 let id = job. id ;
@@ -364,6 +397,7 @@ fn execute_job<Q, Qcx, const INCR: bool>(
364397 qcx : Qcx ,
365398 state : & QueryState < Q :: Key > ,
366399 key : Q :: Key ,
400+ key_hash : u64 ,
367401 id : QueryJobId ,
368402 dep_node : Option < DepNode > ,
369403) -> ( Q :: Value , Option < DepNodeIndex > )
@@ -395,7 +429,7 @@ where
395429 // This can't happen, as query feeding adds the very dependencies to the fed query
396430 // as its feeding query had. So if the fed query is red, so is its feeder, which will
397431 // get evaluated first, and re-feed the query.
398- if let Some ( ( cached_result, _) ) = cache. lookup ( & key) {
432+ if let Some ( ( cached_result, _) ) = cache. lookup ( & key, key_hash ) {
399433 let Some ( hasher) = query. hash_result ( ) else {
400434 panic ! (
401435 "no_hash fed query later has its value computed.\n \
@@ -427,7 +461,7 @@ where
427461 }
428462 }
429463 }
430- job_owner. complete ( cache, result, dep_node_index) ;
464+ job_owner. complete ( cache, key_hash , result, dep_node_index) ;
431465
432466 ( result, Some ( dep_node_index) )
433467}
@@ -826,7 +860,7 @@ where
826860{
827861 // We may be concurrently trying both execute and force a query.
828862 // Ensure that only one of them runs the query.
829- if let Some ( ( _, index) ) = query. query_cache ( qcx) . lookup ( & key) {
863+ if let Some ( ( _, index) ) = query. query_cache ( qcx) . lookup ( & key, sharded :: make_hash ( & key ) ) {
830864 qcx. dep_context ( ) . profiler ( ) . query_cache_hit ( index. into ( ) ) ;
831865 return ;
832866 }
0 commit comments