@@ -41,90 +41,105 @@ struct StackEntry {
4141 bb : mir:: BasicBlock ,
4242 lo : usize ,
4343 hi : usize ,
44- first_part_only : bool ,
4544}
4645
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 ( ) ,
8862 }
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+ }
89108
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 {
103120 bb : succ_bb,
104121 lo : 0 ,
105- hi : * lo - 1 ,
106- first_part_only : true ,
122+ hi : first_lo - 1 ,
107123 } ) ;
124+
125+ // And update this entry with 0, to represent the
126+ // whole BB being processed.
127+ first_lo = 0 ;
108128 }
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 {
114130 // succ_bb hasn't been seen before. Add it to
115131 // `stack` for processing.
116- stack . push ( StackEntry {
132+ self . visit_stack . push ( StackEntry {
117133 bb : succ_bb,
118134 lo : 0 ,
119- hi : body[ succ_bb] . statements . len ( ) ,
120- first_part_only : false ,
135+ hi : self . body [ succ_bb] . statements . len ( ) ,
121136 } ) ;
122- // Insert 0 for this BB, to represent the whole BB
123- // being processed.
124- 0
125- } ) ;
137+ }
138+ }
126139 }
127140 }
141+
142+ self . visited . clear ( ) ;
128143 }
129144}
130145
@@ -133,28 +148,21 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
133148 tcx : TyCtxt < ' tcx > ,
134149 body : & ' a Body < ' tcx > ,
135150 nonlexical_regioncx : Rc < RegionInferenceContext < ' tcx > > ,
136- borrow_set : & Rc < BorrowSet < ' tcx > > ,
151+ borrow_set : Rc < BorrowSet < ' tcx > > ,
137152 ) -> Self {
138- let mut borrows_out_of_scope_at_location = FxHashMap :: default ( ) ;
153+ let mut prec = OutOfScopePrecomputer :: new ( body , nonlexical_regioncx . clone ( ) ) ;
139154 for ( borrow_index, borrow_data) in borrow_set. iter_enumerated ( ) {
140155 let borrow_region = borrow_data. region . to_region_vid ( ) ;
141156 let location = borrow_data. reserve_location ;
142157
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) ;
151159 }
152160
153161 Borrows {
154162 tcx,
155163 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 ,
158166 _nonlexical_regioncx : nonlexical_regioncx,
159167 }
160168 }
0 commit comments