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