@@ -9,6 +9,7 @@ use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering};
99use rustc_data_structures:: unord:: UnordMap ;
1010use rustc_index:: IndexVec ;
1111use rustc_serialize:: opaque:: { FileEncodeResult , FileEncoder } ;
12+ use rustc_session:: Session ;
1213use smallvec:: { smallvec, SmallVec } ;
1314use std:: assert_matches:: assert_matches;
1415use std:: collections:: hash_map:: Entry ;
@@ -115,7 +116,7 @@ where
115116
116117impl < K : DepKind > DepGraph < K > {
117118 pub fn new (
118- profiler : & SelfProfilerRef ,
119+ session : & Session ,
119120 prev_graph : SerializedDepGraph < K > ,
120121 prev_work_products : FxIndexMap < WorkProductId , WorkProduct > ,
121122 encoder : FileEncoder ,
@@ -125,7 +126,7 @@ impl<K: DepKind> DepGraph<K> {
125126 let prev_graph_node_count = prev_graph. node_count ( ) ;
126127
127128 let current = CurrentDepGraph :: new (
128- profiler ,
129+ session ,
129130 prev_graph_node_count,
130131 encoder,
131132 record_graph,
@@ -136,7 +137,7 @@ impl<K: DepKind> DepGraph<K> {
136137
137138 // Instantiate a dependy-less node only once for anonymous queries.
138139 let _green_node_index = current. intern_new_node (
139- profiler ,
140+ & session . prof ,
140141 DepNode { kind : DepKind :: NULL , hash : current. anon_id_seed . into ( ) } ,
141142 smallvec ! [ ] ,
142143 Fingerprint :: ZERO ,
@@ -145,7 +146,7 @@ impl<K: DepKind> DepGraph<K> {
145146
146147 // Instantiate a dependy-less red node only once for anonymous queries.
147148 let ( red_node_index, red_node_prev_index_and_color) = current. intern_node (
148- profiler ,
149+ & session . prof ,
149150 & prev_graph,
150151 DepNode { kind : DepKind :: RED , hash : Fingerprint :: ZERO . into ( ) } ,
151152 smallvec ! [ ] ,
@@ -343,17 +344,13 @@ impl<K: DepKind> DepGraphData<K> {
343344 task : fn ( Ctxt , A ) -> R ,
344345 hash_result : Option < fn ( & mut StableHashingContext < ' _ > , & R ) -> Fingerprint > ,
345346 ) -> ( R , DepNodeIndex ) {
346- // If the following assertion triggers, it can have two reasons:
347- // 1. Something is wrong with DepNode creation, either here or
348- // in `DepGraph::try_mark_green()`.
349- // 2. Two distinct query keys get mapped to the same `DepNode`
350- // (see for example #48923).
351- assert ! (
352- !self . dep_node_exists( & key) ,
353- "forcing query with already existing `DepNode`\n \
354- - query-key: {arg:?}\n \
355- - dep-node: {key:?}"
356- ) ;
347+ self . assert_nonexistent_node ( & key, || {
348+ format ! (
349+ "forcing query with already existing `DepNode`\n \
350+ - query-key: {arg:?}\n \
351+ - dep-node: {key:?}"
352+ )
353+ } ) ;
357354
358355 let with_deps = |task_deps| K :: with_deps ( task_deps, || task ( cx, arg) ) ;
359356 let ( result, edges) = if cx. dep_context ( ) . is_eval_always ( key. kind ) {
@@ -449,12 +446,32 @@ impl<K: DepKind> DepGraphData<K> {
449446 hash : self . current . anon_id_seed . combine ( hasher. finish ( ) ) . into ( ) ,
450447 } ;
451448
452- self . current . intern_new_node (
453- cx. profiler ( ) ,
454- target_dep_node,
455- task_deps,
456- Fingerprint :: ZERO ,
457- )
449+ // The DepNodes generated by the process above are not unique. 2 queries could
450+ // have exactly the same dependencies. However, deserialization does not handle
451+ // duplicated nodes, so we do the deduplication here directly.
452+ //
453+ // As anonymous nodes are a small quantity compared to the full dep-graph, the
454+ // memory impact of this `anon_node_to_index` map remains tolerable, and helps
455+ // us avoid useless growth of the graph with almost-equivalent nodes.
456+ match self
457+ . current
458+ . anon_node_to_index
459+ . get_shard_by_value ( & target_dep_node)
460+ . lock ( )
461+ . entry ( target_dep_node)
462+ {
463+ Entry :: Occupied ( entry) => * entry. get ( ) ,
464+ Entry :: Vacant ( entry) => {
465+ let dep_node_index = self . current . intern_new_node (
466+ cx. profiler ( ) ,
467+ target_dep_node,
468+ task_deps,
469+ Fingerprint :: ZERO ,
470+ ) ;
471+ entry. insert ( dep_node_index) ;
472+ dep_node_index
473+ }
474+ }
458475 }
459476 } ;
460477
@@ -625,25 +642,18 @@ impl<K: DepKind> DepGraph<K> {
625642}
626643
627644impl < K : DepKind > DepGraphData < K > {
628- #[ inline]
629- pub fn dep_node_index_of_opt ( & self , dep_node : & DepNode < K > ) -> Option < DepNodeIndex > {
630- if let Some ( prev_index) = self . previous . node_to_index_opt ( dep_node) {
631- self . current . prev_index_to_index . lock ( ) [ prev_index]
632- } else {
633- self . current
634- . new_node_to_index
635- . get_shard_by_value ( dep_node)
636- . lock ( )
637- . get ( dep_node)
638- . copied ( )
645+ fn assert_nonexistent_node < S : std:: fmt:: Display > (
646+ & self ,
647+ _dep_node : & DepNode < K > ,
648+ _msg : impl FnOnce ( ) -> S ,
649+ ) {
650+ #[ cfg( debug_assertions) ]
651+ if let Some ( seen_dep_nodes) = & self . current . seen_dep_nodes {
652+ let seen = seen_dep_nodes. lock ( ) . contains ( _dep_node) ;
653+ assert ! ( !seen, "{}" , _msg( ) ) ;
639654 }
640655 }
641656
642- #[ inline]
643- pub fn dep_node_exists ( & self , dep_node : & DepNode < K > ) -> bool {
644- self . dep_node_index_of_opt ( dep_node) . is_some ( )
645- }
646-
647657 fn node_color ( & self , dep_node : & DepNode < K > ) -> Option < DepNodeColor > {
648658 if let Some ( prev_index) = self . previous . node_to_index_opt ( dep_node) {
649659 self . colors . get ( prev_index)
@@ -676,11 +686,6 @@ impl<K: DepKind> DepGraphData<K> {
676686}
677687
678688impl < K : DepKind > DepGraph < K > {
679- #[ inline]
680- pub fn dep_node_exists ( & self , dep_node : & DepNode < K > ) -> bool {
681- self . data . as_ref ( ) . is_some_and ( |data| data. dep_node_exists ( dep_node) )
682- }
683-
684689 /// Checks whether a previous work product exists for `v` and, if
685690 /// so, return the path that leads to it. Used to skip doing work.
686691 pub fn previous_work_product ( & self , v : & WorkProductId ) -> Option < WorkProduct > {
@@ -762,7 +767,7 @@ impl<K: DepKind> DepGraphData<K> {
762767 }
763768 }
764769
765- #[ instrument( skip( self , qcx, parent_dep_node_index , frame) , level = "debug" ) ]
770+ #[ instrument( skip( self , qcx, frame) , level = "debug" ) ]
766771 fn try_mark_parent_green < Qcx : QueryContext < DepKind = K > > (
767772 & self ,
768773 qcx : Qcx ,
@@ -861,10 +866,11 @@ impl<K: DepKind> DepGraphData<K> {
861866 let frame = MarkFrame { index : prev_dep_node_index, parent : frame } ;
862867
863868 #[ cfg( not( parallel_compiler) ) ]
864- {
865- debug_assert ! ( !self . dep_node_exists( dep_node) ) ;
866- debug_assert ! ( self . colors. get( prev_dep_node_index) . is_none( ) ) ;
867- }
869+ self . assert_nonexistent_node ( dep_node, || {
870+ format ! ( "trying to mark existing {dep_node:?} as green" )
871+ } ) ;
872+ #[ cfg( not( parallel_compiler) ) ]
873+ debug_assert ! ( self . colors. get( prev_dep_node_index) . is_none( ) ) ;
868874
869875 // We never try to mark eval_always nodes as green
870876 debug_assert ! ( !qcx. dep_context( ) . is_eval_always( dep_node. kind) ) ;
@@ -959,6 +965,18 @@ impl<K: DepKind> DepGraph<K> {
959965 self . node_color ( dep_node) . is_some_and ( |c| c. is_green ( ) )
960966 }
961967
968+ pub fn assert_nonexistent_node < S : std:: fmt:: Display > (
969+ & self ,
970+ dep_node : & DepNode < K > ,
971+ msg : impl FnOnce ( ) -> S ,
972+ ) {
973+ if cfg ! ( debug_assertions)
974+ && let Some ( data) = & self . data
975+ {
976+ data. assert_nonexistent_node ( dep_node, msg)
977+ }
978+ }
979+
962980 /// This method loads all on-disk cacheable query results into memory, so
963981 /// they can be written out to the new cache file again. Most query results
964982 /// will already be in memory but in the case where we marked something as
@@ -1066,24 +1084,24 @@ rustc_index::newtype_index! {
10661084/// largest in the compiler.
10671085///
10681086/// For this reason, we avoid storing `DepNode`s more than once as map
1069- /// keys. The `new_node_to_index ` map only contains nodes not in the previous
1087+ /// keys. The `anon_node_to_index ` map only contains nodes of anonymous queries not in the previous
10701088/// graph, and we map nodes in the previous graph to indices via a two-step
10711089/// mapping. `SerializedDepGraph` maps from `DepNode` to `SerializedDepNodeIndex`,
10721090/// and the `prev_index_to_index` vector (which is more compact and faster than
10731091/// using a map) maps from `SerializedDepNodeIndex` to `DepNodeIndex`.
10741092///
1075- /// This struct uses three locks internally. The `data`, `new_node_to_index `,
1093+ /// This struct uses three locks internally. The `data`, `anon_node_to_index `,
10761094/// and `prev_index_to_index` fields are locked separately. Operations that take
10771095/// a `DepNodeIndex` typically just access the `data` field.
10781096///
10791097/// We only need to manipulate at most two locks simultaneously:
1080- /// `new_node_to_index ` and `data`, or `prev_index_to_index` and `data`. When
1081- /// manipulating both, we acquire `new_node_to_index ` or `prev_index_to_index`
1098+ /// `anon_node_to_index ` and `data`, or `prev_index_to_index` and `data`. When
1099+ /// manipulating both, we acquire `anon_node_to_index ` or `prev_index_to_index`
10821100/// first, and `data` second.
10831101pub ( super ) struct CurrentDepGraph < K : DepKind > {
10841102 encoder : Steal < GraphEncoder < K > > ,
1085- new_node_to_index : Sharded < FxHashMap < DepNode < K > , DepNodeIndex > > ,
10861103 prev_index_to_index : Lock < IndexVec < SerializedDepNodeIndex , Option < DepNodeIndex > > > ,
1104+ anon_node_to_index : Sharded < FxHashMap < DepNode < K > , DepNodeIndex > > ,
10871105
10881106 /// This is used to verify that fingerprints do not change between the creation of a node
10891107 /// and its recomputation.
@@ -1095,6 +1113,11 @@ pub(super) struct CurrentDepGraph<K: DepKind> {
10951113 #[ cfg( debug_assertions) ]
10961114 forbidden_edge : Option < EdgeFilter < K > > ,
10971115
1116+ /// Used to verify the absence of hash collisions among DepNodes.
1117+ /// This field is only `Some` if the `-Z incremental_verify_ich` option is present.
1118+ #[ cfg( debug_assertions) ]
1119+ seen_dep_nodes : Option < Lock < FxHashSet < DepNode < K > > > > ,
1120+
10981121 /// Anonymous `DepNode`s are nodes whose IDs we compute from the list of
10991122 /// their edges. This has the beneficial side-effect that multiple anonymous
11001123 /// nodes can be coalesced into one without changing the semantics of the
@@ -1122,7 +1145,7 @@ pub(super) struct CurrentDepGraph<K: DepKind> {
11221145
11231146impl < K : DepKind > CurrentDepGraph < K > {
11241147 fn new (
1125- profiler : & SelfProfilerRef ,
1148+ session : & Session ,
11261149 prev_graph_node_count : usize ,
11271150 encoder : FileEncoder ,
11281151 record_graph : bool ,
@@ -1152,7 +1175,8 @@ impl<K: DepKind> CurrentDepGraph<K> {
11521175
11531176 let new_node_count_estimate = 102 * prev_graph_node_count / 100 + 200 ;
11541177
1155- let node_intern_event_id = profiler
1178+ let node_intern_event_id = session
1179+ . prof
11561180 . get_or_alloc_cached_string ( "incr_comp_intern_dep_graph_node" )
11571181 . map ( EventId :: from_label) ;
11581182
@@ -1163,7 +1187,7 @@ impl<K: DepKind> CurrentDepGraph<K> {
11631187 record_graph,
11641188 record_stats,
11651189 ) ) ,
1166- new_node_to_index : Sharded :: new ( || {
1190+ anon_node_to_index : Sharded :: new ( || {
11671191 FxHashMap :: with_capacity_and_hasher (
11681192 new_node_count_estimate / sharded:: SHARDS ,
11691193 Default :: default ( ) ,
@@ -1175,6 +1199,13 @@ impl<K: DepKind> CurrentDepGraph<K> {
11751199 forbidden_edge,
11761200 #[ cfg( debug_assertions) ]
11771201 fingerprints : Lock :: new ( IndexVec :: from_elem_n ( None , new_node_count_estimate) ) ,
1202+ #[ cfg( debug_assertions) ]
1203+ seen_dep_nodes : session. opts . unstable_opts . incremental_verify_ich . then ( || {
1204+ Lock :: new ( FxHashSet :: with_capacity_and_hasher (
1205+ new_node_count_estimate,
1206+ Default :: default ( ) ,
1207+ ) )
1208+ } ) ,
11781209 total_read_count : AtomicU64 :: new ( 0 ) ,
11791210 total_duplicate_read_count : AtomicU64 :: new ( 0 ) ,
11801211 node_intern_event_id,
@@ -1200,20 +1231,18 @@ impl<K: DepKind> CurrentDepGraph<K> {
12001231 edges : EdgesVec ,
12011232 current_fingerprint : Fingerprint ,
12021233 ) -> DepNodeIndex {
1203- let dep_node_index = match self . new_node_to_index . get_shard_by_value ( & key) . lock ( ) . entry ( key)
1204- {
1205- Entry :: Occupied ( entry) => * entry. get ( ) ,
1206- Entry :: Vacant ( entry) => {
1207- let dep_node_index =
1208- self . encoder . borrow ( ) . send ( profiler, key, current_fingerprint, edges) ;
1209- entry. insert ( dep_node_index) ;
1210- dep_node_index
1211- }
1212- } ;
1234+ let dep_node_index = self . encoder . borrow ( ) . send ( profiler, key, current_fingerprint, edges) ;
12131235
12141236 #[ cfg( debug_assertions) ]
12151237 self . record_edge ( dep_node_index, key, current_fingerprint) ;
12161238
1239+ #[ cfg( debug_assertions) ]
1240+ if let Some ( ref seen_dep_nodes) = self . seen_dep_nodes {
1241+ if !seen_dep_nodes. lock ( ) . insert ( key) {
1242+ panic ! ( "Found duplicate dep-node {key:?}" ) ;
1243+ }
1244+ }
1245+
12171246 dep_node_index
12181247 }
12191248
@@ -1297,8 +1326,6 @@ impl<K: DepKind> CurrentDepGraph<K> {
12971326 prev_graph : & SerializedDepGraph < K > ,
12981327 prev_index : SerializedDepNodeIndex ,
12991328 ) -> DepNodeIndex {
1300- self . debug_assert_not_in_new_nodes ( prev_graph, prev_index) ;
1301-
13021329 let mut prev_index_to_index = self . prev_index_to_index . lock ( ) ;
13031330
13041331 match prev_index_to_index[ prev_index] {
@@ -1319,19 +1346,6 @@ impl<K: DepKind> CurrentDepGraph<K> {
13191346 }
13201347 }
13211348 }
1322-
1323- #[ inline]
1324- fn debug_assert_not_in_new_nodes (
1325- & self ,
1326- prev_graph : & SerializedDepGraph < K > ,
1327- prev_index : SerializedDepNodeIndex ,
1328- ) {
1329- let node = & prev_graph. index_to_node ( prev_index) ;
1330- debug_assert ! (
1331- !self . new_node_to_index. get_shard_by_value( node) . lock( ) . contains_key( node) ,
1332- "node from previous graph present in new node collection"
1333- ) ;
1334- }
13351349}
13361350
13371351/// The capacity of the `reads` field `SmallVec`
0 commit comments