diff options
| author | David Wood <david@davidtw.co> | 2018-05-27 11:15:52 +0100 |
|---|---|---|
| committer | David Wood <david@davidtw.co> | 2018-05-27 11:15:52 +0100 |
| commit | bbcace5080a73ea36417b1d4f6b846a2a01f9202 (patch) | |
| tree | a5cccc25e45f35b579528d935b59e3abaca69799 | |
| parent | 3fd82a5e6b3a707610fdc878e2b5608340e4969a (diff) | |
| download | rust-bbcace5080a73ea36417b1d4f6b846a2a01f9202.tar.gz rust-bbcace5080a73ea36417b1d4f6b846a2a01f9202.zip | |
Use precomputed DFS of borrows that out of scope at a location.
| -rw-r--r-- | src/librustc_mir/dataflow/impls/borrows.rs | 130 |
1 files changed, 116 insertions, 14 deletions
diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 04c62854c5c..7018ab345db 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -15,12 +15,13 @@ use rustc; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::middle::region; -use rustc::mir::{self, Location, Place, Mir}; +use rustc::mir::{self, Location, Place, Mir, TerminatorKind}; use rustc::ty::TyCtxt; -use rustc::ty::RegionKind; +use rustc::ty::{RegionKind, RegionVid}; use rustc::ty::RegionKind::ReScope; use rustc_data_structures::bitslice::BitwiseOperator; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_set::IdxSet; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::sync::Lrc; @@ -46,9 +47,103 @@ pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> { root_scope: Option<region::Scope>, borrow_set: Rc<BorrowSet<'tcx>>, + borrows_out_of_scope_at_location: FxHashMap<Location, Vec<BorrowIndex>>, /// NLL region inference context with which NLL queries should be resolved - nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>, + _nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>, +} + +fn precompute_borrows_out_of_scope<'a, 'tcx>( + mir: &'a Mir<'tcx>, + regioncx: &Rc<RegionInferenceContext<'tcx>>, + borrows_out_of_scope_at_location: &mut FxHashMap<Location, Vec<BorrowIndex>>, + borrow_index: BorrowIndex, + borrow_region: RegionVid, + location: Location +) { + // Start by dealing with the current location. + if !regioncx.region_contains_point(borrow_region, location) { + borrows_out_of_scope_at_location + .entry(location.clone()) + .and_modify(|m| m.push(borrow_index)) + .or_insert(vec![ borrow_index ]); + } + + let bb_data = &mir[location.block]; + // If we are on the last statement, then check the terminator + // to determine which location to proceed to. + if location.statement_index == bb_data.statements.len() - 1 { + if let Some(ref terminator) = bb_data.terminator { + match terminator.kind { + TerminatorKind::Goto { target } | + TerminatorKind::FalseEdges { real_target: target, .. } | + TerminatorKind::FalseUnwind { real_target: target, .. } => { + precompute_borrows_out_of_scope( + mir, regioncx, borrows_out_of_scope_at_location, + borrow_index, borrow_region, target.start_location() + ); + }, + TerminatorKind::SwitchInt { ref targets, .. } => { + for block in targets { + precompute_borrows_out_of_scope( + mir, regioncx, borrows_out_of_scope_at_location, + borrow_index, borrow_region, block.start_location() + ); + } + }, + TerminatorKind::Drop { target, unwind, .. } | + TerminatorKind::DropAndReplace { target, unwind, .. } => { + precompute_borrows_out_of_scope( + mir, regioncx, borrows_out_of_scope_at_location, + borrow_index, borrow_region, target.start_location() + ); + + if let Some(unwind_block) = unwind { + precompute_borrows_out_of_scope( + mir, regioncx, borrows_out_of_scope_at_location, + borrow_index, borrow_region, unwind_block.start_location() + ); + } + }, + TerminatorKind::Call { ref destination, cleanup, .. } => { + if let Some((_, block)) = destination { + precompute_borrows_out_of_scope( + mir, regioncx, borrows_out_of_scope_at_location, + borrow_index, borrow_region, block.start_location() + ); + } + + if let Some(block) = cleanup { + precompute_borrows_out_of_scope( + mir, regioncx, borrows_out_of_scope_at_location, + borrow_index, borrow_region, block.start_location() + ); + } + }, + TerminatorKind::Assert { target, cleanup, .. } | + TerminatorKind::Yield { resume: target, drop: cleanup, .. } => { + precompute_borrows_out_of_scope( + mir, regioncx, borrows_out_of_scope_at_location, + borrow_index, borrow_region, target.start_location() + ); + + if let Some(block) = cleanup { + precompute_borrows_out_of_scope( + mir, regioncx, borrows_out_of_scope_at_location, + borrow_index, borrow_region, block.start_location() + ); + } + }, + _ => {}, + }; + }; + // If we're not on the last statement, then go to the next + // statement in this block. + } else { + precompute_borrows_out_of_scope(mir, regioncx, borrows_out_of_scope_at_location, + borrow_index, borrow_region, + location.successor_within_block()); + } } impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { @@ -65,18 +160,28 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { region::Scope::CallSite(tcx.hir.body(body_id).value.hir_id.local_id) }); + let mut borrows_out_of_scope_at_location = FxHashMap(); + for (borrow_index, borrow_data) in borrow_set.borrows.iter_enumerated() { + let borrow_region = borrow_data.region.to_region_vid(); + let location = borrow_set.borrows[borrow_index].reserve_location; + + precompute_borrows_out_of_scope(mir, &nonlexical_regioncx, + &mut borrows_out_of_scope_at_location, + borrow_index, borrow_region, location); + } + Borrows { tcx: tcx, mir: mir, borrow_set: borrow_set.clone(), + borrows_out_of_scope_at_location, scope_tree, root_scope, - nonlexical_regioncx, + _nonlexical_regioncx: nonlexical_regioncx, } } crate fn borrows(&self) -> &IndexVec<BorrowIndex, BorrowData<'tcx>> { &self.borrow_set.borrows } - pub fn scope_tree(&self) -> &Lrc<region::ScopeTree> { &self.scope_tree } pub fn location(&self, idx: BorrowIndex) -> &Location { @@ -89,12 +194,10 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { fn kill_loans_out_of_scope_at_location(&self, sets: &mut BlockSets<BorrowIndex>, location: Location) { - let regioncx = &self.nonlexical_regioncx; - // NOTE: The state associated with a given `location` - // reflects the dataflow on entry to the statement. If it - // does not contain `borrow_region`, then then that means - // that the statement at `location` kills the borrow. + // reflects the dataflow on entry to the statement. + // Iterate over each of the borrows that we've precomputed + // to have went out of scope at this location and kill them. // // We are careful always to call this function *before* we // set up the gen-bits for the statement or @@ -102,10 +205,9 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { // terminator *does* introduce a new loan of the same // region, then setting that gen-bit will override any // potential kill introduced here. - for (borrow_index, borrow_data) in self.borrow_set.borrows.iter_enumerated() { - let borrow_region = borrow_data.region.to_region_vid(); - if !regioncx.region_contains_point(borrow_region, location) { - sets.kill(&borrow_index); + if let Some(indices) = self.borrows_out_of_scope_at_location.get(&location) { + for index in indices { + sets.kill(&index); } } } |
