@@ -6,19 +6,19 @@ use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeIndex, DepNodeParams
66use crate :: dep_graph:: { DepGraphData , HasDepContext } ;
77use crate :: ich:: StableHashingContext ;
88use crate :: query:: caches:: QueryCache ;
9+ #[ cfg( parallel_compiler) ]
10+ use crate :: query:: job:: QueryLatch ;
911use crate :: query:: job:: { report_cycle, QueryInfo , QueryJob , QueryJobId , QueryJobInfo } ;
1012use crate :: query:: SerializedDepNodeIndex ;
1113use crate :: query:: { QueryContext , QueryMap , QuerySideEffects , QueryStackFrame } ;
1214use crate :: values:: Value ;
1315use crate :: HandleCycleError ;
1416use rustc_data_structures:: fingerprint:: Fingerprint ;
1517use rustc_data_structures:: fx:: FxHashMap ;
16- #[ cfg( parallel_compiler) ]
17- use rustc_data_structures:: profiling:: TimingGuard ;
18- #[ cfg( parallel_compiler) ]
19- use rustc_data_structures:: sharded:: Sharded ;
2018use rustc_data_structures:: stack:: ensure_sufficient_stack;
21- use rustc_data_structures:: sync:: { Lock , LockGuard } ;
19+ use rustc_data_structures:: sync:: Lock ;
20+ #[ cfg( parallel_compiler) ]
21+ use rustc_data_structures:: { cold_path, sharded:: Sharded } ;
2222use rustc_errors:: { DiagnosticBuilder , ErrorGuaranteed , FatalError } ;
2323use rustc_span:: { Span , DUMMY_SP } ;
2424use std:: cell:: Cell ;
@@ -116,7 +116,6 @@ where
116116{
117117 state : & ' tcx QueryState < K , D > ,
118118 key : K ,
119- id : QueryJobId ,
120119}
121120
122121#[ cold]
@@ -166,81 +165,6 @@ impl<'tcx, K, D: DepKind> JobOwner<'tcx, K, D>
166165where
167166 K : Eq + Hash + Copy ,
168167{
169- /// Either gets a `JobOwner` corresponding the query, allowing us to
170- /// start executing the query, or returns with the result of the query.
171- /// This function assumes that `try_get_cached` is already called and returned `lookup`.
172- /// If the query is executing elsewhere, this will wait for it and return the result.
173- /// If the query panicked, this will silently panic.
174- ///
175- /// This function is inlined because that results in a noticeable speed-up
176- /// for some compile-time benchmarks.
177- #[ inline( always) ]
178- fn try_start < ' b , Qcx > (
179- qcx : & ' b Qcx ,
180- state : & ' b QueryState < K , Qcx :: DepKind > ,
181- mut state_lock : LockGuard < ' b , FxHashMap < K , QueryResult < Qcx :: DepKind > > > ,
182- span : Span ,
183- key : K ,
184- ) -> TryGetJob < ' b , K , D >
185- where
186- Qcx : QueryContext + HasDepContext < DepKind = D > ,
187- {
188- let lock = & mut * state_lock;
189- let current_job_id = qcx. current_query_job ( ) ;
190-
191- match lock. entry ( key) {
192- Entry :: Vacant ( entry) => {
193- let id = qcx. next_job_id ( ) ;
194- let job = QueryJob :: new ( id, span, current_job_id) ;
195-
196- let key = * entry. key ( ) ;
197- entry. insert ( QueryResult :: Started ( job) ) ;
198-
199- let owner = JobOwner { state, id, key } ;
200- return TryGetJob :: NotYetStarted ( owner) ;
201- }
202- Entry :: Occupied ( mut entry) => {
203- match entry. get_mut ( ) {
204- #[ cfg( not( parallel_compiler) ) ]
205- QueryResult :: Started ( job) => {
206- let id = job. id ;
207- drop ( state_lock) ;
208-
209- // If we are single-threaded we know that we have cycle error,
210- // so we just return the error.
211- return TryGetJob :: Cycle ( id. find_cycle_in_stack (
212- qcx. try_collect_active_jobs ( ) . unwrap ( ) ,
213- & current_job_id,
214- span,
215- ) ) ;
216- }
217- #[ cfg( parallel_compiler) ]
218- QueryResult :: Started ( job) => {
219- // For parallel queries, we'll block and wait until the query running
220- // in another thread has completed. Record how long we wait in the
221- // self-profiler.
222- let query_blocked_prof_timer = qcx. dep_context ( ) . profiler ( ) . query_blocked ( ) ;
223-
224- // Get the latch out
225- let latch = job. latch ( ) ;
226-
227- drop ( state_lock) ;
228-
229- // With parallel queries we might just have to wait on some other
230- // thread.
231- let result = latch. wait_on ( current_job_id, span) ;
232-
233- match result {
234- Ok ( ( ) ) => TryGetJob :: JobCompleted ( query_blocked_prof_timer) ,
235- Err ( cycle) => TryGetJob :: Cycle ( cycle) ,
236- }
237- }
238- QueryResult :: Poisoned => FatalError . raise ( ) ,
239- }
240- }
241- }
242- }
243-
244168 /// Completes the query by updating the query cache with the `result`,
245169 /// signals the waiter and forgets the JobOwner, so it won't poison the query
246170 fn complete < C > ( self , cache : & C , result : C :: Value , dep_node_index : DepNodeIndex )
@@ -307,25 +231,6 @@ pub(crate) struct CycleError<D: DepKind> {
307231 pub cycle : Vec < QueryInfo < D > > ,
308232}
309233
310- /// The result of `try_start`.
311- enum TryGetJob < ' tcx , K , D >
312- where
313- K : Eq + Hash + Copy ,
314- D : DepKind ,
315- {
316- /// The query is not yet started. Contains a guard to the cache eventually used to start it.
317- NotYetStarted ( JobOwner < ' tcx , K , D > ) ,
318-
319- /// The query was already completed.
320- /// Returns the result of the query and its dep-node index
321- /// if it succeeded or a cycle error if it failed.
322- #[ cfg( parallel_compiler) ]
323- JobCompleted ( TimingGuard < ' tcx > ) ,
324-
325- /// Trying to execute the query resulted in a cycle.
326- Cycle ( CycleError < D > ) ,
327- }
328-
329234/// Checks if the query is already computed and in the cache.
330235/// It returns the shard index and a lock guard to the shard,
331236/// which will be used if the query is not in the cache and we need
@@ -346,6 +251,65 @@ where
346251 }
347252}
348253
254+ #[ cold]
255+ #[ inline( never) ]
256+ #[ cfg( not( parallel_compiler) ) ]
257+ fn cycle_error < Q , Qcx > (
258+ query : Q ,
259+ qcx : Qcx ,
260+ try_execute : QueryJobId ,
261+ span : Span ,
262+ ) -> ( Q :: Value , Option < DepNodeIndex > )
263+ where
264+ Q : QueryConfig < Qcx > ,
265+ Qcx : QueryContext ,
266+ {
267+ let error = try_execute. find_cycle_in_stack (
268+ qcx. try_collect_active_jobs ( ) . unwrap ( ) ,
269+ & qcx. current_query_job ( ) ,
270+ span,
271+ ) ;
272+ ( mk_cycle ( qcx, error, query. handle_cycle_error ( ) ) , None )
273+ }
274+
275+ #[ inline( always) ]
276+ #[ cfg( parallel_compiler) ]
277+ fn wait_for_query < Q , Qcx > (
278+ query : Q ,
279+ qcx : Qcx ,
280+ span : Span ,
281+ key : Q :: Key ,
282+ latch : QueryLatch < Qcx :: DepKind > ,
283+ current : Option < QueryJobId > ,
284+ ) -> ( Q :: Value , Option < DepNodeIndex > )
285+ where
286+ Q : QueryConfig < Qcx > ,
287+ Qcx : QueryContext ,
288+ {
289+ // For parallel queries, we'll block and wait until the query running
290+ // in another thread has completed. Record how long we wait in the
291+ // self-profiler.
292+ let query_blocked_prof_timer = qcx. dep_context ( ) . profiler ( ) . query_blocked ( ) ;
293+
294+ // With parallel queries we might just have to wait on some other
295+ // thread.
296+ let result = latch. wait_on ( current, span) ;
297+
298+ match result {
299+ Ok ( ( ) ) => {
300+ let Some ( ( v, index) ) = query. query_cache ( qcx) . lookup ( & key) else {
301+ cold_path ( || panic ! ( "value must be in cache after waiting" ) )
302+ } ;
303+
304+ qcx. dep_context ( ) . profiler ( ) . query_cache_hit ( index. into ( ) ) ;
305+ query_blocked_prof_timer. finish_with_query_invocation_id ( index. into ( ) ) ;
306+
307+ ( v, Some ( index) )
308+ }
309+ Err ( cycle) => ( mk_cycle ( qcx, cycle, query. handle_cycle_error ( ) ) , None ) ,
310+ }
311+ }
312+
349313#[ inline( never) ]
350314fn try_execute_query < Q , Qcx > (
351315 query : Q ,
@@ -360,9 +324,9 @@ where
360324{
361325 let state = query. query_state ( qcx) ;
362326 #[ cfg( parallel_compiler) ]
363- let state_lock = state. active . get_shard_by_value ( & key) . lock ( ) ;
327+ let mut state_lock = state. active . get_shard_by_value ( & key) . lock ( ) ;
364328 #[ cfg( not( parallel_compiler) ) ]
365- let state_lock = state. active . lock ( ) ;
329+ let mut state_lock = state. active . lock ( ) ;
366330
367331 // For the parallel compiler we need to check both the query cache and query state structures
368332 // while holding the state lock to ensure that 1) the query has not yet completed and 2) the
@@ -377,44 +341,82 @@ where
377341 }
378342 }
379343
380- match JobOwner :: < ' _ , Q :: Key , Qcx :: DepKind > :: try_start ( & qcx, state, state_lock, span, key) {
381- TryGetJob :: NotYetStarted ( job) => {
382- let ( result, dep_node_index) = match qcx. dep_context ( ) . dep_graph ( ) . data ( ) {
383- None => execute_job_non_incr ( query, qcx, key, job. id ) ,
384- Some ( data) => execute_job_incr ( query, qcx, data, key, dep_node, job. id ) ,
385- } ;
344+ let current_job_id = qcx. current_query_job ( ) ;
345+
346+ match state_lock. entry ( key) {
347+ Entry :: Vacant ( entry) => {
348+ // Nothing has computed or is computing the query, so we start a new job and insert it in the
349+ // state map.
350+ let id = qcx. next_job_id ( ) ;
351+ let job = QueryJob :: new ( id, span, current_job_id) ;
352+ entry. insert ( QueryResult :: Started ( job) ) ;
353+
354+ // Drop the lock before we start executing the query
355+ drop ( state_lock) ;
356+
357+ execute_job ( query, qcx, state, key, id, dep_node)
358+ }
359+ Entry :: Occupied ( mut entry) => {
360+ match entry. get_mut ( ) {
361+ #[ cfg( not( parallel_compiler) ) ]
362+ QueryResult :: Started ( job) => {
363+ let id = job. id ;
364+ drop ( state_lock) ;
365+
366+ // If we are single-threaded we know that we have cycle error,
367+ // so we just return the error.
368+ cycle_error ( query, qcx, id, span)
369+ }
370+ #[ cfg( parallel_compiler) ]
371+ QueryResult :: Started ( job) => {
372+ // Get the latch out
373+ let latch = job. latch ( ) ;
374+ drop ( state_lock) ;
386375
387- let cache = query. query_cache ( qcx) ;
388- if query. feedable ( ) {
389- // We should not compute queries that also got a value via feeding.
390- // This can't happen, as query feeding adds the very dependencies to the fed query
391- // as its feeding query had. So if the fed query is red, so is its feeder, which will
392- // get evaluated first, and re-feed the query.
393- if let Some ( ( cached_result, _) ) = cache. lookup ( & key) {
394- panic ! (
395- "fed query later has its value computed. The already cached value: {cached_result:?}"
396- ) ;
376+ wait_for_query ( query, qcx, span, key, latch, current_job_id)
397377 }
378+ QueryResult :: Poisoned => FatalError . raise ( ) ,
398379 }
399- job. complete ( cache, result, dep_node_index) ;
400- ( result, Some ( dep_node_index) )
401380 }
402- TryGetJob :: Cycle ( error) => {
403- let result = mk_cycle ( qcx, error, query. handle_cycle_error ( ) ) ;
404- ( result, None )
405- }
406- #[ cfg( parallel_compiler) ]
407- TryGetJob :: JobCompleted ( query_blocked_prof_timer) => {
408- let Some ( ( v, index) ) = query. query_cache ( qcx) . lookup ( & key) else {
409- panic ! ( "value must be in cache after waiting" )
410- } ;
381+ }
382+ }
411383
412- qcx. dep_context ( ) . profiler ( ) . query_cache_hit ( index. into ( ) ) ;
413- query_blocked_prof_timer. finish_with_query_invocation_id ( index. into ( ) ) ;
384+ #[ inline( always) ]
385+ fn execute_job < Q , Qcx > (
386+ query : Q ,
387+ qcx : Qcx ,
388+ state : & QueryState < Q :: Key , Qcx :: DepKind > ,
389+ key : Q :: Key ,
390+ id : QueryJobId ,
391+ dep_node : Option < DepNode < Qcx :: DepKind > > ,
392+ ) -> ( Q :: Value , Option < DepNodeIndex > )
393+ where
394+ Q : QueryConfig < Qcx > ,
395+ Qcx : QueryContext ,
396+ {
397+ // Use `JobOwner` so the query will be poisoned if executing it panics.
398+ let job_owner = JobOwner { state, key } ;
414399
415- ( v, Some ( index) )
400+ let ( result, dep_node_index) = match qcx. dep_context ( ) . dep_graph ( ) . data ( ) {
401+ None => execute_job_non_incr ( query, qcx, key, id) ,
402+ Some ( data) => execute_job_incr ( query, qcx, data, key, dep_node, id) ,
403+ } ;
404+
405+ let cache = query. query_cache ( qcx) ;
406+ if query. feedable ( ) {
407+ // We should not compute queries that also got a value via feeding.
408+ // This can't happen, as query feeding adds the very dependencies to the fed query
409+ // as its feeding query had. So if the fed query is red, so is its feeder, which will
410+ // get evaluated first, and re-feed the query.
411+ if let Some ( ( cached_result, _) ) = cache. lookup ( & key) {
412+ panic ! (
413+ "fed query later has its value computed. The already cached value: {cached_result:?}"
414+ ) ;
416415 }
417416 }
417+ job_owner. complete ( cache, result, dep_node_index) ;
418+
419+ ( result, Some ( dep_node_index) )
418420}
419421
420422// Fast path for when incr. comp. is off.
0 commit comments