Skip to content

Commit 87bacf2

Browse files
committed
Auto merge of #81132 - bugadani:map-prealloc, r=matthewjasper
Borrowck: refactor visited map to a bitset This PR refactors `Borrows` and the `precompute_borrows_out_of_scope` function so that this initial phase has a much reduced memory pressure. This is achieved by reducing what is stored on the heap, and also reusing heap memory as much as possible.
2 parents 097bc6a + 5271c62 commit 87bacf2

File tree

3 files changed

+96
-93
lines changed

3 files changed

+96
-93
lines changed

Cargo.lock

+1-1
Original file line numberDiff line numberDiff line change
@@ -5395,7 +5395,7 @@ dependencies = [
53955395
"chrono",
53965396
"lazy_static",
53975397
"matchers",
5398-
"parking_lot 0.11.0",
5398+
"parking_lot 0.9.0",
53995399
"regex",
54005400
"serde",
54015401
"serde_json",

compiler/rustc_mir/src/borrow_check/mod.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ fn do_mir_borrowck<'a, 'tcx>(
243243

244244
let regioncx = Rc::new(regioncx);
245245

246-
let flow_borrows = Borrows::new(tcx, &body, regioncx.clone(), &borrow_set)
246+
let flow_borrows = Borrows::new(tcx, &body, &regioncx, &borrow_set)
247247
.into_engine(tcx, &body)
248248
.pass_name("borrowck")
249249
.iterate_to_fixpoint();
@@ -287,7 +287,7 @@ fn do_mir_borrowck<'a, 'tcx>(
287287
regioncx: regioncx.clone(),
288288
used_mut: Default::default(),
289289
used_mut_upvars: SmallVec::new(),
290-
borrow_set: borrow_set.clone(),
290+
borrow_set: Rc::clone(&borrow_set),
291291
dominators,
292292
upvars: Vec::new(),
293293
local_names: IndexVec::from_elem(None, &promoted_body.local_decls),
@@ -317,10 +317,10 @@ fn do_mir_borrowck<'a, 'tcx>(
317317
move_error_reported: BTreeMap::new(),
318318
uninitialized_error_reported: Default::default(),
319319
errors_buffer,
320-
regioncx,
320+
regioncx: Rc::clone(&regioncx),
321321
used_mut: Default::default(),
322322
used_mut_upvars: SmallVec::new(),
323-
borrow_set,
323+
borrow_set: Rc::clone(&borrow_set),
324324
dominators,
325325
upvars,
326326
local_names,

compiler/rustc_mir/src/dataflow/impls/borrows.rs

+91-88
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use crate::borrow_check::{
1111
use crate::dataflow::{self, fmt::DebugWithContext, GenKill};
1212

1313
use std::fmt;
14-
use std::rc::Rc;
1514

1615
rustc_index::newtype_index! {
1716
pub struct BorrowIndex {
@@ -30,132 +29,136 @@ pub struct Borrows<'a, 'tcx> {
3029
tcx: TyCtxt<'tcx>,
3130
body: &'a Body<'tcx>,
3231

33-
borrow_set: Rc<BorrowSet<'tcx>>,
32+
borrow_set: &'a BorrowSet<'tcx>,
3433
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>>,
3834
}
3935

4036
struct StackEntry {
4137
bb: mir::BasicBlock,
4238
lo: usize,
4339
hi: usize,
44-
first_part_only: bool,
4540
}
4641

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(),
8858
}
59+
}
60+
}
8961

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 {
103116
bb: succ_bb,
104117
lo: 0,
105-
hi: *lo - 1,
106-
first_part_only: true,
118+
hi: first_lo - 1,
107119
});
120+
121+
// And update this entry with 0, to represent the
122+
// whole BB being processed.
123+
first_lo = 0;
108124
}
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 {
114126
// succ_bb hasn't been seen before. Add it to
115127
// `stack` for processing.
116-
stack.push(StackEntry {
128+
self.visit_stack.push(StackEntry {
117129
bb: succ_bb,
118130
lo: 0,
119-
hi: body[succ_bb].statements.len(),
120-
first_part_only: false,
131+
hi: self.body[succ_bb].statements.len(),
121132
});
122-
// Insert 0 for this BB, to represent the whole BB
123-
// being processed.
124-
0
125-
});
133+
}
134+
}
126135
}
127136
}
137+
138+
self.visited.clear();
128139
}
129140
}
130141

131142
impl<'a, 'tcx> Borrows<'a, 'tcx> {
132143
crate fn new(
133144
tcx: TyCtxt<'tcx>,
134145
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>,
137148
) -> Self {
138-
let mut borrows_out_of_scope_at_location = FxHashMap::default();
149+
let mut prec = OutOfScopePrecomputer::new(body, nonlexical_regioncx);
139150
for (borrow_index, borrow_data) in borrow_set.iter_enumerated() {
140151
let borrow_region = borrow_data.region.to_region_vid();
141152
let location = borrow_data.reserve_location;
142153

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);
151155
}
152156

153157
Borrows {
154158
tcx,
155159
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,
159162
}
160163
}
161164

0 commit comments

Comments
 (0)