@@ -7,14 +7,16 @@ use std::sync::atomic::{AtomicU32, Ordering};
7
7
8
8
use rustc_data_structures:: fingerprint:: Fingerprint ;
9
9
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
10
- use rustc_data_structures:: profiling:: { QueryInvocationId , SelfProfilerRef } ;
10
+ use rustc_data_structures:: outline;
11
+ use rustc_data_structures:: profiling:: QueryInvocationId ;
11
12
use rustc_data_structures:: sharded:: { self , ShardedHashMap } ;
12
13
use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher } ;
13
14
use rustc_data_structures:: sync:: { AtomicU64 , Lock } ;
14
15
use rustc_data_structures:: unord:: UnordMap ;
15
16
use rustc_index:: IndexVec ;
16
17
use rustc_macros:: { Decodable , Encodable } ;
17
18
use rustc_serialize:: opaque:: { FileEncodeResult , FileEncoder } ;
19
+ use rustc_session:: Session ;
18
20
use tracing:: { debug, instrument} ;
19
21
#[ cfg( debug_assertions) ]
20
22
use { super :: debug:: EdgeFilter , std:: env} ;
@@ -118,7 +120,7 @@ where
118
120
119
121
impl < D : Deps > DepGraph < D > {
120
122
pub fn new (
121
- profiler : & SelfProfilerRef ,
123
+ session : & Session ,
122
124
prev_graph : Arc < SerializedDepGraph > ,
123
125
prev_work_products : WorkProductMap ,
124
126
encoder : FileEncoder ,
@@ -128,7 +130,7 @@ impl<D: Deps> DepGraph<D> {
128
130
let prev_graph_node_count = prev_graph. node_count ( ) ;
129
131
130
132
let current = CurrentDepGraph :: new (
131
- profiler ,
133
+ session ,
132
134
prev_graph_node_count,
133
135
encoder,
134
136
record_graph,
@@ -139,7 +141,7 @@ impl<D: Deps> DepGraph<D> {
139
141
let colors = DepNodeColorMap :: new ( prev_graph_node_count) ;
140
142
141
143
// Instantiate a dependy-less node only once for anonymous queries.
142
- let _green_node_index = current. intern_new_node (
144
+ let _green_node_index = current. alloc_new_node (
143
145
DepNode { kind : D :: DEP_KIND_NULL , hash : current. anon_id_seed . into ( ) } ,
144
146
EdgesVec :: new ( ) ,
145
147
Fingerprint :: ZERO ,
@@ -353,12 +355,13 @@ impl<D: Deps> DepGraphData<D> {
353
355
// in `DepGraph::try_mark_green()`.
354
356
// 2. Two distinct query keys get mapped to the same `DepNode`
355
357
// (see for example #48923).
356
- assert ! (
357
- ! self . dep_node_exists ( & key ) ,
358
- "forcing query with already existing `DepNode`\n \
358
+ self . assert_dep_node_not_yet_allocated_in_current_session ( & key , || {
359
+ format ! (
360
+ "forcing query with already existing `DepNode`\n \
359
361
- query-key: {arg:?}\n \
360
362
- dep-node: {key:?}"
361
- ) ;
363
+ )
364
+ } ) ;
362
365
363
366
let with_deps = |task_deps| D :: with_deps ( task_deps, || task ( cx, arg) ) ;
364
367
let ( result, edges) = if cx. dep_context ( ) . is_eval_always ( key. kind ) {
@@ -438,7 +441,16 @@ impl<D: Deps> DepGraphData<D> {
438
441
hash : self . current . anon_id_seed . combine ( hasher. finish ( ) ) . into ( ) ,
439
442
} ;
440
443
441
- self . current . intern_new_node ( target_dep_node, task_deps, Fingerprint :: ZERO )
444
+ // The DepNodes generated by the process above are not unique. 2 queries could
445
+ // have exactly the same dependencies. However, deserialization does not handle
446
+ // duplicated nodes, so we do the deduplication here directly.
447
+ //
448
+ // As anonymous nodes are a small quantity compared to the full dep-graph, the
449
+ // memory impact of this `anon_node_to_index` map remains tolerable, and helps
450
+ // us avoid useless growth of the graph with almost-equivalent nodes.
451
+ self . current . anon_node_to_index . get_or_insert_with ( target_dep_node, || {
452
+ self . current . alloc_new_node ( target_dep_node, task_deps, Fingerprint :: ZERO )
453
+ } )
442
454
}
443
455
} ;
444
456
@@ -613,20 +625,24 @@ impl<D: Deps> DepGraph<D> {
613
625
}
614
626
615
627
impl < D : Deps > DepGraphData < D > {
616
- #[ inline]
617
- fn dep_node_index_of_opt ( & self , dep_node : & DepNode ) -> Option < DepNodeIndex > {
628
+ fn assert_dep_node_not_yet_allocated_in_current_session < S : std:: fmt:: Display > (
629
+ & self ,
630
+ dep_node : & DepNode ,
631
+ msg : impl FnOnce ( ) -> S ,
632
+ ) {
618
633
if let Some ( prev_index) = self . previous . node_to_index_opt ( dep_node) {
619
- self . current . prev_index_to_index . lock ( ) [ prev_index]
620
- } else {
621
- self . current . new_node_to_index . get ( dep_node)
634
+ let current = self . current . prev_index_to_index . lock ( ) [ prev_index] ;
635
+ assert ! ( current. is_none( ) , "{}" , msg( ) )
636
+ } else if let Some ( nodes_newly_allocated_in_current_session) =
637
+ & self . current . nodes_newly_allocated_in_current_session
638
+ {
639
+ outline ( || {
640
+ let seen = nodes_newly_allocated_in_current_session. lock ( ) . contains_key ( dep_node) ;
641
+ assert ! ( !seen, "{}" , msg( ) ) ;
642
+ } ) ;
622
643
}
623
644
}
624
645
625
- #[ inline]
626
- fn dep_node_exists ( & self , dep_node : & DepNode ) -> bool {
627
- self . dep_node_index_of_opt ( dep_node) . is_some ( )
628
- }
629
-
630
646
fn node_color ( & self , dep_node : & DepNode ) -> Option < DepNodeColor > {
631
647
if let Some ( prev_index) = self . previous . node_to_index_opt ( dep_node) {
632
648
self . colors . get ( prev_index)
@@ -659,11 +675,6 @@ impl<D: Deps> DepGraphData<D> {
659
675
}
660
676
661
677
impl < D : Deps > DepGraph < D > {
662
- #[ inline]
663
- pub fn dep_node_exists ( & self , dep_node : & DepNode ) -> bool {
664
- self . data . as_ref ( ) . is_some_and ( |data| data. dep_node_exists ( dep_node) )
665
- }
666
-
667
678
/// Checks whether a previous work product exists for `v` and, if
668
679
/// so, return the path that leads to it. Used to skip doing work.
669
680
pub fn previous_work_product ( & self , v : & WorkProductId ) -> Option < WorkProduct > {
@@ -926,6 +937,16 @@ impl<D: Deps> DepGraph<D> {
926
937
self . node_color ( dep_node) . is_some_and ( |c| c. is_green ( ) )
927
938
}
928
939
940
+ pub fn assert_dep_node_not_yet_allocated_in_current_session < S : std:: fmt:: Display > (
941
+ & self ,
942
+ dep_node : & DepNode ,
943
+ msg : impl FnOnce ( ) -> S ,
944
+ ) {
945
+ if let Some ( data) = & self . data {
946
+ data. assert_dep_node_not_yet_allocated_in_current_session ( dep_node, msg)
947
+ }
948
+ }
949
+
929
950
/// This method loads all on-disk cacheable query results into memory, so
930
951
/// they can be written out to the new cache file again. Most query results
931
952
/// will already be in memory but in the case where we marked something as
@@ -1031,24 +1052,24 @@ rustc_index::newtype_index! {
1031
1052
/// largest in the compiler.
1032
1053
///
1033
1054
/// For this reason, we avoid storing `DepNode`s more than once as map
1034
- /// keys. The `new_node_to_index ` map only contains nodes not in the previous
1055
+ /// keys. The `anon_node_to_index ` map only contains nodes of anonymous queries not in the previous
1035
1056
/// graph, and we map nodes in the previous graph to indices via a two-step
1036
1057
/// mapping. `SerializedDepGraph` maps from `DepNode` to `SerializedDepNodeIndex`,
1037
1058
/// and the `prev_index_to_index` vector (which is more compact and faster than
1038
1059
/// using a map) maps from `SerializedDepNodeIndex` to `DepNodeIndex`.
1039
1060
///
1040
- /// This struct uses three locks internally. The `data`, `new_node_to_index `,
1061
+ /// This struct uses three locks internally. The `data`, `anon_node_to_index `,
1041
1062
/// and `prev_index_to_index` fields are locked separately. Operations that take
1042
1063
/// a `DepNodeIndex` typically just access the `data` field.
1043
1064
///
1044
1065
/// We only need to manipulate at most two locks simultaneously:
1045
- /// `new_node_to_index ` and `data`, or `prev_index_to_index` and `data`. When
1046
- /// manipulating both, we acquire `new_node_to_index ` or `prev_index_to_index`
1066
+ /// `anon_node_to_index ` and `data`, or `prev_index_to_index` and `data`. When
1067
+ /// manipulating both, we acquire `anon_node_to_index ` or `prev_index_to_index`
1047
1068
/// first, and `data` second.
1048
1069
pub ( super ) struct CurrentDepGraph < D : Deps > {
1049
1070
encoder : GraphEncoder < D > ,
1050
- new_node_to_index : ShardedHashMap < DepNode , DepNodeIndex > ,
1051
1071
prev_index_to_index : Lock < IndexVec < SerializedDepNodeIndex , Option < DepNodeIndex > > > ,
1072
+ anon_node_to_index : ShardedHashMap < DepNode , DepNodeIndex > ,
1052
1073
1053
1074
/// This is used to verify that fingerprints do not change between the creation of a node
1054
1075
/// and its recomputation.
@@ -1060,6 +1081,14 @@ pub(super) struct CurrentDepGraph<D: Deps> {
1060
1081
#[ cfg( debug_assertions) ]
1061
1082
forbidden_edge : Option < EdgeFilter > ,
1062
1083
1084
+ /// Used to verify the absence of hash collisions among DepNodes.
1085
+ /// This field is only `Some` if the `-Z incremental_verify_ich` option is present
1086
+ /// or if `debug_assertions` are enabled.
1087
+ ///
1088
+ /// The map contains all DepNodes that have been allocated in the current session so far and
1089
+ /// for which there is no equivalent in the previous session.
1090
+ nodes_newly_allocated_in_current_session : Option < Lock < FxHashMap < DepNode , DepNodeIndex > > > ,
1091
+
1063
1092
/// Anonymous `DepNode`s are nodes whose IDs we compute from the list of
1064
1093
/// their edges. This has the beneficial side-effect that multiple anonymous
1065
1094
/// nodes can be coalesced into one without changing the semantics of the
@@ -1081,7 +1110,7 @@ pub(super) struct CurrentDepGraph<D: Deps> {
1081
1110
1082
1111
impl < D : Deps > CurrentDepGraph < D > {
1083
1112
fn new (
1084
- profiler : & SelfProfilerRef ,
1113
+ session : & Session ,
1085
1114
prev_graph_node_count : usize ,
1086
1115
encoder : FileEncoder ,
1087
1116
record_graph : bool ,
@@ -1107,16 +1136,20 @@ impl<D: Deps> CurrentDepGraph<D> {
1107
1136
1108
1137
let new_node_count_estimate = 102 * prev_graph_node_count / 100 + 200 ;
1109
1138
1139
+ let new_node_dbg =
1140
+ session. opts . unstable_opts . incremental_verify_ich || cfg ! ( debug_assertions) ;
1141
+
1110
1142
CurrentDepGraph {
1111
1143
encoder : GraphEncoder :: new (
1112
1144
encoder,
1113
1145
prev_graph_node_count,
1114
1146
record_graph,
1115
1147
record_stats,
1116
- profiler ,
1148
+ & session . prof ,
1117
1149
previous,
1118
1150
) ,
1119
- new_node_to_index : ShardedHashMap :: with_capacity (
1151
+ anon_node_to_index : ShardedHashMap :: with_capacity (
1152
+ // FIXME: The count estimate is off as anon nodes are only a portion of the nodes.
1120
1153
new_node_count_estimate / sharded:: shards ( ) ,
1121
1154
) ,
1122
1155
prev_index_to_index : Lock :: new ( IndexVec :: from_elem_n ( None , prev_graph_node_count) ) ,
@@ -1125,6 +1158,12 @@ impl<D: Deps> CurrentDepGraph<D> {
1125
1158
forbidden_edge,
1126
1159
#[ cfg( debug_assertions) ]
1127
1160
fingerprints : Lock :: new ( IndexVec :: from_elem_n ( None , new_node_count_estimate) ) ,
1161
+ nodes_newly_allocated_in_current_session : new_node_dbg. then ( || {
1162
+ Lock :: new ( FxHashMap :: with_capacity_and_hasher (
1163
+ new_node_count_estimate,
1164
+ Default :: default ( ) ,
1165
+ ) )
1166
+ } ) ,
1128
1167
total_read_count : AtomicU64 :: new ( 0 ) ,
1129
1168
total_duplicate_read_count : AtomicU64 :: new ( 0 ) ,
1130
1169
}
@@ -1142,19 +1181,31 @@ impl<D: Deps> CurrentDepGraph<D> {
1142
1181
/// Writes the node to the current dep-graph and allocates a `DepNodeIndex` for it.
1143
1182
/// Assumes that this is a node that has no equivalent in the previous dep-graph.
1144
1183
#[ inline( always) ]
1145
- fn intern_new_node (
1184
+ fn alloc_new_node (
1146
1185
& self ,
1147
1186
key : DepNode ,
1148
1187
edges : EdgesVec ,
1149
1188
current_fingerprint : Fingerprint ,
1150
1189
) -> DepNodeIndex {
1151
- let dep_node_index = self
1152
- . new_node_to_index
1153
- . get_or_insert_with ( key, || self . encoder . send ( key, current_fingerprint, edges) ) ;
1190
+ let dep_node_index = self . encoder . send ( key, current_fingerprint, edges) ;
1154
1191
1155
1192
#[ cfg( debug_assertions) ]
1156
1193
self . record_edge ( dep_node_index, key, current_fingerprint) ;
1157
1194
1195
+ if let Some ( ref nodes_newly_allocated_in_current_session) =
1196
+ self . nodes_newly_allocated_in_current_session
1197
+ {
1198
+ outline ( || {
1199
+ if nodes_newly_allocated_in_current_session
1200
+ . lock ( )
1201
+ . insert ( key, dep_node_index)
1202
+ . is_some ( )
1203
+ {
1204
+ panic ! ( "Found duplicate dep-node {key:?}" ) ;
1205
+ }
1206
+ } ) ;
1207
+ }
1208
+
1158
1209
dep_node_index
1159
1210
}
1160
1211
@@ -1209,7 +1260,7 @@ impl<D: Deps> CurrentDepGraph<D> {
1209
1260
let fingerprint = fingerprint. unwrap_or ( Fingerprint :: ZERO ) ;
1210
1261
1211
1262
// This is a new node: it didn't exist in the previous compilation session.
1212
- let dep_node_index = self . intern_new_node ( key, edges, fingerprint) ;
1263
+ let dep_node_index = self . alloc_new_node ( key, edges, fingerprint) ;
1213
1264
1214
1265
( dep_node_index, None )
1215
1266
}
@@ -1248,7 +1299,10 @@ impl<D: Deps> CurrentDepGraph<D> {
1248
1299
) {
1249
1300
let node = & prev_graph. index_to_node ( prev_index) ;
1250
1301
debug_assert ! (
1251
- !self . new_node_to_index. get( node) . is_some( ) ,
1302
+ !self
1303
+ . nodes_newly_allocated_in_current_session
1304
+ . as_ref( )
1305
+ . map_or( false , |set| set. lock( ) . contains_key( node) ) ,
1252
1306
"node from previous graph present in new node collection"
1253
1307
) ;
1254
1308
}
@@ -1370,13 +1424,12 @@ fn panic_on_forbidden_read<D: Deps>(data: &DepGraphData<D>, dep_node_index: DepN
1370
1424
}
1371
1425
}
1372
1426
1373
- if dep_node. is_none ( ) {
1374
- // Try to find it among the new nodes
1375
- for shard in data. current . new_node_to_index . lock_shards ( ) {
1376
- if let Some ( ( node, _) ) = shard. iter ( ) . find ( |( _, index) | * index == dep_node_index) {
1377
- dep_node = Some ( * node) ;
1378
- break ;
1379
- }
1427
+ if dep_node. is_none ( )
1428
+ && let Some ( nodes) = & data. current . nodes_newly_allocated_in_current_session
1429
+ {
1430
+ // Try to find it among the nodes allocated so far in this session
1431
+ if let Some ( ( node, _) ) = nodes. lock ( ) . iter ( ) . find ( |& ( _, index) | * index == dep_node_index) {
1432
+ dep_node = Some ( * node) ;
1380
1433
}
1381
1434
}
1382
1435
0 commit comments