@@ -2,8 +2,11 @@ use crate::dep_graph::DepNodeIndex;
22
33use rustc_data_structures:: fx:: FxHashMap ;
44use rustc_data_structures:: sharded:: { self , Sharded } ;
5- use rustc_data_structures:: sync:: OnceLock ;
5+ use rustc_data_structures:: sync:: { Lock , OnceLock } ;
6+ use rustc_hir:: def_id:: LOCAL_CRATE ;
67use rustc_index:: { Idx , IndexVec } ;
8+ use rustc_span:: def_id:: DefId ;
9+ use rustc_span:: def_id:: DefIndex ;
710use std:: fmt:: Debug ;
811use std:: hash:: Hash ;
912use std:: marker:: PhantomData ;
@@ -148,6 +151,8 @@ where
148151
149152 #[ inline( always) ]
150153 fn lookup ( & self , key : & K ) -> Option < ( V , DepNodeIndex ) > {
154+ // FIXME: lock_shard_by_hash will use high bits which are usually zero in the index() passed
155+ // here. This makes sharding essentially useless, always selecting the zero'th shard.
151156 let lock = self . cache . lock_shard_by_hash ( key. index ( ) as u64 ) ;
152157 if let Some ( Some ( value) ) = lock. get ( * key) { Some ( * value) } else { None }
153158 }
@@ -168,3 +173,75 @@ where
168173 }
169174 }
170175}
176+
177+ pub struct DefIdCacheSelector ;
178+
179+ impl < ' tcx , V : ' tcx > CacheSelector < ' tcx , V > for DefIdCacheSelector {
180+ type Cache = DefIdCache < V >
181+ where
182+ V : Copy ;
183+ }
184+
185+ pub struct DefIdCache < V > {
186+ /// Stores the local DefIds in a dense map. Local queries are much more often dense, so this is
187+ /// a win over hashing query keys at marginal memory cost (~5% at most) compared to FxHashMap.
188+ ///
189+ /// The second element of the tuple is the set of keys actually present in the IndexVec, used
190+ /// for faster iteration in `iter()`.
191+ // FIXME: This may want to be sharded, like VecCache. However *how* to shard an IndexVec isn't
192+ // super clear; VecCache is effectively not sharded today (see FIXME there). For now just omit
193+ // that complexity here.
194+ local : Lock < ( IndexVec < DefIndex , Option < ( V , DepNodeIndex ) > > , Vec < DefIndex > ) > ,
195+ foreign : DefaultCache < DefId , V > ,
196+ }
197+
198+ impl < V > Default for DefIdCache < V > {
199+ fn default ( ) -> Self {
200+ DefIdCache { local : Default :: default ( ) , foreign : Default :: default ( ) }
201+ }
202+ }
203+
204+ impl < V > QueryCache for DefIdCache < V >
205+ where
206+ V : Copy ,
207+ {
208+ type Key = DefId ;
209+ type Value = V ;
210+
211+ #[ inline( always) ]
212+ fn lookup ( & self , key : & DefId ) -> Option < ( V , DepNodeIndex ) > {
213+ if key. krate == LOCAL_CRATE {
214+ let cache = self . local . lock ( ) ;
215+ cache. 0 . get ( key. index ) . and_then ( |v| * v)
216+ } else {
217+ self . foreign . lookup ( key)
218+ }
219+ }
220+
221+ #[ inline]
222+ fn complete ( & self , key : DefId , value : V , index : DepNodeIndex ) {
223+ if key. krate == LOCAL_CRATE {
224+ let mut cache = self . local . lock ( ) ;
225+ let ( cache, present) = & mut * cache;
226+ let slot = cache. ensure_contains_elem ( key. index , Default :: default) ;
227+ if slot. is_none ( ) {
228+ // FIXME: Only store the present set when running in incremental mode. `iter` is not
229+ // used outside of saving caches to disk and self-profile.
230+ present. push ( key. index ) ;
231+ }
232+ * slot = Some ( ( value, index) ) ;
233+ } else {
234+ self . foreign . complete ( key, value, index)
235+ }
236+ }
237+
238+ fn iter ( & self , f : & mut dyn FnMut ( & Self :: Key , & Self :: Value , DepNodeIndex ) ) {
239+ let guard = self . local . lock ( ) ;
240+ let ( cache, present) = & * guard;
241+ for & idx in present. iter ( ) {
242+ let value = cache[ idx] . unwrap ( ) ;
243+ f ( & DefId { krate : LOCAL_CRATE , index : idx } , & value. 0 , value. 1 ) ;
244+ }
245+ self . foreign . iter ( f) ;
246+ }
247+ }
0 commit comments