@@ -18,7 +18,7 @@ use std::mem;
18
18
use std:: usize;
19
19
20
20
use super :: MirBorrowckCtxt ;
21
- use super :: gather_moves:: { Location , MoveData , MovePathData , MovePathIndex , PathMap } ;
21
+ use super :: gather_moves:: { Location , MoveData , MovePathData , MovePathIndex , MoveOutIndex , PathMap } ;
22
22
use super :: graphviz;
23
23
use bitslice:: BitSlice ; // adds set_bit/get_bit to &[usize] bitvector rep.
24
24
@@ -35,15 +35,31 @@ impl<'b, 'a: 'b, 'tcx: 'a> Dataflow for MirBorrowckCtxt<'b, 'a, 'tcx> {
35
35
}
36
36
}
37
37
38
- struct PropagationContext < ' c , ' b : ' c , ' a : ' b , ' tcx : ' a > {
38
+ struct PropagationContext < ' c , ' b : ' c , ' a : ' b , ' tcx : ' a , OnReturn >
39
+ where OnReturn : Fn ( & MoveData , & mut [ usize ] , & repr:: Lvalue )
40
+ {
39
41
mbcx : & ' c mut MirBorrowckCtxt < ' b , ' a , ' tcx > ,
40
42
changed : bool ,
43
+ on_return : OnReturn
41
44
}
42
45
43
46
impl < ' b , ' a : ' b , ' tcx : ' a > MirBorrowckCtxt < ' b , ' a , ' tcx > {
44
47
fn propagate ( & mut self ) {
45
48
let mut temp = vec ! [ 0 ; self . flow_state. sets. words_per_block] ;
46
- let mut propcx = PropagationContext { mbcx : & mut * self , changed : true , } ;
49
+ let mut propcx = PropagationContext {
50
+ mbcx : & mut * self ,
51
+ changed : true ,
52
+ on_return : |move_data, in_out, dest_lval| {
53
+ let move_path_index = move_data. rev_lookup . find ( dest_lval) ;
54
+ on_all_children_bits ( in_out,
55
+ & move_data. path_map ,
56
+ & move_data. move_paths ,
57
+ move_path_index,
58
+ & |in_out, mpi| {
59
+ in_out. clear_bit ( mpi. idx ( ) . unwrap ( ) ) ;
60
+ } ) ;
61
+ } ,
62
+ } ;
47
63
while propcx. changed {
48
64
propcx. changed = false ;
49
65
propcx. reset ( & mut temp) ;
@@ -79,19 +95,22 @@ impl<'b, 'a: 'b, 'tcx: 'a> MirBorrowckCtxt<'b, 'a, 'tcx> {
79
95
// Every path deinitialized by a *particular move*
80
96
// has corresponding bit, "gen'ed" (i.e. set)
81
97
// here, in dataflow vector
82
- let retval = sets. gen_set . set_bit ( move_index. idx ( ) . unwrap ( ) ) ;
83
- assert ! ( retval) ;
98
+ zero_to_one ( & mut sets. gen_set , * move_index) ;
84
99
}
85
100
match stmt. kind {
86
101
repr:: StatementKind :: Assign ( ref lvalue, _) => {
87
102
// assigning into this `lvalue` kills all
88
103
// MoveOuts from it, and *also* all MoveOuts
89
104
// for children and associated fragment sets.
90
105
let move_path_index = rev_lookup. find ( lvalue) ;
91
- set_children_kill_bits ( sets. kill_set ,
92
- move_path_index,
93
- path_map,
94
- move_paths) ;
106
+
107
+ on_all_children_bits ( sets. kill_set ,
108
+ path_map,
109
+ move_paths,
110
+ move_path_index,
111
+ & |kill_set, mpi| {
112
+ kill_set. set_bit ( mpi. idx ( ) . unwrap ( ) ) ;
113
+ } ) ;
95
114
}
96
115
}
97
116
}
@@ -100,79 +119,47 @@ impl<'b, 'a: 'b, 'tcx: 'a> MirBorrowckCtxt<'b, 'a, 'tcx> {
100
119
debug ! ( "terminator {:?} at loc {:?} moves out of move_indexes {:?}" ,
101
120
terminator, loc, & loc_map[ loc] ) ;
102
121
for move_index in & loc_map[ loc] {
103
- let retval = sets. gen_set . set_bit ( move_index. idx ( ) . unwrap ( ) ) ;
104
- assert ! ( retval) ;
122
+ zero_to_one ( & mut sets. gen_set , * move_index) ;
105
123
}
124
+ }
106
125
107
- // Note: while below as originally authored could be
108
- // written as an `if let`, it is more future-proof (to MIR
109
- // changes) to use an explicit `match` here.
110
- match * terminator {
111
- None => { }
112
- Some ( repr:: Terminator :: Goto { target : _ } ) => { }
113
- Some ( repr:: Terminator :: If { cond : _, targets : _ } ) => { }
114
- Some ( repr:: Terminator :: Switch { discr : _, adt_def : _, targets : _ } ) => { }
115
- Some ( repr:: Terminator :: SwitchInt { discr : _, switch_ty : _, values : _, targets : _ } ) => { }
116
- Some ( repr:: Terminator :: Resume ) => { }
117
- Some ( repr:: Terminator :: Return ) => { }
118
- Some ( repr:: Terminator :: Drop { value : _, target : _, unwind : _ } ) => {
119
- // either kind of Drop completely invalidates the
120
- // state of the referenced memory, effectively
121
- // acting like a MoveOut. Such gen-set additions
122
- // were added by the loop above over the loc_map.
123
- }
124
- Some ( repr:: Terminator :: Call { func : _, args : _, cleanup : _,
125
- ref destination } ) => {
126
- // Note: a followup commit refines this to reflect
127
- // that the destination will be initialized if the
128
- // call succeeds (thus killling any MoveOuts for
129
- // that destination).
130
- //
131
- // That is, this code just does the kills
132
- // unconditionally (which I believe this matches
133
- // the behavior of the old borrowck dataflow
134
- // analysis), but this code also is also removed
135
- // and replaced with something flow-dependent in a
136
- // followup commit.
137
-
138
- if let Some ( ( ref destination, _) ) = * destination {
139
- let move_path_index = rev_lookup. find ( destination) ;
140
- set_children_kill_bits ( sets. kill_set ,
141
- move_path_index,
142
- path_map,
143
- move_paths) ;
144
- }
145
- }
146
- }
126
+ fn zero_to_one ( gen_set : & mut [ usize ] , move_index : MoveOutIndex ) {
127
+ let retval = gen_set. set_bit ( move_index. idx ( ) . unwrap ( ) ) ;
128
+ assert ! ( retval) ;
147
129
}
130
+ }
131
+ }
148
132
149
- fn set_children_kill_bits ( kill_set : & mut [ usize ] ,
150
- move_path_index : MovePathIndex ,
151
- path_map : & PathMap ,
152
- move_paths : & MovePathData ) {
153
- assert ! ( move_path_index. idx( ) . is_some( ) ) ;
133
+ fn on_all_children_bits < Each > ( set : & mut [ usize ] ,
134
+ path_map : & PathMap ,
135
+ move_paths : & MovePathData ,
136
+ move_path_index : MovePathIndex ,
137
+ each_child : & Each )
138
+ where Each : Fn ( & mut [ usize ] , MoveOutIndex )
139
+ {
140
+ assert ! ( move_path_index. idx( ) . is_some( ) ) ;
154
141
155
- // 1. set kill bits for all moves that directly
156
- // influence path for `move_path_index`
157
- for move_index in & path_map[ move_path_index] {
158
- kill_set . set_bit ( move_index. idx ( ) . unwrap ( ) ) ;
159
- }
142
+ // 1. invoke `each_child` callback for all moves that directly
143
+ // influence path for `move_path_index`
144
+ for move_index in & path_map[ move_path_index] {
145
+ each_child ( set , * move_index) ;
146
+ }
160
147
161
- // 2. for each child of the path (that is named in this
162
- // function), recur.
163
- //
164
- // (Unnamed children are irrelevant to dataflow; by
165
- // definition they have no associated moves.)
166
- let mut child_index = move_paths[ move_path_index] . first_child ;
167
- while let Some ( _) = child_index. idx ( ) {
168
- set_children_kill_bits ( kill_set, child_index, path_map, move_paths) ;
169
- child_index = move_paths[ child_index] . next_sibling ;
170
- }
171
- }
148
+ // 2. for each child of the path (that is named in this
149
+ // function), recur.
150
+ //
151
+ // (Unnamed children are irrelevant to dataflow; by
152
+ // definition they have no associated moves.)
153
+ let mut child_index = move_paths[ move_path_index] . first_child ;
154
+ while let Some ( _) = child_index. idx ( ) {
155
+ on_all_children_bits ( set, path_map, move_paths, child_index, each_child) ;
156
+ child_index = move_paths[ child_index] . next_sibling ;
172
157
}
173
158
}
174
159
175
- impl < ' c , ' b : ' c , ' a : ' b , ' tcx : ' a > PropagationContext < ' c , ' b , ' a , ' tcx > {
160
+ impl < ' c , ' b : ' c , ' a : ' b , ' tcx : ' a , OnReturn > PropagationContext < ' c , ' b , ' a , ' tcx , OnReturn >
161
+ where OnReturn : Fn ( & MoveData , & mut [ usize ] , & repr:: Lvalue )
162
+ {
176
163
fn reset ( & mut self , bits : & mut [ usize ] ) {
177
164
let e = if self . mbcx . flow_state . operator . initial_value ( ) { usize:: MAX } else { 0 } ;
178
165
for b in bits {
@@ -190,7 +177,10 @@ impl<'c, 'b: 'c, 'a: 'b, 'tcx: 'a> PropagationContext<'c, 'b, 'a, 'tcx> {
190
177
bitwise ( in_out, sets. gen_set , & Union ) ;
191
178
bitwise ( in_out, sets. kill_set , & Subtract ) ;
192
179
}
193
- flow_state. propagate_bits_into_graph_successors_of ( in_out, & mut self . changed , bb) ;
180
+ flow_state. propagate_bits_into_graph_successors_of ( in_out,
181
+ & mut self . changed ,
182
+ bb,
183
+ & self . on_return ) ;
194
184
}
195
185
}
196
186
}
@@ -405,10 +395,23 @@ impl<D: BitDenotation> DataflowState<D> {
405
395
}
406
396
407
397
impl < D : BitDenotation > DataflowState < D > {
408
- fn propagate_bits_into_graph_successors_of ( & mut self ,
409
- in_out : & mut [ usize ] ,
410
- changed : & mut bool ,
411
- bb : & repr:: BasicBlockData ) {
398
+ /// Propagates the bits of `in_out` into all the successors of `bb`,
399
+ /// using bitwise operator denoted by `self.operator`.
400
+ ///
401
+ /// For most blocks, this is entirely uniform. However, for blocks
402
+ /// that end with a call terminator, the effect of the call on the
403
+ /// dataflow state may depend on whether the call returned
404
+ /// successfully or unwound. To reflect this, the `on_return`
405
+ /// callback mutates `in_out` when propagating `in_out` via a call
406
+ /// terminator; such mutation is performed *last*, to ensure its
407
+ /// side-effects do not leak elsewhere (e.g. into unwind target).
408
+ fn propagate_bits_into_graph_successors_of < OnReturn > (
409
+ & mut self ,
410
+ in_out : & mut [ usize ] ,
411
+ changed : & mut bool ,
412
+ bb : & repr:: BasicBlockData ,
413
+ on_return : OnReturn ) where OnReturn : Fn ( & D , & mut [ usize ] , & repr:: Lvalue )
414
+ {
412
415
let term = if let Some ( ref term) = bb. terminator { term } else { return } ;
413
416
match * term {
414
417
repr:: Terminator :: Return |
@@ -435,15 +438,18 @@ impl<D: BitDenotation> DataflowState<D> {
435
438
if let Some ( ref unwind) = * cleanup {
436
439
self . propagate_bits_into_entry_set_for ( in_out, changed, unwind) ;
437
440
}
438
- if let Some ( ( _, ref destination) ) = * destination {
439
- self . propagate_bits_into_entry_set_for ( in_out, changed, destination) ;
441
+ if let Some ( ( ref dest_lval, ref dest_bb) ) = * destination {
442
+ // N.B.: This must be done *last*, after all other
443
+ // propagation, as documented in comment above.
444
+ on_return ( & self . operator , in_out, dest_lval) ;
445
+ self . propagate_bits_into_entry_set_for ( in_out, changed, dest_bb) ;
440
446
}
441
447
}
442
448
}
443
449
}
444
450
445
451
fn propagate_bits_into_entry_set_for ( & mut self ,
446
- in_out : & mut [ usize ] ,
452
+ in_out : & [ usize ] ,
447
453
changed : & mut bool ,
448
454
bb : & repr:: BasicBlock ) {
449
455
let entry_set = self . sets . for_block ( bb. index ( ) ) . on_entry ;
0 commit comments