@@ -41,90 +41,105 @@ struct StackEntry {
41
41
bb : mir:: BasicBlock ,
42
42
lo : usize ,
43
43
hi : usize ,
44
- first_part_only : bool ,
45
44
}
46
45
47
- fn precompute_borrows_out_of_scope < ' tcx > (
48
- body : & Body < ' tcx > ,
49
- regioncx : & Rc < RegionInferenceContext < ' tcx > > ,
50
- borrows_out_of_scope_at_location : & mut FxHashMap < Location , Vec < BorrowIndex > > ,
51
- borrow_index : BorrowIndex ,
52
- borrow_region : RegionVid ,
53
- location : Location ,
54
- ) {
55
- // We visit one BB at a time. The complication is that we may start in the
56
- // middle of the first BB visited (the one containing `location`), in which
57
- // case we may have to later on process the first part of that BB if there
58
- // is a path back to its start.
59
-
60
- // For visited BBs, we record the index of the first statement processed.
61
- // (In fully processed BBs this index is 0.) Note also that we add BBs to
62
- // `visited` once they are added to `stack`, before they are actually
63
- // processed, because this avoids the need to look them up again on
64
- // completion.
65
- let mut visited = FxHashMap :: default ( ) ;
66
- visited. insert ( location. block , location. statement_index ) ;
67
-
68
- let mut stack = vec ! [ ] ;
69
- stack. push ( StackEntry {
70
- bb : location. block ,
71
- lo : location. statement_index ,
72
- hi : body[ location. block ] . statements . len ( ) ,
73
- first_part_only : false ,
74
- } ) ;
75
-
76
- while let Some ( StackEntry { bb, lo, hi, first_part_only } ) = stack. pop ( ) {
77
- let mut finished_early = first_part_only;
78
- for i in lo..=hi {
79
- let location = Location { block : bb, statement_index : i } ;
80
- // If region does not contain a point at the location, then add to list and skip
81
- // successor locations.
82
- if !regioncx. region_contains ( borrow_region, location) {
83
- debug ! ( "borrow {:?} gets killed at {:?}" , borrow_index, location) ;
84
- borrows_out_of_scope_at_location. entry ( location) . or_default ( ) . push ( borrow_index) ;
85
- finished_early = true ;
86
- break ;
87
- }
46
+ struct OutOfScopePrecomputer < ' a , ' tcx > {
47
+ visited : BitSet < mir:: BasicBlock > ,
48
+ visit_stack : Vec < StackEntry > ,
49
+ body : & ' a Body < ' tcx > ,
50
+ regioncx : Rc < RegionInferenceContext < ' tcx > > ,
51
+ borrows_out_of_scope_at_location : FxHashMap < Location , Vec < BorrowIndex > > ,
52
+ }
53
+
54
+ impl < ' a , ' tcx > OutOfScopePrecomputer < ' a , ' tcx > {
55
+ fn new ( body : & ' a Body < ' tcx > , regioncx : Rc < RegionInferenceContext < ' tcx > > ) -> Self {
56
+ OutOfScopePrecomputer {
57
+ visited : BitSet :: new_empty ( body. basic_blocks ( ) . len ( ) ) ,
58
+ visit_stack : vec ! [ ] ,
59
+ body,
60
+ regioncx,
61
+ borrows_out_of_scope_at_location : FxHashMap :: default ( ) ,
88
62
}
63
+ }
64
+ }
65
+
66
+ impl < ' tcx > OutOfScopePrecomputer < ' _ , ' tcx > {
67
+ fn precompute_borrows_out_of_scope (
68
+ & mut self ,
69
+ borrow_index : BorrowIndex ,
70
+ borrow_region : RegionVid ,
71
+ location : Location ,
72
+ ) {
73
+ // We visit one BB at a time. The complication is that we may start in the
74
+ // middle of the first BB visited (the one containing `location`), in which
75
+ // case we may have to later on process the first part of that BB if there
76
+ // is a path back to its start.
77
+
78
+ // For visited BBs, we record the index of the first statement processed.
79
+ // (In fully processed BBs this index is 0.) Note also that we add BBs to
80
+ // `visited` once they are added to `stack`, before they are actually
81
+ // processed, because this avoids the need to look them up again on
82
+ // completion.
83
+ self . visited . insert ( location. block ) ;
84
+
85
+ let mut first_lo = location. statement_index ;
86
+ let first_hi = self . body [ location. block ] . statements . len ( ) ;
87
+
88
+ self . visit_stack . push ( StackEntry { bb : location. block , lo : first_lo, hi : first_hi } ) ;
89
+
90
+ while let Some ( StackEntry { bb, lo, hi } ) = self . visit_stack . pop ( ) {
91
+ // If we process the first part of the first basic block (i.e. we encounter that block
92
+ // for the second time), we no longer have to visit its successors again.
93
+ let mut finished_early = bb == location. block && hi != first_hi;
94
+ for i in lo..=hi {
95
+ let location = Location { block : bb, statement_index : i } ;
96
+ // If region does not contain a point at the location, then add to list and skip
97
+ // successor locations.
98
+ if !self . regioncx . region_contains ( borrow_region, location) {
99
+ debug ! ( "borrow {:?} gets killed at {:?}" , borrow_index, location) ;
100
+ self . borrows_out_of_scope_at_location
101
+ . entry ( location)
102
+ . or_default ( )
103
+ . push ( borrow_index) ;
104
+ finished_early = true ;
105
+ break ;
106
+ }
107
+ }
89
108
90
- if !finished_early {
91
- // Add successor BBs to the work list, if necessary.
92
- let bb_data = & body[ bb] ;
93
- assert ! ( hi == bb_data. statements. len( ) ) ;
94
- for & succ_bb in bb_data. terminator ( ) . successors ( ) {
95
- visited
96
- . entry ( succ_bb)
97
- . and_modify ( |lo| {
98
- // `succ_bb` has been seen before. If it wasn't
99
- // fully processed, add its first part to `stack`
100
- // for processing.
101
- if * lo > 0 {
102
- stack. push ( StackEntry {
109
+ if !finished_early {
110
+ // Add successor BBs to the work list, if necessary.
111
+ let bb_data = & self . body [ bb] ;
112
+ debug_assert ! ( hi == bb_data. statements. len( ) ) ;
113
+ for & succ_bb in bb_data. terminator ( ) . successors ( ) {
114
+ if self . visited . insert ( succ_bb) == false {
115
+ if succ_bb == location. block && first_lo > 0 {
116
+ // `succ_bb` has been seen before. If it wasn't
117
+ // fully processed, add its first part to `stack`
118
+ // for processing.
119
+ self . visit_stack . push ( StackEntry {
103
120
bb : succ_bb,
104
121
lo : 0 ,
105
- hi : * lo - 1 ,
106
- first_part_only : true ,
122
+ hi : first_lo - 1 ,
107
123
} ) ;
124
+
125
+ // And update this entry with 0, to represent the
126
+ // whole BB being processed.
127
+ first_lo = 0 ;
108
128
}
109
- // And update this entry with 0, to represent the
110
- // whole BB being processed.
111
- * lo = 0 ;
112
- } )
113
- . or_insert_with ( || {
129
+ } else {
114
130
// succ_bb hasn't been seen before. Add it to
115
131
// `stack` for processing.
116
- stack . push ( StackEntry {
132
+ self . visit_stack . push ( StackEntry {
117
133
bb : succ_bb,
118
134
lo : 0 ,
119
- hi : body[ succ_bb] . statements . len ( ) ,
120
- first_part_only : false ,
135
+ hi : self . body [ succ_bb] . statements . len ( ) ,
121
136
} ) ;
122
- // Insert 0 for this BB, to represent the whole BB
123
- // being processed.
124
- 0
125
- } ) ;
137
+ }
138
+ }
126
139
}
127
140
}
141
+
142
+ self . visited . clear ( ) ;
128
143
}
129
144
}
130
145
@@ -133,28 +148,21 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
133
148
tcx : TyCtxt < ' tcx > ,
134
149
body : & ' a Body < ' tcx > ,
135
150
nonlexical_regioncx : Rc < RegionInferenceContext < ' tcx > > ,
136
- borrow_set : & Rc < BorrowSet < ' tcx > > ,
151
+ borrow_set : Rc < BorrowSet < ' tcx > > ,
137
152
) -> Self {
138
- let mut borrows_out_of_scope_at_location = FxHashMap :: default ( ) ;
153
+ let mut prec = OutOfScopePrecomputer :: new ( body , nonlexical_regioncx . clone ( ) ) ;
139
154
for ( borrow_index, borrow_data) in borrow_set. iter_enumerated ( ) {
140
155
let borrow_region = borrow_data. region . to_region_vid ( ) ;
141
156
let location = borrow_data. reserve_location ;
142
157
143
- precompute_borrows_out_of_scope (
144
- body,
145
- & nonlexical_regioncx,
146
- & mut borrows_out_of_scope_at_location,
147
- borrow_index,
148
- borrow_region,
149
- location,
150
- ) ;
158
+ prec. precompute_borrows_out_of_scope ( borrow_index, borrow_region, location) ;
151
159
}
152
160
153
161
Borrows {
154
162
tcx,
155
163
body,
156
- borrow_set : borrow_set . clone ( ) ,
157
- borrows_out_of_scope_at_location,
164
+ borrow_set,
165
+ borrows_out_of_scope_at_location : prec . borrows_out_of_scope_at_location ,
158
166
_nonlexical_regioncx : nonlexical_regioncx,
159
167
}
160
168
}
0 commit comments