Skip to content

Commit 5ea002a

Browse files
committed
Auto merge of #68988 - Zoxc:query-caches, r=<try>
[WIP] Add an abstraction for custom query caches r? @eddyb
2 parents e168dcd + 022416d commit 5ea002a

File tree

12 files changed

+589
-219
lines changed

12 files changed

+589
-219
lines changed

src/librustc/dep_graph/dep_node.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,17 +99,17 @@ macro_rules! is_eval_always_attr {
9999
}
100100

101101
macro_rules! contains_anon_attr {
102-
($($attr:ident),*) => ({$(is_anon_attr!($attr) | )* false});
102+
($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_anon_attr!($attr) | )* false});
103103
}
104104

105105
macro_rules! contains_eval_always_attr {
106-
($($attr:ident),*) => ({$(is_eval_always_attr!($attr) | )* false});
106+
($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_eval_always_attr!($attr) | )* false});
107107
}
108108

109109
macro_rules! define_dep_nodes {
110110
(<$tcx:tt>
111111
$(
112-
[$($attr:ident),* ]
112+
[$($attrs:tt)*]
113113
$variant:ident $(( $tuple_arg_ty:ty $(,)? ))*
114114
$({ $($struct_arg_name:ident : $struct_arg_ty:ty),* })*
115115
,)*
@@ -126,7 +126,7 @@ macro_rules! define_dep_nodes {
126126
match *self {
127127
$(
128128
DepKind :: $variant => {
129-
if contains_anon_attr!($($attr),*) {
129+
if contains_anon_attr!($($attrs)*) {
130130
return false;
131131
}
132132

@@ -152,15 +152,15 @@ macro_rules! define_dep_nodes {
152152
pub fn is_anon(&self) -> bool {
153153
match *self {
154154
$(
155-
DepKind :: $variant => { contains_anon_attr!($($attr),*) }
155+
DepKind :: $variant => { contains_anon_attr!($($attrs)*) }
156156
)*
157157
}
158158
}
159159

160160
pub fn is_eval_always(&self) -> bool {
161161
match *self {
162162
$(
163-
DepKind :: $variant => { contains_eval_always_attr!($($attr), *) }
163+
DepKind :: $variant => { contains_eval_always_attr!($($attrs)*) }
164164
)*
165165
}
166166
}

src/librustc/dep_graph/graph.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,6 +1122,7 @@ impl CurrentDepGraph {
11221122
}
11231123

11241124
impl DepGraphData {
1125+
#[inline]
11251126
fn read_index(&self, source: DepNodeIndex) {
11261127
ty::tls::with_context_opt(|icx| {
11271128
let icx = if let Some(icx) = icx { icx } else { return };

src/librustc/query/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ rustc_queries! {
5757

5858
/// Records the type of every item.
5959
query type_of(key: DefId) -> Ty<'tcx> {
60+
storage(caches::LocalDenseDefIdCacheSelector<Ty<'tcx>>)
6061
cache_on_disk_if { key.is_local() }
6162
}
6263

src/librustc/ty/context.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,6 +1688,7 @@ pub mod tls {
16881688

16891689
/// Gets the pointer to the current `ImplicitCtxt`.
16901690
#[cfg(not(parallel_compiler))]
1691+
#[inline]
16911692
fn get_tlv() -> usize {
16921693
TLV.with(|tlv| tlv.get())
16931694
}

src/librustc/ty/query/caches.rs

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
use crate::dep_graph::DepNodeIndex;
2+
use crate::ty::query::config::QueryAccessors;
3+
use crate::ty::query::plumbing::{QueryLookup, QueryState, QueryStateShard};
4+
use crate::ty::TyCtxt;
5+
6+
use rustc_data_structures::fx::FxHashMap;
7+
use rustc_data_structures::sharded::Sharded;
8+
use rustc_hir::def_id::{DefId, DefIndex, LOCAL_CRATE};
9+
use rustc_index::vec::IndexVec;
10+
use std::cell::RefCell;
11+
use std::default::Default;
12+
use std::hash::Hash;
13+
use std::marker::PhantomData;
14+
15+
pub(crate) trait CacheSelector<K, V> {
16+
type Cache: QueryCache<K, V>;
17+
}
18+
19+
pub(crate) trait QueryCache<K, V>: Default {
20+
type Sharded: Default;
21+
22+
/// Checks if the query is already computed and in the cache.
23+
/// It returns the shard index and a lock guard to the shard,
24+
/// which will be used if the query is not in the cache and we need
25+
/// to compute it.
26+
fn lookup<'tcx, R, GetCache, OnHit, OnMiss, Q>(
27+
&self,
28+
state: &'tcx QueryState<'tcx, Q>,
29+
get_cache: GetCache,
30+
key: K,
31+
// `on_hit` can be called while holding a lock to the query state shard.
32+
on_hit: OnHit,
33+
on_miss: OnMiss,
34+
) -> R
35+
where
36+
Q: QueryAccessors<'tcx>,
37+
GetCache: for<'a> Fn(&'a mut QueryStateShard<'tcx, Q>) -> &'a mut Self::Sharded,
38+
OnHit: FnOnce(&V, DepNodeIndex) -> R,
39+
OnMiss: FnOnce(K, QueryLookup<'tcx, Q>) -> R;
40+
41+
fn complete(
42+
&self,
43+
tcx: TyCtxt<'tcx>,
44+
lock_sharded_storage: &mut Self::Sharded,
45+
key: K,
46+
value: V,
47+
index: DepNodeIndex,
48+
);
49+
50+
fn iter<R, L>(
51+
&self,
52+
shards: &Sharded<L>,
53+
get_shard: impl Fn(&mut L) -> &mut Self::Sharded,
54+
f: impl for<'a> FnOnce(Box<dyn Iterator<Item = (&'a K, &'a V, DepNodeIndex)> + 'a>) -> R,
55+
) -> R;
56+
}
57+
58+
pub struct DefaultCacheSelector;
59+
60+
impl<K: Eq + Hash, V: Clone> CacheSelector<K, V> for DefaultCacheSelector {
61+
type Cache = DefaultCache<()>;
62+
}
63+
64+
pub struct DefaultCache<D>(PhantomData<D>);
65+
66+
impl<D> Default for DefaultCache<D> {
67+
fn default() -> Self {
68+
DefaultCache(PhantomData)
69+
}
70+
}
71+
72+
impl<D, K: Eq + Hash, V: Clone> QueryCache<K, V> for DefaultCache<D> {
73+
type Sharded = FxHashMap<K, (V, DepNodeIndex)>;
74+
75+
#[inline(always)]
76+
fn lookup<'tcx, R, GetCache, OnHit, OnMiss, Q>(
77+
&self,
78+
state: &'tcx QueryState<'tcx, Q>,
79+
get_cache: GetCache,
80+
key: K,
81+
on_hit: OnHit,
82+
on_miss: OnMiss,
83+
) -> R
84+
where
85+
Q: QueryAccessors<'tcx>,
86+
GetCache: for<'a> Fn(&'a mut QueryStateShard<'tcx, Q>) -> &'a mut Self::Sharded,
87+
OnHit: FnOnce(&V, DepNodeIndex) -> R,
88+
OnMiss: FnOnce(K, QueryLookup<'tcx, Q>) -> R,
89+
{
90+
let mut lookup = state.get_lookup(&key);
91+
let lock = &mut *lookup.lock;
92+
93+
let result = get_cache(lock).raw_entry().from_key_hashed_nocheck(lookup.key_hash, &key);
94+
95+
if let Some((_, value)) = result { on_hit(&value.0, value.1) } else { on_miss(key, lookup) }
96+
}
97+
98+
#[inline]
99+
fn complete(
100+
&self,
101+
_: TyCtxt<'tcx>,
102+
lock_sharded_storage: &mut Self::Sharded,
103+
key: K,
104+
value: V,
105+
index: DepNodeIndex,
106+
) {
107+
lock_sharded_storage.insert(key, (value, index));
108+
}
109+
110+
fn iter<R, L>(
111+
&self,
112+
shards: &Sharded<L>,
113+
get_shard: impl Fn(&mut L) -> &mut Self::Sharded,
114+
f: impl for<'a> FnOnce(Box<dyn Iterator<Item = (&'a K, &'a V, DepNodeIndex)> + 'a>) -> R,
115+
) -> R {
116+
let mut shards = shards.lock_shards();
117+
let mut shards: Vec<_> = shards.iter_mut().map(|shard| get_shard(shard)).collect();
118+
let results = shards.iter_mut().flat_map(|shard| shard.iter()).map(|(k, v)| (k, &v.0, v.1));
119+
f(Box::new(results))
120+
}
121+
}
122+
123+
#[cfg(parallel_compiler)]
124+
pub type LocalDenseDefIdCacheSelector<V> = DefaultCache<V>;
125+
#[cfg(not(parallel_compiler))]
126+
pub type LocalDenseDefIdCacheSelector<V> = LocalDenseDefIdCache<V>;
127+
128+
pub struct LocalDenseDefIdCache<V> {
129+
local: RefCell<IndexVec<DefIndex, Option<(V, DepNodeIndex)>>>,
130+
other: DefaultCache<()>,
131+
}
132+
133+
impl<V> Default for LocalDenseDefIdCache<V> {
134+
fn default() -> Self {
135+
LocalDenseDefIdCache { local: RefCell::new(IndexVec::new()), other: Default::default() }
136+
}
137+
}
138+
139+
impl<V: Clone> QueryCache<DefId, V> for LocalDenseDefIdCache<V> {
140+
type Sharded = <DefaultCache<()> as QueryCache<DefId, V>>::Sharded;
141+
142+
#[inline(always)]
143+
fn lookup<'tcx, R, GetCache, OnHit, OnMiss, Q>(
144+
&self,
145+
state: &'tcx QueryState<'tcx, Q>,
146+
get_cache: GetCache,
147+
key: DefId,
148+
on_hit: OnHit,
149+
on_miss: OnMiss,
150+
) -> R
151+
where
152+
Q: QueryAccessors<'tcx>,
153+
GetCache: for<'a> Fn(&'a mut QueryStateShard<'tcx, Q>) -> &'a mut Self::Sharded,
154+
OnHit: FnOnce(&V, DepNodeIndex) -> R,
155+
OnMiss: FnOnce(DefId, QueryLookup<'tcx, Q>) -> R,
156+
{
157+
if key.krate == LOCAL_CRATE {
158+
let local = self.local.borrow();
159+
if let Some(result) = local.get(key.index).and_then(|v| v.as_ref()) {
160+
on_hit(&result.0, result.1)
161+
} else {
162+
drop(local);
163+
let lookup = state.get_lookup(&key);
164+
on_miss(key, lookup)
165+
}
166+
} else {
167+
self.other.lookup(state, get_cache, key, on_hit, on_miss)
168+
}
169+
}
170+
171+
#[inline]
172+
fn complete(
173+
&self,
174+
tcx: TyCtxt<'tcx>,
175+
lock_sharded_storage: &mut Self::Sharded,
176+
key: DefId,
177+
value: V,
178+
index: DepNodeIndex,
179+
) {
180+
if key.krate == LOCAL_CRATE {
181+
let mut local = self.local.borrow_mut();
182+
if local.raw.capacity() == 0 {
183+
*local = IndexVec::from_elem_n(None, tcx.hir().definitions().def_index_count());
184+
}
185+
local[key.index] = Some((value, index));
186+
} else {
187+
self.other.complete(tcx, lock_sharded_storage, key, value, index);
188+
}
189+
}
190+
191+
fn iter<R, L>(
192+
&self,
193+
shards: &Sharded<L>,
194+
get_shard: impl Fn(&mut L) -> &mut Self::Sharded,
195+
f: impl for<'a> FnOnce(Box<dyn Iterator<Item = (&'a DefId, &'a V, DepNodeIndex)> + 'a>) -> R,
196+
) -> R {
197+
let local = self.local.borrow();
198+
let local: Vec<(DefId, &V, DepNodeIndex)> = local
199+
.iter_enumerated()
200+
.filter_map(|(i, e)| e.as_ref().map(|e| (DefId::local(i), &e.0, e.1)))
201+
.collect();
202+
self.other.iter(shards, get_shard, |results| {
203+
f(Box::new(results.chain(local.iter().map(|(id, v, i)| (id, *v, *i)))))
204+
})
205+
}
206+
}

src/librustc/ty/query/config.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
use crate::dep_graph::SerializedDepNodeIndex;
22
use crate::dep_graph::{DepKind, DepNode};
3+
use crate::ty::query::caches::QueryCache;
34
use crate::ty::query::plumbing::CycleError;
45
use crate::ty::query::queries;
5-
use crate::ty::query::{Query, QueryCache};
6+
use crate::ty::query::{Query, QueryState};
67
use crate::ty::TyCtxt;
78
use rustc_data_structures::profiling::ProfileCategory;
89
use rustc_hir::def_id::{CrateNum, DefId};
910

1011
use crate::ich::StableHashingContext;
1112
use rustc_data_structures::fingerprint::Fingerprint;
12-
use rustc_data_structures::sharded::Sharded;
1313
use std::borrow::Cow;
1414
use std::fmt::Debug;
1515
use std::hash::Hash;
@@ -30,10 +30,12 @@ pub(crate) trait QueryAccessors<'tcx>: QueryConfig<'tcx> {
3030
const ANON: bool;
3131
const EVAL_ALWAYS: bool;
3232

33+
type Cache: QueryCache<Self::Key, Self::Value>;
34+
3335
fn query(key: Self::Key) -> Query<'tcx>;
3436

3537
// Don't use this method to access query results, instead use the methods on TyCtxt
36-
fn query_cache<'a>(tcx: TyCtxt<'tcx>) -> &'a Sharded<QueryCache<'tcx, Self>>;
38+
fn query_state<'a>(tcx: TyCtxt<'tcx>) -> &'a QueryState<'tcx, Self>;
3739

3840
fn to_dep_node(tcx: TyCtxt<'tcx>, key: &Self::Key) -> DepNode;
3941

@@ -61,7 +63,10 @@ pub(crate) trait QueryDescription<'tcx>: QueryAccessors<'tcx> {
6163
}
6264
}
6365

64-
impl<'tcx, M: QueryAccessors<'tcx, Key = DefId>> QueryDescription<'tcx> for M {
66+
impl<'tcx, M: QueryAccessors<'tcx, Key = DefId>> QueryDescription<'tcx> for M
67+
where
68+
<M as QueryAccessors<'tcx>>::Cache: QueryCache<DefId, <M as QueryConfig<'tcx>>::Value>,
69+
{
6570
default fn describe(tcx: TyCtxt<'_>, def_id: DefId) -> Cow<'static, str> {
6671
if !tcx.sess.verbose() {
6772
format!("processing `{}`", tcx.def_path_str(def_id)).into()

0 commit comments

Comments
 (0)