@@ -18,9 +18,26 @@ use borrow_check::nll::region_infer::values::{RegionElementIndex, RegionValueEle
18
18
use syntax:: codemap:: Span ;
19
19
use rustc:: mir:: { Location , Mir } ;
20
20
use rustc:: ty:: RegionVid ;
21
- use rustc_data_structures:: fx:: FxHashSet ;
21
+ use rustc_data_structures:: bitvec:: BitVector ;
22
+ use rustc_data_structures:: indexed_vec:: Idx ;
23
+
24
+ pub ( super ) struct DfsStorage {
25
+ stack : Vec < Location > ,
26
+ visited : BitVector ,
27
+ }
22
28
23
29
impl < ' tcx > RegionInferenceContext < ' tcx > {
30
+ /// Creates dfs storage for use by dfs; this should be shared
31
+ /// across as many calls to dfs as possible to amortize allocation
32
+ /// costs.
33
+ pub ( super ) fn new_dfs_storage ( & self ) -> DfsStorage {
34
+ let num_elements = self . elements . num_elements ( ) ;
35
+ DfsStorage {
36
+ stack : vec ! [ ] ,
37
+ visited : BitVector :: new ( num_elements) ,
38
+ }
39
+ }
40
+
24
41
/// Function used to satisfy or test a `R1: R2 @ P`
25
42
/// constraint. The core idea is that it performs a DFS starting
26
43
/// from `P`. The precise actions *during* that DFS depend on the
@@ -34,25 +51,29 @@ impl<'tcx> RegionInferenceContext<'tcx> {
34
51
/// - `Ok(false)` if the walk was completed with no changes;
35
52
/// - `Err(early)` if the walk was existed early by `op`. `earlyelem` is the
36
53
/// value that `op` returned.
37
- pub ( super ) fn dfs < C > ( & self , mir : & Mir < ' tcx > , mut op : C ) -> Result < bool , C :: Early >
54
+ #[ inline( never) ] // ensure dfs is identifiable in profiles
55
+ pub ( super ) fn dfs < C > (
56
+ & self ,
57
+ mir : & Mir < ' tcx > ,
58
+ dfs : & mut DfsStorage ,
59
+ mut op : C ,
60
+ ) -> Result < bool , C :: Early >
38
61
where
39
62
C : DfsOp ,
40
63
{
41
64
let mut changed = false ;
42
65
43
- let mut stack = vec ! [ ] ;
44
- let mut visited = FxHashSet ( ) ;
45
-
46
- stack. push ( op. start_point ( ) ) ;
47
- while let Some ( p) = stack. pop ( ) {
66
+ dfs. visited . clear ( ) ;
67
+ dfs. stack . push ( op. start_point ( ) ) ;
68
+ while let Some ( p) = dfs. stack . pop ( ) {
48
69
let point_index = self . elements . index ( p) ;
49
70
50
71
if !op. source_region_contains ( point_index) {
51
72
debug ! ( " not in from-region" ) ;
52
73
continue ;
53
74
}
54
75
55
- if !visited. insert ( p ) {
76
+ if !dfs . visited . insert ( point_index . index ( ) ) {
56
77
debug ! ( " already visited" ) ;
57
78
continue ;
58
79
}
@@ -62,25 +83,27 @@ impl<'tcx> RegionInferenceContext<'tcx> {
62
83
63
84
let block_data = & mir[ p. block ] ;
64
85
65
- let start_stack_len = stack. len ( ) ;
86
+ let start_stack_len = dfs . stack . len ( ) ;
66
87
67
88
if p. statement_index < block_data. statements . len ( ) {
68
- stack. push ( Location {
89
+ dfs . stack . push ( Location {
69
90
statement_index : p. statement_index + 1 ,
70
91
..p
71
92
} ) ;
72
93
} else {
73
- stack. extend ( block_data. terminator ( ) . successors ( ) . iter ( ) . map (
74
- |& basic_block| {
75
- Location {
94
+ dfs. stack . extend (
95
+ block_data
96
+ . terminator ( )
97
+ . successors ( )
98
+ . iter ( )
99
+ . map ( |& basic_block| Location {
76
100
statement_index : 0 ,
77
101
block : basic_block,
78
- }
79
- } ,
80
- ) ) ;
102
+ } ) ,
103
+ ) ;
81
104
}
82
105
83
- if stack. len ( ) == start_stack_len {
106
+ if dfs . stack . len ( ) == start_stack_len {
84
107
// If we reach the END point in the graph, then copy
85
108
// over any skolemized end points in the `from_region`
86
109
// and make sure they are included in the `to_region`.
@@ -229,9 +252,8 @@ impl<'v, 'tcx> DfsOp for TestTargetOutlivesSource<'v, 'tcx> {
229
252
// `X: ur_in_source`, OK.
230
253
if self . inferred_values
231
254
. universal_regions_outlived_by ( self . target_region )
232
- . any ( |ur_in_target| {
233
- self . universal_regions . outlives ( ur_in_target, ur_in_source)
234
- } ) {
255
+ . any ( |ur_in_target| self . universal_regions . outlives ( ur_in_target, ur_in_source) )
256
+ {
235
257
continue ;
236
258
}
237
259
0 commit comments