11use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher } ;
2- use rustc_data_structures:: sync:: { Lock , LockGuard , MappedLockGuard } ;
2+ use rustc_data_structures:: sync:: { Lock , Lrc } ;
33use rustc_index:: vec:: IndexVec ;
44use rustc_serialize as serialize;
55use smallvec:: SmallVec ;
@@ -11,7 +11,7 @@ pub type Predecessors = IndexVec<BasicBlock, SmallVec<[BasicBlock; 4]>>;
1111
1212#[ derive( Clone , Debug ) ]
1313pub struct PredecessorCache {
14- cache : Lock < Option < Predecessors > > ,
14+ cache : Lock < Option < Lrc < Predecessors > > > ,
1515}
1616
1717impl PredecessorCache {
@@ -20,30 +20,39 @@ impl PredecessorCache {
2020 PredecessorCache { cache : Lock :: new ( None ) }
2121 }
2222
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.
2329 #[ inline]
2430 pub fn invalidate ( & mut self ) {
2531 * self . cache . get_mut ( ) = None ;
2632 }
2733
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.
2839 #[ inline]
2940 pub fn compute (
3041 & self ,
3142 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) ;
4150 }
4251 }
52+ }
4353
44- preds
45- } )
46- } )
54+ Lrc :: new ( preds)
55+ } ) )
4756 }
4857}
4958
0 commit comments