29
29
//!
30
30
//! The `Node`s in the dependency graph include data values of type `NodeKind`. `NodeKind` has
31
31
//! three variants: `Local`, `Borrow` and `LocalWithRefs`.
32
- //! * `NodeKind::Local` is used for `Local`s that are borrowed somewhere (`_4` in our example)
32
+ //! * `NodeKind::Local` is used for `Local`s that are borrowed somewhere (`_4` in our example), but aren't
33
+ //! themselves references or pointers.
33
34
//! * `NodeKind::Borrow` is used for `Local`s that correspond to borrows (`_5` in our example) and
34
35
//! also `Local`s that result from re-borrows.
35
36
//! * `NodeKind::LocalWithRefs` is used for `Local`s that aren't themselves borrows, but contain
36
- //! borrowed `Local`s. We want to keep these `Local`s live and also any of the references/pointers
37
- //! they might contain . Let's look at an example:
37
+ //! `Local`s that correspond to references, pointers or other `Local`s with `Node`s of kind
38
+ //! `NodeKind::LocalWithRef`s . Let's look at an example:
38
39
//!
39
40
//! ```ignore(rust)
40
41
//! _4 = Bar {}
47
48
//! In this example `_6` would be given `NodeKind::LocalWithRefs` and our graph would look
48
49
//! as follows:
49
50
//!
50
- //! `_7 (NodeKind::Borrow) -> `_6` (NodeKind::LocalWithRefs) -> `_5` (NodeKind::Borrow) -> `_4` (NodeKind::Local)
51
- //!
52
- //! In addition to keeping `_6` alive over the range of `_7` we also keep `_4` alive (leaf node).
51
+ //! `_7` (NodeKind::Borrow) -> `_6` (NodeKind::LocalWithRefs) -> `_5` (NodeKind::Borrow) -> `_4` (NodeKind::Local)
52
+ //!
53
+ //! On the one hand we need to treat `Local`s with `Node`s of kind `NodeKind::LocalWithRefs` similarly
54
+ //! to how we treat `Local`s with `Node`s of kind `NodeKind::Local`, in the sense that if they are
55
+ //! borrowed we want to keep them live over the live range of the borrow. But on the other hand we
56
+ //! want to also treat them like `Local`s with `Node`s of kind `NodeKind::Borrow` as they ultimately
57
+ //! could also contain references or pointers that refer to other `Local`s. So we want a
58
+ //! path in the graph from a `NodeKind::LocalWithRef`s node to the `NodeKind::Local` nodes, whose borrows
59
+ //! they might contain.
53
60
//!
54
61
//! Additionally `NodeKind::LocalWithRefs` is also used for raw pointers that are cast to
55
62
//! `usize`:
66
73
//! * `_5` (Borrow) -> `_4` (Local)
67
74
//! * `_6` (LocalWithRefs) -> `_5` (Borrow)
68
75
//! * `_7` (LocalWithRefs) -> `_6` (LocalWithRefs)
69
- //! * `_8` (LocalWithRefs) -> `_7` (LocalWithRefs) (FIXME this one is currently not being done)
76
+ //! * `_8` (LocalWithRefs) -> `_7` (LocalWithRefs) (FIXME this one is currently not being done, but unsafe )
70
77
//!
71
78
//! We also have to be careful when dealing with `Terminator`s. Whenever we pass references,
72
- //! pointers or `Local`s with `NodeKind::LocalWithRefs` (FIXME currently not done) to
73
- //! a `TerminatorKind::Call` or `TerminatorKind:: Yield` and the destination `Place` or resume place, resp.,
74
- //! contains references/ pointers or generic parameters we have to be careful and treat the
75
- //! `Local`s corresponding to the `Place`s as `NodeKind::LocalWithRef`s .
79
+ //! pointers or `Local`s with `NodeKind::LocalWithRefs` to a `TerminatorKind::Call` or
80
+ //! `TerminatorKind::Yield`, the destination `Place` or resume place, resp., might contain
81
+ //! these references, pointers or `NodeKind::LocalWithRefs` `Local`s, hence we have to be conservative
82
+ //! and keep the `destination` `Local` and `resume_arg` `Local` live .
76
83
//!
77
84
//! 2. Liveness analysis for borrows
78
85
//!
86
93
//! 3. _5 = Ref(_3)
87
94
//! 4. _6 = Ref(_4)
88
95
//! 5. _7 = Aggregate(..)(move _5)
89
- //! 6. _8 = Call(..)(move _6) (assume _8 contains no refs/ptrs or generic params)
96
+ //! 6. _8 = Call(..)(move _6)
90
97
//! 7. _9 = (_8.0)
91
- //! 8. (_7.0) = _9
98
+ //! 8. _10 = const 5
99
+ //! 9. (_7.0) = move _10
92
100
//! ```
93
101
//!
94
102
//! * `_5` is live from stmt 3 to stmt 5
95
103
//! * `_6` is live from stmt 4 to stmt 6
96
- //! * `_7` is a `Local` of kind `LocalWithRef` so needs to be taken into account in the
97
- //! analyis. It's live from stmt 5 to stmt 8
104
+ //! * `_7` is a `Local` of kind `LocalWithRefs` so needs to be taken into account in the
105
+ //! analyis. It's live from stmt 5 to stmt 9
106
+ //! * `_8` is a `Local` of kind `LocalWithRefs`. It's live from 6. to 7.
107
+ //! * `_9` is a `Local` of kind `LocalWithRefs` (FIXME this is currently not done, see FIXME above),
108
+ //! it's live at 7.
98
109
//!
99
110
//! 3. Determining which `Local`s are borrowed
100
111
//!
103
114
//! `_5` (Borrow) -> `_3` (Local)
104
115
//! `_6` (Borrow) -> `_4` (Local)
105
116
//! `_7` (LocalWithRef) -> `_5` (Borrow)
106
- //! `_7` (LocalWithRef) -> `_9` (Local)
117
+ //! `_8` (LocalWithRef) -> `_6` (Borrow)
118
+ //! `_9` (LocalWithRef) -> `_8` (LocalWithRef) (FIXME currently not done)
119
+ //! `_7` (LocalWithRef) -> `_10` (Local)
107
120
//!
108
121
//! So at each of those statements we have the following `Local`s that are live due to borrows:
109
122
//!
112
125
//! 3. {_3}
113
126
//! 4. {_3, _4}
114
127
//! 5. {_3, _4, _7}
115
- //! 6. {_3, _4, _7}
116
- //! 7. {_3, _7 }
128
+ //! 6. {_3, _4, _7, _8 }
129
+ //! 7. {_3, _4, _7, _8 }
117
130
//! 8. {_3, _7}
131
+ //! 9. {_3, _7}
118
132
//!
119
133
120
134
use super :: * ;
@@ -134,16 +148,16 @@ use either::Either;
134
148
135
149
#[ derive( Copy , Clone , Debug ) ]
136
150
enum NodeKind {
137
- // An node corresponding to the place of the borrowed place (`_4` in this case) in
138
- // an assignment like `_3 = Ref(_, _, _4)`.
151
+ // An node corresponding to the place on the lhs of an assignment like `_3 = Ref(_, _, _4)`.
139
152
Borrow ( Local ) ,
140
153
141
154
// Nodes corresponding to the place on the lhs of a statement like
142
155
// `_2 = Aggregate(Adt(..), _, _, _, _), [move _3, move _6])`,
143
156
// where _3 and _6 are places corresponding to references or raw pointers.
144
157
LocalWithRefs ( Local ) ,
145
158
146
- // Nodes corresponding to the place on the lhs of an assignment like `_2 = Ref(..)`.
159
+ // Nodes corresponding to the borrowed place of an assignment like `_2 = Ref(_, _, borrowed_place)`,
160
+ // if `borrowed_place` is a non-ref or non-ptr value.
147
161
Local ( Local ) ,
148
162
}
149
163
@@ -159,11 +173,25 @@ impl NodeKind {
159
173
160
174
/// Used to build a dependency graph between borrows/pointers and the `Local`s that
161
175
/// they reference.
162
- /// We add edges to the graph in two kinds of situations:
163
- /// * direct assignment of reference or raw pointer (e.g. `_4 = Ref(..)` or `_4 = AddressOf`)
176
+ /// We add edges to the graph in following situations:
177
+ /// * direct assignment of reference or raw pointer (e.g. `_4 = Ref(_, _ , borrowed_place)` or
178
+ /// `_4 = AddressOf(_, borrowed_place)`). For this case we create a `Node` of kind
179
+ /// `NodeKind::Borrow` for the `Local` being assigned to and an edge to either an existing
180
+ /// `Node` or if none exists yet to a new `Node` of type `NodeKind::Local` corresponding to
181
+ /// a non-ref/ptr `Local`.
164
182
/// * assignments to non-reference or non-pointer `Local`s, which themselves might contain
165
183
/// references or pointers (e.g. `_2 = Aggregate(Adt(..), _, _, _, _), [move _3, move _6])`,
166
- /// where `_3` and `_6` are places corresponding to references or raw pointers).
184
+ /// where `_3` and `_6` are places corresponding to references or raw pointers). In this case
185
+ /// we create a `Node` of kind `NodeKind::LocalWithRefs` for `_2`. Since `_3` and `_6` are
186
+ /// `Local`s that correspond to references, pointers or composite types that might contain
187
+ /// references or pointers (`NodeKind::LocalWithRefs`), there already exist `Node`s for these
188
+ /// `Local`s. We then add edges from the `Node` for `_2` to both the `Node` for `_3` and the
189
+ /// `Node` for `_6`.
190
+ /// * `destination` places for `TerminatorKind::Call` and the `resume_arg` places for
191
+ /// `TerminatorKind::Yield` if we pass in any references, pointers or composite values that
192
+ /// might correspond to references, pointers or exposed pointers (`NodeKind::LocalWithRef`s).
193
+ /// The rationale for this is that the return values of both of these terminators might themselves
194
+ /// contain any of the references or pointers passed as arguments.
167
195
struct BorrowDependencies < ' a , ' tcx > {
168
196
tcx : TyCtxt < ' tcx > ,
169
197
local_decls : & ' a LocalDecls < ' tcx > ,
@@ -396,7 +424,13 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowDependencies<'a, 'tcx> {
396
424
}
397
425
398
426
pub struct BorrowedLocalsResults < ' mir , ' tcx > {
427
+ // the results of the liveness analysis of `LiveBorrows`
399
428
borrows_analysis_results : Results < ' tcx , LiveBorrows < ' mir , ' tcx > > ,
429
+
430
+ // Maps each `Local` that corresponds to a reference, pointer or a node of kind
431
+ // `NodeKind::LocalWithRefs` (i.e. `Local`s which either correspond to refs, pointers or
432
+ // exposed pointers or a composite value that might include refs, pointers or exposed pointers)
433
+ // to the set of `Local`s that are borrowed through those references, pointers or composite values.
400
434
borrowed_local_to_locals_to_keep_alive : FxHashMap < Local , Vec < Local > > ,
401
435
}
402
436
@@ -473,6 +507,8 @@ where
473
507
}
474
508
}
475
509
510
+ /// The function gets the results of the borrowed locals analysis in this module. See the module
511
+ /// doc-comment for information on what exactly this analysis does.
476
512
#[ instrument( skip( tcx) , level = "debug" ) ]
477
513
pub fn get_borrowed_locals_results < ' mir , ' tcx > (
478
514
body : & ' mir Body < ' tcx > ,
@@ -517,9 +553,19 @@ pub fn get_borrowed_locals_results<'mir, 'tcx>(
517
553
BorrowedLocalsResults :: new ( results)
518
554
}
519
555
556
+ /// The `ResultsCursor` equivalent for the borrowed locals analysis. Since this analysis doesn't
557
+ /// require convergence, we expose the set of borrowed `Local`s for a `Location` directly via
558
+ /// the `get` method without the need for any prior 'seek' calls.
520
559
pub struct BorrowedLocalsResultsCursor < ' a , ' mir , ' tcx > {
521
560
body : & ' mir Body < ' tcx > ,
561
+
562
+ // The cursor for the liveness analysis performed by `LiveBorrows`
522
563
borrows_analysis_cursor : ResultsRefCursor < ' a , ' mir , ' tcx , LiveBorrows < ' mir , ' tcx > > ,
564
+
565
+ // Maps each `Local` corresponding to a reference or pointer to the set of `Local`s
566
+ // that are borrowed through the ref/ptr. Additionally contains entries for `Local`s
567
+ // corresponding to `NodeKind::LocalWithRefs` since they might contain refs, ptrs or
568
+ // exposed pointers and need to be treated equivalently to refs/ptrs
523
569
borrowed_local_to_locals_to_keep_alive : & ' a FxHashMap < Local , Vec < Local > > ,
524
570
}
525
571
@@ -586,7 +632,9 @@ impl<'a, 'mir, 'tcx> BorrowedLocalsResultsCursor<'a, 'mir, 'tcx> {
586
632
}
587
633
}
588
634
589
- /// Performs a liveness analysis for borrows and raw pointers.
635
+ /// Performs a liveness analysis for borrows and raw pointers. This analysis also tracks `Local`s
636
+ /// corresponding to `Node`s of kind `NodeKind::LocalWithRefs`, as these could potentially refer to
637
+ /// or include references, pointers or exposed pointers.
590
638
pub struct LiveBorrows < ' mir , ' tcx > {
591
639
body : & ' mir Body < ' tcx > ,
592
640
tcx : TyCtxt < ' tcx > ,
@@ -662,7 +710,7 @@ impl<'a, 'tcx> GenKillAnalysis<'tcx> for LiveBorrows<'a, 'tcx> {
662
710
}
663
711
}
664
712
665
- /// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals `.
713
+ /// A `Visitor` that defines the transfer function for `LiveBorrows `.
666
714
struct TransferFunction < ' a , ' b , ' c , ' tcx , T > {
667
715
body : & ' a Body < ' tcx > ,
668
716
tcx : TyCtxt < ' tcx > ,
0 commit comments