1- use std:: sync:: OnceLock ;
1+ use std:: sync:: { Arc , OnceLock } ;
22
33use rustc_data_structures:: graph;
44use rustc_data_structures:: graph:: dominators:: { Dominators , dominators} ;
@@ -14,7 +14,8 @@ use crate::mir::{BasicBlock, BasicBlockData, START_BLOCK};
1414#[ derive( Clone , TyEncodable , TyDecodable , Debug , HashStable , TypeFoldable , TypeVisitable ) ]
1515pub struct BasicBlocks < ' tcx > {
1616 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 > ,
1819}
1920
2021// Typically 95%+ of basic blocks have 4 or fewer predecessors.
@@ -38,9 +39,10 @@ struct Cache {
3839impl < ' tcx > BasicBlocks < ' tcx > {
3940 #[ inline]
4041 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 ( ) ) }
4243 }
4344
45+ #[ inline]
4446 pub fn dominators ( & self ) -> & Dominators < BasicBlock > {
4547 self . cache . dominators . get_or_init ( || dominators ( self ) )
4648 }
@@ -104,7 +106,14 @@ impl<'tcx> BasicBlocks<'tcx> {
104106 /// All other methods that allow you to mutate the basic blocks also call this method
105107 /// themselves, thereby avoiding any risk of accidentally cache invalidation.
106108 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+ }
108117 }
109118}
110119
0 commit comments