@@ -2,8 +2,10 @@ use crate::dep_graph::DepNodeIndex;
22use crate :: query:: plumbing:: { QueryLookup , QueryState } ;
33use crate :: query:: QueryContext ;
44
5+ use arena:: TypedArena ;
56use rustc_data_structures:: fx:: FxHashMap ;
67use rustc_data_structures:: sharded:: Sharded ;
8+ use rustc_data_structures:: sync:: WorkerLocal ;
79use std:: default:: Default ;
810use std:: hash:: Hash ;
911use std:: marker:: PhantomData ;
@@ -133,3 +135,88 @@ impl<K: Eq + Hash, V: Clone> QueryCache for DefaultCache<K, V> {
133135 f ( Box :: new ( results) )
134136 }
135137}
138+
139+ pub struct ArenaCacheSelector < ' tcx > ( PhantomData < & ' tcx ( ) > ) ;
140+
141+ impl < ' tcx , K : Eq + Hash , V : ' tcx > CacheSelector < K , V > for ArenaCacheSelector < ' tcx > {
142+ type Cache = ArenaCache < ' tcx , K , V > ;
143+ }
144+
145+ pub struct ArenaCache < ' tcx , K , V > {
146+ arena : WorkerLocal < & ' tcx TypedArena < ( V , DepNodeIndex ) > > ,
147+ phantom : PhantomData < K > ,
148+ }
149+
150+ impl < ' tcx , K , V > Default for ArenaCache < ' tcx , K , V > {
151+ fn default ( ) -> Self {
152+ ArenaCache {
153+ arena : WorkerLocal :: new ( |_| & * Box :: leak ( Box :: new ( TypedArena :: default ( ) ) ) ) ,
154+ phantom : PhantomData ,
155+ }
156+ }
157+ }
158+
159+ impl < ' tcx , K : Eq + Hash , V : ' tcx > QueryStorage for ArenaCache < ' tcx , K , V > {
160+ type Value = V ;
161+ type Stored = & ' tcx V ;
162+
163+ fn store_nocache ( & self , value : Self :: Value ) -> Self :: Stored {
164+ let value = self . arena . alloc ( ( value, DepNodeIndex :: INVALID ) ) ;
165+ & value. 0
166+ }
167+ }
168+
169+ impl < ' tcx , K : Eq + Hash , V : ' tcx > QueryCache for ArenaCache < ' tcx , K , V > {
170+ type Key = K ;
171+ type Sharded = FxHashMap < K , & ' tcx ( V , DepNodeIndex ) > ;
172+
173+ #[ inline( always) ]
174+ fn lookup < CTX : QueryContext , R , OnHit , OnMiss > (
175+ & self ,
176+ state : & QueryState < CTX , Self > ,
177+ key : K ,
178+ on_hit : OnHit ,
179+ on_miss : OnMiss ,
180+ ) -> R
181+ where
182+ OnHit : FnOnce ( & & ' tcx V , DepNodeIndex ) -> R ,
183+ OnMiss : FnOnce ( K , QueryLookup < ' _ , CTX , K , Self :: Sharded > ) -> R ,
184+ {
185+ let mut lookup = state. get_lookup ( & key) ;
186+ let lock = & mut * lookup. lock ;
187+
188+ let result = lock. cache . raw_entry ( ) . from_key_hashed_nocheck ( lookup. key_hash , & key) ;
189+
190+ if let Some ( ( _, value) ) = result {
191+ on_hit ( & & value. 0 , value. 1 )
192+ } else {
193+ on_miss ( key, lookup)
194+ }
195+ }
196+
197+ #[ inline]
198+ fn complete < CTX : QueryContext > (
199+ & self ,
200+ _: CTX ,
201+ lock_sharded_storage : & mut Self :: Sharded ,
202+ key : K ,
203+ value : V ,
204+ index : DepNodeIndex ,
205+ ) -> Self :: Stored {
206+ let value = self . arena . alloc ( ( value, index) ) ;
207+ lock_sharded_storage. insert ( key, value) ;
208+ & value. 0
209+ }
210+
211+ fn iter < R , L > (
212+ & self ,
213+ shards : & Sharded < L > ,
214+ get_shard : impl Fn ( & mut L ) -> & mut Self :: Sharded ,
215+ f : impl for < ' a > FnOnce ( Box < dyn Iterator < Item = ( & ' a K , & ' a V , DepNodeIndex ) > + ' a > ) -> R ,
216+ ) -> R {
217+ let mut shards = shards. lock_shards ( ) ;
218+ let mut shards: Vec < _ > = shards. iter_mut ( ) . map ( |shard| get_shard ( shard) ) . collect ( ) ;
219+ let results = shards. iter_mut ( ) . flat_map ( |shard| shard. iter ( ) ) . map ( |( k, v) | ( k, & v. 0 , v. 1 ) ) ;
220+ f ( Box :: new ( results) )
221+ }
222+ }
0 commit comments