@@ -152,6 +152,11 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
152
152
let directory = DefIdDirectory :: decode ( & mut dep_graph_decoder) ?;
153
153
let serialized_dep_graph = SerializedDepGraph :: decode ( & mut dep_graph_decoder) ?;
154
154
155
+ let edge_map: FxHashMap < _ , _ > = serialized_dep_graph. edges
156
+ . into_iter ( )
157
+ . map ( |s| ( s. source , s. targets ) )
158
+ . collect ( ) ;
159
+
155
160
// Retrace the paths in the directory to find their current location (if any).
156
161
let retraced = directory. retrace ( tcx) ;
157
162
@@ -166,46 +171,48 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
166
171
incremental_hashes_map,
167
172
& serialized_dep_graph. hashes ,
168
173
& retraced) ;
169
- let dirty_raw_nodes = transitive_dirty_nodes ( & serialized_dep_graph . edges , dirty_raw_nodes) ;
174
+ let dirty_raw_nodes = transitive_dirty_nodes ( & edge_map , dirty_raw_nodes) ;
170
175
171
176
// Recreate the edges in the graph that are still clean.
172
177
let mut clean_work_products = FxHashSet ( ) ;
173
178
let mut dirty_work_products = FxHashSet ( ) ; // incomplete; just used to suppress debug output
174
- for edge in & serialized_dep_graph. edges {
175
- // If the target is dirty, skip the edge. If this is an edge
176
- // that targets a work-product, we can print the blame
177
- // information now.
178
- if let Some ( blame) = dirty_raw_nodes. get ( & edge. 1 ) {
179
- if let DepNode :: WorkProduct ( ref wp) = edge. 1 {
180
- if tcx. sess . opts . debugging_opts . incremental_info {
181
- if dirty_work_products. insert ( wp. clone ( ) ) {
182
- // It'd be nice to pretty-print these paths better than just
183
- // using the `Debug` impls, but wev.
184
- println ! ( "incremental: module {:?} is dirty because {:?} \
185
- changed or was removed",
186
- wp,
187
- blame. map_def( |& index| {
188
- Some ( directory. def_path_string( tcx, index) )
189
- } ) . unwrap( ) ) ;
179
+ for ( source, targets) in & edge_map {
180
+ for target in targets {
181
+ // If the target is dirty, skip the edge. If this is an edge
182
+ // that targets a work-product, we can print the blame
183
+ // information now.
184
+ if let Some ( blame) = dirty_raw_nodes. get ( target) {
185
+ if let DepNode :: WorkProduct ( ref wp) = * target {
186
+ if tcx. sess . opts . debugging_opts . incremental_info {
187
+ if dirty_work_products. insert ( wp. clone ( ) ) {
188
+ // It'd be nice to pretty-print these paths better than just
189
+ // using the `Debug` impls, but wev.
190
+ println ! ( "incremental: module {:?} is dirty because {:?} \
191
+ changed or was removed",
192
+ wp,
193
+ blame. map_def( |& index| {
194
+ Some ( directory. def_path_string( tcx, index) )
195
+ } ) . unwrap( ) ) ;
196
+ }
190
197
}
191
198
}
199
+ continue ;
192
200
}
193
- continue ;
194
- }
195
201
196
- // If the source is dirty, the target will be dirty.
197
- assert ! ( !dirty_raw_nodes. contains_key( & edge. 0 ) ) ;
198
-
199
- // Retrace the source -> target edges to def-ids and then
200
- // create an edge in the graph. Retracing may yield none if
201
- // some of the data happens to have been removed; this ought
202
- // to be impossible unless it is dirty, so we can unwrap.
203
- let source_node = retraced. map ( & edge. 0 ) . unwrap ( ) ;
204
- let target_node = retraced. map ( & edge. 1 ) . unwrap ( ) ;
205
- let _task = tcx. dep_graph . in_task ( target_node) ;
206
- tcx. dep_graph . read ( source_node) ;
207
- if let DepNode :: WorkProduct ( ref wp) = edge. 1 {
208
- clean_work_products. insert ( wp. clone ( ) ) ;
202
+ // If the source is dirty, the target will be dirty.
203
+ assert ! ( !dirty_raw_nodes. contains_key( source) ) ;
204
+
205
+ // Retrace the source -> target edges to def-ids and then
206
+ // create an edge in the graph. Retracing may yield none if
207
+ // some of the data happens to have been removed; this ought
208
+ // to be impossible unless it is dirty, so we can unwrap.
209
+ let source_node = retraced. map ( source) . unwrap ( ) ;
210
+ let target_node = retraced. map ( target) . unwrap ( ) ;
211
+ let _task = tcx. dep_graph . in_task ( target_node) ;
212
+ tcx. dep_graph . read ( source_node) ;
213
+ if let DepNode :: WorkProduct ( ref wp) = * target {
214
+ clean_work_products. insert ( wp. clone ( ) ) ;
215
+ }
209
216
}
210
217
}
211
218
@@ -268,16 +275,23 @@ fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
268
275
dirty_nodes
269
276
}
270
277
271
- fn transitive_dirty_nodes ( edges : & [ SerializedEdge ] ,
278
+ fn transitive_dirty_nodes ( edge_map : & FxHashMap < DepNode < DefPathIndex > , Vec < DepNode < DefPathIndex > > > ,
272
279
mut dirty_nodes : DirtyNodes )
273
280
-> DirtyNodes
274
281
{
275
- let mut len = 0 ;
276
- while len != dirty_nodes. len ( ) {
277
- len = dirty_nodes. len ( ) ;
278
- for edge in edges {
279
- if let Some ( n) = dirty_nodes. get ( & edge. 0 ) . cloned ( ) {
280
- dirty_nodes. insert ( edge. 1 . clone ( ) , n) ;
282
+ let mut stack: Vec < ( DepNode < DefPathIndex > , DepNode < DefPathIndex > ) > = vec ! [ ] ;
283
+ stack. extend ( dirty_nodes. iter ( ) . map ( |( s, b) | ( s. clone ( ) , b. clone ( ) ) ) ) ;
284
+ while let Some ( ( source, blame) ) = stack. pop ( ) {
285
+ // we know the source is dirty (because of the node `blame`)...
286
+ assert ! ( dirty_nodes. contains_key( & source) ) ;
287
+
288
+ // ...so we dirty all the targets (with the same blame)
289
+ if let Some ( targets) = edge_map. get ( & source) {
290
+ for target in targets {
291
+ if !dirty_nodes. contains_key ( target) {
292
+ dirty_nodes. insert ( target. clone ( ) , blame. clone ( ) ) ;
293
+ stack. push ( ( target. clone ( ) , blame. clone ( ) ) ) ;
294
+ }
281
295
}
282
296
}
283
297
}
0 commit comments