Optimize Borrows
Reuse as much memory as possible, reduce number of allocations. Use BitSet instead of a HashMap, since only a single bit of information was used as the map's value.
This commit is contained in:
parent
5e91c4ecc0
commit
46f30455f4
2 changed files with 89 additions and 81 deletions
|
@ -259,7 +259,7 @@ fn do_mir_borrowck<'a, 'tcx>(
|
||||||
|
|
||||||
let regioncx = Rc::new(regioncx);
|
let regioncx = Rc::new(regioncx);
|
||||||
|
|
||||||
let flow_borrows = Borrows::new(tcx, &body, regioncx.clone(), &borrow_set)
|
let flow_borrows = Borrows::new(tcx, &body, regioncx.clone(), Rc::clone(borrow_set))
|
||||||
.into_engine(tcx, &body)
|
.into_engine(tcx, &body)
|
||||||
.pass_name("borrowck")
|
.pass_name("borrowck")
|
||||||
.iterate_to_fixpoint();
|
.iterate_to_fixpoint();
|
||||||
|
|
|
@ -41,17 +41,35 @@ struct StackEntry {
|
||||||
bb: mir::BasicBlock,
|
bb: mir::BasicBlock,
|
||||||
lo: usize,
|
lo: usize,
|
||||||
hi: usize,
|
hi: usize,
|
||||||
first_part_only: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn precompute_borrows_out_of_scope<'tcx>(
|
struct OutOfScopePrecomputer<'a, 'tcx> {
|
||||||
body: &Body<'tcx>,
|
visited: BitSet<mir::BasicBlock>,
|
||||||
regioncx: &Rc<RegionInferenceContext<'tcx>>,
|
visit_stack: Vec<StackEntry>,
|
||||||
borrows_out_of_scope_at_location: &mut FxHashMap<Location, Vec<BorrowIndex>>,
|
body: &'a Body<'tcx>,
|
||||||
|
regioncx: Rc<RegionInferenceContext<'tcx>>,
|
||||||
|
borrows_out_of_scope_at_location: FxHashMap<Location, Vec<BorrowIndex>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'tcx> OutOfScopePrecomputer<'a, 'tcx> {
|
||||||
|
fn new(body: &'a Body<'tcx>, regioncx: Rc<RegionInferenceContext<'tcx>>) -> Self {
|
||||||
|
OutOfScopePrecomputer {
|
||||||
|
visited: BitSet::new_empty(body.basic_blocks().len()),
|
||||||
|
visit_stack: vec![],
|
||||||
|
body,
|
||||||
|
regioncx,
|
||||||
|
borrows_out_of_scope_at_location: FxHashMap::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> OutOfScopePrecomputer<'_, 'tcx> {
|
||||||
|
fn precompute_borrows_out_of_scope(
|
||||||
|
&mut self,
|
||||||
borrow_index: BorrowIndex,
|
borrow_index: BorrowIndex,
|
||||||
borrow_region: RegionVid,
|
borrow_region: RegionVid,
|
||||||
location: Location,
|
location: Location,
|
||||||
) {
|
) {
|
||||||
// We visit one BB at a time. The complication is that we may start in the
|
// We visit one BB at a time. The complication is that we may start in the
|
||||||
// middle of the first BB visited (the one containing `location`), in which
|
// middle of the first BB visited (the one containing `location`), in which
|
||||||
// case we may have to later on process the first part of that BB if there
|
// case we may have to later on process the first part of that BB if there
|
||||||
|
@ -62,26 +80,27 @@ fn precompute_borrows_out_of_scope<'tcx>(
|
||||||
// `visited` once they are added to `stack`, before they are actually
|
// `visited` once they are added to `stack`, before they are actually
|
||||||
// processed, because this avoids the need to look them up again on
|
// processed, because this avoids the need to look them up again on
|
||||||
// completion.
|
// completion.
|
||||||
let mut visited = FxHashMap::default();
|
self.visited.insert(location.block);
|
||||||
visited.insert(location.block, location.statement_index);
|
|
||||||
|
|
||||||
let mut stack = vec![];
|
let mut first_lo = location.statement_index;
|
||||||
stack.push(StackEntry {
|
let first_hi = self.body[location.block].statements.len();
|
||||||
bb: location.block,
|
|
||||||
lo: location.statement_index,
|
|
||||||
hi: body[location.block].statements.len(),
|
|
||||||
first_part_only: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
while let Some(StackEntry { bb, lo, hi, first_part_only }) = stack.pop() {
|
self.visit_stack.push(StackEntry { bb: location.block, lo: first_lo, hi: first_hi });
|
||||||
let mut finished_early = first_part_only;
|
|
||||||
|
while let Some(StackEntry { bb, lo, hi }) = self.visit_stack.pop() {
|
||||||
|
// If we process the first part of the first basic block (i.e. we encounter that block
|
||||||
|
// for the second time), we no longer have to visit its successors again.
|
||||||
|
let mut finished_early = bb == location.block && hi != first_hi;
|
||||||
for i in lo..=hi {
|
for i in lo..=hi {
|
||||||
let location = Location { block: bb, statement_index: i };
|
let location = Location { block: bb, statement_index: i };
|
||||||
// If region does not contain a point at the location, then add to list and skip
|
// If region does not contain a point at the location, then add to list and skip
|
||||||
// successor locations.
|
// successor locations.
|
||||||
if !regioncx.region_contains(borrow_region, location) {
|
if !self.regioncx.region_contains(borrow_region, location) {
|
||||||
debug!("borrow {:?} gets killed at {:?}", borrow_index, location);
|
debug!("borrow {:?} gets killed at {:?}", borrow_index, location);
|
||||||
borrows_out_of_scope_at_location.entry(location).or_default().push(borrow_index);
|
self.borrows_out_of_scope_at_location
|
||||||
|
.entry(location)
|
||||||
|
.or_default()
|
||||||
|
.push(borrow_index);
|
||||||
finished_early = true;
|
finished_early = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -89,43 +108,39 @@ fn precompute_borrows_out_of_scope<'tcx>(
|
||||||
|
|
||||||
if !finished_early {
|
if !finished_early {
|
||||||
// Add successor BBs to the work list, if necessary.
|
// Add successor BBs to the work list, if necessary.
|
||||||
let bb_data = &body[bb];
|
let bb_data = &self.body[bb];
|
||||||
assert!(hi == bb_data.statements.len());
|
debug_assert!(hi == bb_data.statements.len());
|
||||||
for &succ_bb in bb_data.terminator().successors() {
|
for &succ_bb in bb_data.terminator().successors() {
|
||||||
visited
|
if self.visited.insert(succ_bb) == false {
|
||||||
.entry(succ_bb)
|
if succ_bb == location.block && first_lo > 0 {
|
||||||
.and_modify(|lo| {
|
|
||||||
// `succ_bb` has been seen before. If it wasn't
|
// `succ_bb` has been seen before. If it wasn't
|
||||||
// fully processed, add its first part to `stack`
|
// fully processed, add its first part to `stack`
|
||||||
// for processing.
|
// for processing.
|
||||||
if *lo > 0 {
|
self.visit_stack.push(StackEntry {
|
||||||
stack.push(StackEntry {
|
|
||||||
bb: succ_bb,
|
bb: succ_bb,
|
||||||
lo: 0,
|
lo: 0,
|
||||||
hi: *lo - 1,
|
hi: first_lo - 1,
|
||||||
first_part_only: true,
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
// And update this entry with 0, to represent the
|
// And update this entry with 0, to represent the
|
||||||
// whole BB being processed.
|
// whole BB being processed.
|
||||||
*lo = 0;
|
first_lo = 0;
|
||||||
})
|
}
|
||||||
.or_insert_with(|| {
|
} else {
|
||||||
// succ_bb hasn't been seen before. Add it to
|
// succ_bb hasn't been seen before. Add it to
|
||||||
// `stack` for processing.
|
// `stack` for processing.
|
||||||
stack.push(StackEntry {
|
self.visit_stack.push(StackEntry {
|
||||||
bb: succ_bb,
|
bb: succ_bb,
|
||||||
lo: 0,
|
lo: 0,
|
||||||
hi: body[succ_bb].statements.len(),
|
hi: self.body[succ_bb].statements.len(),
|
||||||
first_part_only: false,
|
|
||||||
});
|
|
||||||
// Insert 0 for this BB, to represent the whole BB
|
|
||||||
// being processed.
|
|
||||||
0
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.visited.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> Borrows<'a, 'tcx> {
|
impl<'a, 'tcx> Borrows<'a, 'tcx> {
|
||||||
|
@ -133,28 +148,21 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
body: &'a Body<'tcx>,
|
body: &'a Body<'tcx>,
|
||||||
nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
|
nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
|
||||||
borrow_set: &Rc<BorrowSet<'tcx>>,
|
borrow_set: Rc<BorrowSet<'tcx>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut borrows_out_of_scope_at_location = FxHashMap::default();
|
let mut prec = OutOfScopePrecomputer::new(body, nonlexical_regioncx.clone());
|
||||||
for (borrow_index, borrow_data) in borrow_set.iter_enumerated() {
|
for (borrow_index, borrow_data) in borrow_set.iter_enumerated() {
|
||||||
let borrow_region = borrow_data.region.to_region_vid();
|
let borrow_region = borrow_data.region.to_region_vid();
|
||||||
let location = borrow_data.reserve_location;
|
let location = borrow_data.reserve_location;
|
||||||
|
|
||||||
precompute_borrows_out_of_scope(
|
prec.precompute_borrows_out_of_scope(borrow_index, borrow_region, location);
|
||||||
body,
|
|
||||||
&nonlexical_regioncx,
|
|
||||||
&mut borrows_out_of_scope_at_location,
|
|
||||||
borrow_index,
|
|
||||||
borrow_region,
|
|
||||||
location,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Borrows {
|
Borrows {
|
||||||
tcx,
|
tcx,
|
||||||
body,
|
body,
|
||||||
borrow_set: borrow_set.clone(),
|
borrow_set,
|
||||||
borrows_out_of_scope_at_location,
|
borrows_out_of_scope_at_location: prec.borrows_out_of_scope_at_location,
|
||||||
_nonlexical_regioncx: nonlexical_regioncx,
|
_nonlexical_regioncx: nonlexical_regioncx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue