Skip to content

Commit bbcace5

Browse files
committed
Use precomputed DFS of borrows that out of scope at a location.
1 parent 3fd82a5 commit bbcace5

File tree

1 file changed

+116
-14
lines changed

1 file changed

+116
-14
lines changed

src/librustc_mir/dataflow/impls/borrows.rs

Lines changed: 116 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@ use rustc;
1515
use rustc::hir;
1616
use rustc::hir::def_id::DefId;
1717
use rustc::middle::region;
18-
use rustc::mir::{self, Location, Place, Mir};
18+
use rustc::mir::{self, Location, Place, Mir, TerminatorKind};
1919
use rustc::ty::TyCtxt;
20-
use rustc::ty::RegionKind;
20+
use rustc::ty::{RegionKind, RegionVid};
2121
use rustc::ty::RegionKind::ReScope;
2222

2323
use rustc_data_structures::bitslice::BitwiseOperator;
24+
use rustc_data_structures::fx::FxHashMap;
2425
use rustc_data_structures::indexed_set::IdxSet;
2526
use rustc_data_structures::indexed_vec::IndexVec;
2627
use rustc_data_structures::sync::Lrc;
@@ -46,9 +47,103 @@ pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
4647
root_scope: Option<region::Scope>,
4748

4849
borrow_set: Rc<BorrowSet<'tcx>>,
50+
borrows_out_of_scope_at_location: FxHashMap<Location, Vec<BorrowIndex>>,
4951

5052
/// NLL region inference context with which NLL queries should be resolved
51-
nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
53+
_nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
54+
}
55+
56+
fn precompute_borrows_out_of_scope<'a, 'tcx>(
57+
mir: &'a Mir<'tcx>,
58+
regioncx: &Rc<RegionInferenceContext<'tcx>>,
59+
borrows_out_of_scope_at_location: &mut FxHashMap<Location, Vec<BorrowIndex>>,
60+
borrow_index: BorrowIndex,
61+
borrow_region: RegionVid,
62+
location: Location
63+
) {
64+
// Start by dealing with the current location.
65+
if !regioncx.region_contains_point(borrow_region, location) {
66+
borrows_out_of_scope_at_location
67+
.entry(location.clone())
68+
.and_modify(|m| m.push(borrow_index))
69+
.or_insert(vec![ borrow_index ]);
70+
}
71+
72+
let bb_data = &mir[location.block];
73+
// If we are on the last statement, then check the terminator
74+
// to determine which location to proceed to.
75+
if location.statement_index == bb_data.statements.len() - 1 {
76+
if let Some(ref terminator) = bb_data.terminator {
77+
match terminator.kind {
78+
TerminatorKind::Goto { target } |
79+
TerminatorKind::FalseEdges { real_target: target, .. } |
80+
TerminatorKind::FalseUnwind { real_target: target, .. } => {
81+
precompute_borrows_out_of_scope(
82+
mir, regioncx, borrows_out_of_scope_at_location,
83+
borrow_index, borrow_region, target.start_location()
84+
);
85+
},
86+
TerminatorKind::SwitchInt { ref targets, .. } => {
87+
for block in targets {
88+
precompute_borrows_out_of_scope(
89+
mir, regioncx, borrows_out_of_scope_at_location,
90+
borrow_index, borrow_region, block.start_location()
91+
);
92+
}
93+
},
94+
TerminatorKind::Drop { target, unwind, .. } |
95+
TerminatorKind::DropAndReplace { target, unwind, .. } => {
96+
precompute_borrows_out_of_scope(
97+
mir, regioncx, borrows_out_of_scope_at_location,
98+
borrow_index, borrow_region, target.start_location()
99+
);
100+
101+
if let Some(unwind_block) = unwind {
102+
precompute_borrows_out_of_scope(
103+
mir, regioncx, borrows_out_of_scope_at_location,
104+
borrow_index, borrow_region, unwind_block.start_location()
105+
);
106+
}
107+
},
108+
TerminatorKind::Call { ref destination, cleanup, .. } => {
109+
if let Some((_, block)) = destination {
110+
precompute_borrows_out_of_scope(
111+
mir, regioncx, borrows_out_of_scope_at_location,
112+
borrow_index, borrow_region, block.start_location()
113+
);
114+
}
115+
116+
if let Some(block) = cleanup {
117+
precompute_borrows_out_of_scope(
118+
mir, regioncx, borrows_out_of_scope_at_location,
119+
borrow_index, borrow_region, block.start_location()
120+
);
121+
}
122+
},
123+
TerminatorKind::Assert { target, cleanup, .. } |
124+
TerminatorKind::Yield { resume: target, drop: cleanup, .. } => {
125+
precompute_borrows_out_of_scope(
126+
mir, regioncx, borrows_out_of_scope_at_location,
127+
borrow_index, borrow_region, target.start_location()
128+
);
129+
130+
if let Some(block) = cleanup {
131+
precompute_borrows_out_of_scope(
132+
mir, regioncx, borrows_out_of_scope_at_location,
133+
borrow_index, borrow_region, block.start_location()
134+
);
135+
}
136+
},
137+
_ => {},
138+
};
139+
};
140+
// If we're not on the last statement, then go to the next
141+
// statement in this block.
142+
} else {
143+
precompute_borrows_out_of_scope(mir, regioncx, borrows_out_of_scope_at_location,
144+
borrow_index, borrow_region,
145+
location.successor_within_block());
146+
}
52147
}
53148

54149
impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
@@ -65,18 +160,28 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
65160
region::Scope::CallSite(tcx.hir.body(body_id).value.hir_id.local_id)
66161
});
67162

163+
let mut borrows_out_of_scope_at_location = FxHashMap();
164+
for (borrow_index, borrow_data) in borrow_set.borrows.iter_enumerated() {
165+
let borrow_region = borrow_data.region.to_region_vid();
166+
let location = borrow_set.borrows[borrow_index].reserve_location;
167+
168+
precompute_borrows_out_of_scope(mir, &nonlexical_regioncx,
169+
&mut borrows_out_of_scope_at_location,
170+
borrow_index, borrow_region, location);
171+
}
172+
68173
Borrows {
69174
tcx: tcx,
70175
mir: mir,
71176
borrow_set: borrow_set.clone(),
177+
borrows_out_of_scope_at_location,
72178
scope_tree,
73179
root_scope,
74-
nonlexical_regioncx,
180+
_nonlexical_regioncx: nonlexical_regioncx,
75181
}
76182
}
77183

78184
crate fn borrows(&self) -> &IndexVec<BorrowIndex, BorrowData<'tcx>> { &self.borrow_set.borrows }
79-
80185
pub fn scope_tree(&self) -> &Lrc<region::ScopeTree> { &self.scope_tree }
81186

82187
pub fn location(&self, idx: BorrowIndex) -> &Location {
@@ -89,23 +194,20 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
89194
fn kill_loans_out_of_scope_at_location(&self,
90195
sets: &mut BlockSets<BorrowIndex>,
91196
location: Location) {
92-
let regioncx = &self.nonlexical_regioncx;
93-
94197
// NOTE: The state associated with a given `location`
95-
// reflects the dataflow on entry to the statement. If it
96-
// does not contain `borrow_region`, then then that means
97-
// that the statement at `location` kills the borrow.
198+
// reflects the dataflow on entry to the statement.
199+
// Iterate over each of the borrows that we've precomputed
200+
// to have went out of scope at this location and kill them.
98201
//
99202
// We are careful always to call this function *before* we
100203
// set up the gen-bits for the statement or
101204
// termanator. That way, if the effect of the statement or
102205
// terminator *does* introduce a new loan of the same
103206
// region, then setting that gen-bit will override any
104207
// potential kill introduced here.
105-
for (borrow_index, borrow_data) in self.borrow_set.borrows.iter_enumerated() {
106-
let borrow_region = borrow_data.region.to_region_vid();
107-
if !regioncx.region_contains_point(borrow_region, location) {
108-
sets.kill(&borrow_index);
208+
if let Some(indices) = self.borrows_out_of_scope_at_location.get(&location) {
209+
for index in indices {
210+
sets.kill(&index);
109211
}
110212
}
111213
}

0 commit comments

Comments
 (0)