@@ -17,7 +17,7 @@ use rustc_data_structures::profiling::TimingGuard;
1717#[ cfg( parallel_compiler) ]
1818use rustc_data_structures:: sharded:: Sharded ;
1919use rustc_data_structures:: stack:: ensure_sufficient_stack;
20- use rustc_data_structures:: sync:: Lock ;
20+ use rustc_data_structures:: sync:: { Lock , LockGuard } ;
2121use rustc_errors:: { DiagnosticBuilder , ErrorGuaranteed , FatalError } ;
2222use rustc_session:: Session ;
2323use rustc_span:: { Span , DUMMY_SP } ;
@@ -178,16 +178,13 @@ where
178178 fn try_start < ' b , Qcx > (
179179 qcx : & ' b Qcx ,
180180 state : & ' b QueryState < K , Qcx :: DepKind > ,
181+ mut state_lock : LockGuard < ' b , FxHashMap < K , QueryResult < Qcx :: DepKind > > > ,
181182 span : Span ,
182183 key : K ,
183184 ) -> TryGetJob < ' b , K , D >
184185 where
185186 Qcx : QueryContext + HasDepContext < DepKind = D > ,
186187 {
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 ( ) ;
191188 let lock = & mut * state_lock;
192189 let current_job_id = qcx. current_query_job ( ) ;
193190
@@ -362,7 +359,25 @@ where
362359 Qcx : QueryContext ,
363360{
364361 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) {
366381 TryGetJob :: NotYetStarted ( job) => {
367382 let ( result, dep_node_index) = execute_job ( query, qcx, key. clone ( ) , dep_node, job. id ) ;
368383 let cache = query. query_cache ( qcx) ;
0 commit comments