1
- use std:: sync:: OnceLock ;
1
+ use std:: sync:: { Arc , OnceLock } ;
2
2
3
3
use rustc_data_structures:: graph;
4
4
use rustc_data_structures:: graph:: dominators:: { Dominators , dominators} ;
@@ -14,7 +14,8 @@ use crate::mir::{BasicBlock, BasicBlockData, START_BLOCK};
14
14
#[ derive( Clone , TyEncodable , TyDecodable , Debug , HashStable , TypeFoldable , TypeVisitable ) ]
15
15
pub struct BasicBlocks < ' tcx > {
16
16
basic_blocks : IndexVec < BasicBlock , BasicBlockData < ' tcx > > ,
17
- cache : Cache ,
17
+ /// Use an `Arc` so we can share the cache when we clone the MIR body, as borrowck does.
18
+ cache : Arc < Cache > ,
18
19
}
19
20
20
21
// Typically 95%+ of basic blocks have 4 or fewer predecessors.
@@ -38,9 +39,10 @@ struct Cache {
38
39
impl < ' tcx > BasicBlocks < ' tcx > {
39
40
#[ inline]
40
41
pub fn new ( basic_blocks : IndexVec < BasicBlock , BasicBlockData < ' tcx > > ) -> Self {
41
- BasicBlocks { basic_blocks, cache : Cache :: default ( ) }
42
+ BasicBlocks { basic_blocks, cache : Arc :: new ( Cache :: default ( ) ) }
42
43
}
43
44
45
+ #[ inline]
44
46
pub fn dominators ( & self ) -> & Dominators < BasicBlock > {
45
47
self . cache . dominators . get_or_init ( || dominators ( self ) )
46
48
}
@@ -104,7 +106,14 @@ impl<'tcx> BasicBlocks<'tcx> {
104
106
/// All other methods that allow you to mutate the basic blocks also call this method
105
107
/// themselves, thereby avoiding any risk of accidentally cache invalidation.
106
108
pub fn invalidate_cfg_cache ( & mut self ) {
107
- self . cache = Cache :: default ( ) ;
109
+ if let Some ( cache) = Arc :: get_mut ( & mut self . cache ) {
110
+ // If we only have a single reference to this cache, clear it.
111
+ * cache = Cache :: default ( ) ;
112
+ } else {
113
+ // If we have several references to this cache, overwrite the pointer itself so other
114
+ // users can continue to use their (valid) cache.
115
+ self . cache = Arc :: new ( Cache :: default ( ) ) ;
116
+ }
108
117
}
109
118
}
110
119
0 commit comments