1
1
use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher } ;
2
- use rustc_data_structures:: sync:: { Lock , LockGuard , MappedLockGuard } ;
2
+ use rustc_data_structures:: sync:: { Lock , Lrc } ;
3
3
use rustc_index:: vec:: IndexVec ;
4
4
use rustc_serialize as serialize;
5
5
use smallvec:: SmallVec ;
@@ -11,7 +11,7 @@ pub type Predecessors = IndexVec<BasicBlock, SmallVec<[BasicBlock; 4]>>;
11
11
12
12
#[ derive( Clone , Debug ) ]
13
13
pub struct PredecessorCache {
14
- cache : Lock < Option < Predecessors > > ,
14
+ cache : Lock < Option < Lrc < Predecessors > > > ,
15
15
}
16
16
17
17
impl PredecessorCache {
@@ -20,30 +20,39 @@ impl PredecessorCache {
20
20
PredecessorCache { cache : Lock :: new ( None ) }
21
21
}
22
22
23
+ /// Invalidates the predecessor cache.
24
+ ///
25
+ /// Invalidating the predecessor cache requires mutating the MIR, which in turn requires a
26
+ /// unique reference (`&mut`) to the `mir::Body`. Because of this, we can assume that all
27
+ /// callers of `invalidate` have a unique reference to the MIR and thus to the predecessor
28
+ /// cache. This means we don't actually need to take a lock when `invalidate` is called.
23
29
#[ inline]
24
30
pub fn invalidate ( & mut self ) {
25
31
* self . cache . get_mut ( ) = None ;
26
32
}
27
33
34
+ /// Returns a ref-counted smart pointer containing the predecessor graph for this MIR.
35
+ ///
36
+ /// We use ref-counting instead of a mapped `LockGuard` here to ensure that the lock for
37
+ /// `cache` is only held inside this function. As long as no other locks are taken while
38
+ /// computing the predecessor graph, deadlock is impossible.
28
39
#[ inline]
29
40
pub fn compute (
30
41
& self ,
31
42
basic_blocks : & IndexVec < BasicBlock , BasicBlockData < ' _ > > ,
32
- ) -> MappedLockGuard < ' _ , Predecessors > {
33
- LockGuard :: map ( self . cache . lock ( ) , |cache| {
34
- cache. get_or_insert_with ( || {
35
- let mut preds = IndexVec :: from_elem ( SmallVec :: new ( ) , basic_blocks) ;
36
- for ( bb, data) in basic_blocks. iter_enumerated ( ) {
37
- if let Some ( term) = & data. terminator {
38
- for & succ in term. successors ( ) {
39
- preds[ succ] . push ( bb) ;
40
- }
43
+ ) -> Lrc < Predecessors > {
44
+ Lrc :: clone ( self . cache . lock ( ) . get_or_insert_with ( || {
45
+ let mut preds = IndexVec :: from_elem ( SmallVec :: new ( ) , basic_blocks) ;
46
+ for ( bb, data) in basic_blocks. iter_enumerated ( ) {
47
+ if let Some ( term) = & data. terminator {
48
+ for & succ in term. successors ( ) {
49
+ preds[ succ] . push ( bb) ;
41
50
}
42
51
}
52
+ }
43
53
44
- preds
45
- } )
46
- } )
54
+ Lrc :: new ( preds)
55
+ } ) )
47
56
}
48
57
}
49
58
0 commit comments