@@ -17,7 +17,7 @@ use rustc_data_structures::profiling::TimingGuard;
17
17
#[ cfg( parallel_compiler) ]
18
18
use rustc_data_structures:: sharded:: Sharded ;
19
19
use rustc_data_structures:: stack:: ensure_sufficient_stack;
20
- use rustc_data_structures:: sync:: Lock ;
20
+ use rustc_data_structures:: sync:: { Lock , LockGuard } ;
21
21
use rustc_errors:: { DiagnosticBuilder , ErrorGuaranteed , FatalError } ;
22
22
use rustc_session:: Session ;
23
23
use rustc_span:: { Span , DUMMY_SP } ;
@@ -178,16 +178,13 @@ where
178
178
fn try_start < ' b , Qcx > (
179
179
qcx : & ' b Qcx ,
180
180
state : & ' b QueryState < K , Qcx :: DepKind > ,
181
+ mut state_lock : LockGuard < ' b , FxHashMap < K , QueryResult < Qcx :: DepKind > > > ,
181
182
span : Span ,
182
183
key : K ,
183
184
) -> TryGetJob < ' b , K , D >
184
185
where
185
186
Qcx : QueryContext + HasDepContext < DepKind = D > ,
186
187
{
187
- #[ cfg( parallel_compiler) ]
188
- let mut state_lock = state. active . get_shard_by_value ( & key) . lock ( ) ;
189
- #[ cfg( not( parallel_compiler) ) ]
190
- let mut state_lock = state. active . lock ( ) ;
191
188
let lock = & mut * state_lock;
192
189
let current_job_id = qcx. current_query_job ( ) ;
193
190
@@ -362,7 +359,25 @@ where
362
359
Qcx : QueryContext ,
363
360
{
364
361
let state = query. query_state ( qcx) ;
365
- match JobOwner :: < ' _ , Q :: Key , Qcx :: DepKind > :: try_start ( & qcx, state, span, key) {
362
+ #[ cfg( parallel_compiler) ]
363
+ let state_lock = state. active . get_shard_by_value ( & key) . lock ( ) ;
364
+ #[ cfg( not( parallel_compiler) ) ]
365
+ let state_lock = state. active . lock ( ) ;
366
+
367
+ // For the parallel compiler we need to check both the query cache and query state structures
368
+ // while holding the state lock to ensure that 1) the query has not yet completed and 2) the
369
+ // query is not still executing. Without checking the query cache here, we can end up
370
+ // re-executing the query since `try_start` only checks that the query is not currently
371
+ // executing, but another thread may have already completed the query and stores it result
372
+ // in the query cache.
373
+ if cfg ! ( parallel_compiler) && qcx. dep_context ( ) . sess ( ) . threads ( ) > 1 {
374
+ if let Some ( ( value, index) ) = query. query_cache ( qcx) . lookup ( & key) {
375
+ qcx. dep_context ( ) . profiler ( ) . query_cache_hit ( index. into ( ) ) ;
376
+ return ( value, Some ( index) ) ;
377
+ }
378
+ }
379
+
380
+ match JobOwner :: < ' _ , Q :: Key , Qcx :: DepKind > :: try_start ( & qcx, state, state_lock, span, key) {
366
381
TryGetJob :: NotYetStarted ( job) => {
367
382
let ( result, dep_node_index) = execute_job ( query, qcx, key. clone ( ) , dep_node, job. id ) ;
368
383
let cache = query. query_cache ( qcx) ;
0 commit comments