rust/compiler/rustc_query_system/src/query/caches.rs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

172 lines
4.5 KiB
Rust
Raw Normal View History

use std::fmt::Debug;
use std::hash::Hash;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sharded::{self, Sharded};
use rustc_data_structures::sync::OnceLock;
pub use rustc_data_structures::vec_cache::VecCache;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_index::Idx;
use rustc_span::def_id::{DefId, DefIndex};
use crate::dep_graph::DepNodeIndex;
pub trait QueryCache: Sized {
2023-02-17 16:33:05 +00:00
type Key: Hash + Eq + Copy + Debug;
type Value: Copy;
/// Checks if the query is already computed and in the cache.
fn lookup(&self, key: &Self::Key) -> Option<(Self::Value, DepNodeIndex)>;
fn complete(&self, key: Self::Key, value: Self::Value, index: DepNodeIndex);
fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex));
}
pub struct DefaultCache<K, V> {
cache: Sharded<FxHashMap<K, (V, DepNodeIndex)>>,
}
impl<K, V> Default for DefaultCache<K, V> {
fn default() -> Self {
DefaultCache { cache: Default::default() }
}
}
impl<K, V> QueryCache for DefaultCache<K, V>
where
2023-02-17 16:33:05 +00:00
K: Eq + Hash + Copy + Debug,
V: Copy,
{
type Key = K;
type Value = V;
#[inline(always)]
fn lookup(&self, key: &K) -> Option<(V, DepNodeIndex)> {
let key_hash = sharded::make_hash(key);
let lock = self.cache.lock_shard_by_hash(key_hash);
let result = lock.raw_entry().from_key_hashed_nocheck(key_hash, key);
if let Some((_, value)) = result { Some(*value) } else { None }
}
#[inline]
fn complete(&self, key: K, value: V, index: DepNodeIndex) {
let mut lock = self.cache.lock_shard_by_value(&key);
// We may be overwriting another value. This is all right, since the dep-graph
// will check that the fingerprint matches.
2023-02-15 22:18:40 +00:00
lock.insert(key, (value, index));
}
fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) {
2023-08-17 09:07:50 +00:00
for shard in self.cache.lock_shards() {
for (k, v) in shard.iter() {
f(k, &v.0, v.1);
}
}
}
}
2020-03-27 17:46:25 +00:00
pub struct SingleCache<V> {
2023-08-31 23:14:33 +00:00
cache: OnceLock<(V, DepNodeIndex)>,
}
impl<V> Default for SingleCache<V> {
fn default() -> Self {
2023-08-31 23:14:33 +00:00
SingleCache { cache: OnceLock::new() }
}
}
impl<V> QueryCache for SingleCache<V>
where
V: Copy,
{
type Key = ();
type Value = V;
#[inline(always)]
fn lookup(&self, _key: &()) -> Option<(V, DepNodeIndex)> {
2023-08-31 23:14:33 +00:00
self.cache.get().copied()
}
#[inline]
fn complete(&self, _key: (), value: V, index: DepNodeIndex) {
2023-08-31 23:14:33 +00:00
self.cache.set((value, index)).ok();
}
fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) {
2023-08-31 23:14:33 +00:00
if let Some(value) = self.cache.get() {
2023-04-09 21:07:18 +00:00
f(&(), &value.0, value.1)
}
}
}
pub struct DefIdCache<V> {
/// Stores the local DefIds in a dense map. Local queries are much more often dense, so this is
/// a win over hashing query keys at marginal memory cost (~5% at most) compared to FxHashMap.
local: VecCache<DefIndex, V, DepNodeIndex>,
foreign: DefaultCache<DefId, V>,
}
impl<V> Default for DefIdCache<V> {
fn default() -> Self {
DefIdCache { local: Default::default(), foreign: Default::default() }
}
}
impl<V> QueryCache for DefIdCache<V>
where
V: Copy,
{
type Key = DefId;
type Value = V;
#[inline(always)]
fn lookup(&self, key: &DefId) -> Option<(V, DepNodeIndex)> {
if key.krate == LOCAL_CRATE {
self.local.lookup(&key.index)
} else {
self.foreign.lookup(key)
}
}
#[inline]
fn complete(&self, key: DefId, value: V, index: DepNodeIndex) {
if key.krate == LOCAL_CRATE {
self.local.complete(key.index, value, index)
} else {
self.foreign.complete(key, value, index)
}
}
fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) {
self.local.iter(&mut |key, value, index| {
f(&DefId { krate: LOCAL_CRATE, index: *key }, value, index);
});
self.foreign.iter(f);
}
}
impl<K, V> QueryCache for VecCache<K, V, DepNodeIndex>
where
K: Idx + Eq + Hash + Copy + Debug,
V: Copy,
{
type Key = K;
type Value = V;
#[inline(always)]
fn lookup(&self, key: &K) -> Option<(V, DepNodeIndex)> {
self.lookup(key)
}
#[inline]
fn complete(&self, key: K, value: V, index: DepNodeIndex) {
self.complete(key, value, index)
}
fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) {
self.iter(f)
}
}