Skip to content

Commit 9f6ef66

Browse files
committed
Added dataflow analysis for Borrows.
post-rebase: addressed review comment: rename `loc_map`/`location_map` and `rgn_map`/`region_map`. post-rebase: remove now unnecessary `mut` decl. post-rebase: address comments: bind iterator expr, and alpha-rename `loc`/`location` and `idx`/`index`.
1 parent cff060b commit 9f6ef66

File tree

4 files changed

+187
-1
lines changed

4 files changed

+187
-1
lines changed
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use rustc::mir::{self, Location, Mir};
12+
use rustc::mir::visit::Visitor;
13+
use rustc::ty::{Region, TyCtxt};
14+
use rustc::ty::RegionKind::ReScope;
15+
use rustc::util::nodemap::{FxHashMap, FxHashSet};
16+
17+
use rustc_data_structures::bitslice::{BitwiseOperator};
18+
use rustc_data_structures::indexed_set::{IdxSet};
19+
use rustc_data_structures::indexed_vec::{IndexVec};
20+
21+
use dataflow::{BitDenotation, BlockSets, DataflowOperator};
22+
pub use dataflow::indexes::BorrowIndex;
23+
24+
use std::fmt;
25+
26+
// `Borrows` maps each dataflow bit to an `Rvalue::Ref`, which can be
27+
// uniquely identified in the MIR by the `Location` of the assigment
28+
// statement in which it appears on the right hand side.
29+
pub struct Borrows<'a, 'tcx: 'a> {
30+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
31+
mir: &'a Mir<'tcx>,
32+
borrows: IndexVec<BorrowIndex, BorrowData<'tcx>>,
33+
location_map: FxHashMap<Location, BorrowIndex>,
34+
region_map: FxHashMap<Region<'tcx>, FxHashSet<BorrowIndex>>,
35+
}
36+
37+
// temporarily allow some dead fields: `kind` and `region` will be
38+
// needed by borrowck; `lvalue` will probably be a MovePathIndex when
39+
// that is extended to include borrowed data paths.
40+
#[allow(dead_code)]
41+
#[derive(Debug)]
42+
pub struct BorrowData<'tcx> {
43+
pub(crate) location: Location,
44+
pub(crate) kind: mir::BorrowKind,
45+
pub(crate) region: Region<'tcx>,
46+
pub(crate) lvalue: mir::Lvalue<'tcx>,
47+
}
48+
49+
impl<'tcx> fmt::Display for BorrowData<'tcx> {
50+
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
51+
let kind = match self.kind {
52+
mir::BorrowKind::Shared => "",
53+
mir::BorrowKind::Unique => "uniq ",
54+
mir::BorrowKind::Mut => "mut ",
55+
};
56+
let region = format!("{}", self.region);
57+
let region = if region.len() > 0 { format!("{} ", region) } else { region };
58+
write!(w, "&{}{}{:?}", region, kind, self.lvalue)
59+
}
60+
}
61+
62+
impl<'a, 'tcx> Borrows<'a, 'tcx> {
63+
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self {
64+
let mut visitor = GatherBorrows { idx_vec: IndexVec::new(),
65+
location_map: FxHashMap(),
66+
region_map: FxHashMap(), };
67+
visitor.visit_mir(mir);
68+
return Borrows { tcx: tcx,
69+
mir: mir,
70+
borrows: visitor.idx_vec,
71+
location_map: visitor.location_map,
72+
region_map: visitor.region_map, };
73+
74+
struct GatherBorrows<'tcx> {
75+
idx_vec: IndexVec<BorrowIndex, BorrowData<'tcx>>,
76+
location_map: FxHashMap<Location, BorrowIndex>,
77+
region_map: FxHashMap<Region<'tcx>, FxHashSet<BorrowIndex>>,
78+
}
79+
impl<'tcx> Visitor<'tcx> for GatherBorrows<'tcx> {
80+
fn visit_rvalue(&mut self,
81+
rvalue: &mir::Rvalue<'tcx>,
82+
location: mir::Location) {
83+
if let mir::Rvalue::Ref(region, kind, ref lvalue) = *rvalue {
84+
let borrow = BorrowData {
85+
location: location, kind: kind, region: region, lvalue: lvalue.clone(),
86+
};
87+
let idx = self.idx_vec.push(borrow);
88+
self.location_map.insert(location, idx);
89+
let borrows = self.region_map.entry(region).or_insert(FxHashSet());
90+
borrows.insert(idx);
91+
}
92+
}
93+
}
94+
}
95+
96+
pub fn borrows(&self) -> &IndexVec<BorrowIndex, BorrowData<'tcx>> { &self.borrows }
97+
98+
pub fn location(&self, idx: BorrowIndex) -> &Location {
99+
&self.borrows[idx].location
100+
}
101+
}
102+
103+
impl<'a, 'tcx> BitDenotation for Borrows<'a, 'tcx> {
104+
type Idx = BorrowIndex;
105+
fn name() -> &'static str { "borrows" }
106+
fn bits_per_block(&self) -> usize {
107+
self.borrows.len()
108+
}
109+
fn start_block_effect(&self, _sets: &mut BlockSets<BorrowIndex>) {
110+
// no borrows of code extents have been taken prior to
111+
// function execution, so this method has no effect on
112+
// `_sets`.
113+
}
114+
fn statement_effect(&self,
115+
sets: &mut BlockSets<BorrowIndex>,
116+
location: Location) {
117+
let block = &self.mir.basic_blocks().get(location.block).unwrap_or_else(|| {
118+
panic!("could not find block at location {:?}", location);
119+
});
120+
let stmt = block.statements.get(location.statement_index).unwrap_or_else(|| {
121+
panic!("could not find statement at location {:?}");
122+
});
123+
match stmt.kind {
124+
mir::StatementKind::EndRegion(extent) => {
125+
let borrow_indexes = self.region_map.get(&ReScope(extent)).unwrap_or_else(|| {
126+
panic!("could not find BorrowIndexs for code-extent {:?}", extent);
127+
});
128+
129+
for idx in borrow_indexes { sets.kill(&idx); }
130+
}
131+
132+
mir::StatementKind::Assign(_, ref rhs) => {
133+
if let mir::Rvalue::Ref(region, _, _) = *rhs {
134+
let index = self.location_map.get(&location).unwrap_or_else(|| {
135+
panic!("could not find BorrowIndex for location {:?}", location);
136+
});
137+
assert!(self.region_map.get(region).unwrap_or_else(|| {
138+
panic!("could not find BorrowIndexs for region {:?}", region);
139+
}).contains(&index));
140+
sets.gen(&index);
141+
}
142+
}
143+
144+
mir::StatementKind::InlineAsm { .. } |
145+
mir::StatementKind::SetDiscriminant { .. } |
146+
mir::StatementKind::StorageLive(..) |
147+
mir::StatementKind::StorageDead(..) |
148+
mir::StatementKind::Validate(..) |
149+
mir::StatementKind::Nop => {}
150+
151+
}
152+
}
153+
fn terminator_effect(&self,
154+
_sets: &mut BlockSets<BorrowIndex>,
155+
_location: Location) {
156+
// no terminators start nor end code extents.
157+
}
158+
159+
fn propagate_call_return(&self,
160+
_in_out: &mut IdxSet<BorrowIndex>,
161+
_call_bb: mir::BasicBlock,
162+
_dest_bb: mir::BasicBlock,
163+
_dest_lval: &mir::Lvalue) {
164+
// there are no effects on the extents from method calls.
165+
}
166+
}
167+
168+
impl<'a, 'tcx> BitwiseOperator for Borrows<'a, 'tcx> {
169+
#[inline]
170+
fn join(&self, pred1: usize, pred2: usize) -> usize {
171+
pred1 | pred2 // union effects of preds when computing borrows
172+
}
173+
}
174+
175+
impl<'a, 'tcx> DataflowOperator for Borrows<'a, 'tcx> {
176+
#[inline]
177+
fn bottom_value() -> bool {
178+
false // bottom = no Rvalue::Refs are active by default
179+
}
180+
}

src/librustc_mir/dataflow/impls/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ use super::drop_flag_effects_for_function_entry;
3030
use super::drop_flag_effects_for_location;
3131
use super::on_lookup_result_bits;
3232

33+
#[allow(dead_code)]
34+
pub(super) mod borrows;
35+
3336
/// `MaybeInitializedLvals` tracks all l-values that might be
3437
/// initialized upon reaching a particular point in the control flow
3538
/// for a function.

src/librustc_mir/dataflow/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use std::usize;
2525

2626
pub use self::impls::{MaybeInitializedLvals, MaybeUninitializedLvals};
2727
pub use self::impls::{DefinitelyInitializedLvals, MovingOutStatements};
28-
28+
pub use self::impls::borrows::{Borrows, BorrowData, BorrowIndex};
2929
pub(crate) use self::drop_flag_effects::*;
3030

3131
mod drop_flag_effects;

src/librustc_mir/dataflow/move_paths/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ pub(crate) mod indexes {
6363

6464
/// Index into MoveData.moves.
6565
new_index!(MoveOutIndex, "mo");
66+
67+
/// Index into Borrows.locations
68+
new_index!(BorrowIndex, "bw");
6669
}
6770

6871
pub use self::indexes::MovePathIndex;

0 commit comments

Comments
 (0)