Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add queries for LocalDefId <-> HirId conversion (take 2) #75641

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/librustc_middle/arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ macro_rules! arena_types {
[few] hir_definitions: rustc_hir::definitions::Definitions,
[] hir_owner: rustc_middle::hir::Owner<$tcx>,
[] hir_owner_nodes: rustc_middle::hir::OwnerNodes<$tcx>,
[] hir_owner_defs: rustc_data_structures::fx::FxHashMap<rustc_hir::ItemLocalId, rustc_span::def_id::LocalDefId>,

// Note that this deliberately duplicates items in the `rustc_hir::arena`,
// since we need to allocate this type on both the `rustc_hir` arena
Expand Down
12 changes: 1 addition & 11 deletions src/librustc_middle/dep_graph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,17 +122,7 @@ impl<'tcx> DepContext for TyCtxt<'tcx> {
);
}
} else {
// This `DefPath` does not have a
// corresponding `DepNode` (e.g. a
// struct field), and the ` DefPath`
// collided with the `DefPath` of a
// proper item that existed in the
// previous compilation session.
//
// Since the given `DefPath` does not
// denote the item that previously
// existed, we just fail to mark green.
return false;
bug!("DepNode {:?} collided (DefId {:?})", dep_node, def_id);
}
} else {
// If the node does not exist anymore, we
Expand Down
10 changes: 9 additions & 1 deletion src/librustc_middle/hir/map/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
hcx,
hir_body_nodes,
map: (0..definitions.def_index_count())
.map(|_| HirOwnerData { signature: None, with_bodies: None })
.map(|_| HirOwnerData { signature: None, with_bodies: None, defs: None })
.collect(),
};
collector.insert_entry(
Expand Down Expand Up @@ -229,6 +229,14 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
id.local_id,
ParentedNode { parent: entry.parent.local_id, node: entry.node },
);

// Check if this HirId has a DefId, and insert it in the `defs` map if so.
if let Some(def_id) = self.definitions.opt_hir_id_to_local_def_id(id) {
if data.defs.is_none() {
data.defs = Some(arena.alloc(FxHashMap::default()));
};
data.defs.as_mut().unwrap().insert(id.local_id, def_id);
}
}
}

Expand Down
13 changes: 10 additions & 3 deletions src/librustc_middle/hir/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::hir::{Owner, OwnerNodes};
use crate::ty::query::Providers;
use crate::ty::TyCtxt;
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::svh::Svh;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
Expand Down Expand Up @@ -89,6 +90,7 @@ fn is_body_owner<'hir>(node: Node<'hir>, hir_id: HirId) -> bool {
pub(super) struct HirOwnerData<'hir> {
pub(super) signature: Option<&'hir Owner<'hir>>,
pub(super) with_bodies: Option<&'hir mut OwnerNodes<'hir>>,
pub(super) defs: Option<&'hir mut FxHashMap<ItemLocalId, LocalDefId>>,
}

pub struct IndexedHir<'hir> {
Expand Down Expand Up @@ -170,17 +172,22 @@ impl<'hir> Map<'hir> {

#[inline]
pub fn opt_local_def_id(&self, hir_id: HirId) -> Option<LocalDefId> {
self.tcx.definitions.opt_hir_id_to_local_def_id(hir_id)
if hir_id.local_id == ItemLocalId::from_u32(0) {
// Every HirId owner has a DefId, so we can just return it directly here
Some(hir_id.owner)
} else {
self.tcx.hir_owner_defs(hir_id.owner).and_then(|map| map.get(&hir_id.local_id).copied())
}
}

#[inline]
pub fn local_def_id_to_hir_id(&self, def_id: LocalDefId) -> HirId {
self.tcx.definitions.local_def_id_to_hir_id(def_id)
self.tcx.local_def_id_to_hir_id(def_id).unwrap()
}

#[inline]
pub fn opt_local_def_id_to_hir_id(&self, def_id: LocalDefId) -> Option<HirId> {
self.tcx.definitions.opt_local_def_id_to_hir_id(def_id)
self.tcx.local_def_id_to_hir_id(def_id)
}

pub fn def_kind(&self, local_def_id: LocalDefId) -> DefKind {
Expand Down
3 changes: 3 additions & 0 deletions src/librustc_middle/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,5 +92,8 @@ pub fn provide(providers: &mut Providers) {
span_bug!(hir.span(hir_id), "fn_arg_names: unexpected item {:?}", id);
}
};
providers.local_def_id_to_hir_id = |tcx, id| tcx.definitions.opt_local_def_id_to_hir_id(id);
providers.hir_owner_defs =
|tcx, index| tcx.index_hir(LOCAL_CRATE).map[index].defs.as_ref().map(|defs| &**defs);
map::provide(providers);
}
18 changes: 18 additions & 0 deletions src/librustc_middle/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,24 @@ rustc_queries! {
desc { |tcx| "computing the optional const parameter of `{}`", tcx.def_path_str(key.to_def_id()) }
}

// Converts a `LocalDefId` to a `HirId`.
// This can be conveniently accessed by `tcx.hir().as_local_hir_id`.
// Avoid calling this query directly.
query local_def_id_to_hir_id(key: LocalDefId) -> Option<hir::HirId> {
storage(IndexVecCacheSelector)
eval_always
desc { "converting a LocalDefId to HirId" }
}

// A map of the HIR items which also have a `DefId` in addition to their `HirId`.
// This can be conveniently accessed by `tcx.hir().opt_local_def_id`.
// Avoid calling this query directly.
query hir_owner_defs(key: LocalDefId) -> Option<&'tcx FxHashMap<ItemLocalId, LocalDefId>> {
storage(IndexVecCacheSelector)
eval_always
desc { "getting a LocalDefId map" }
}

/// Records the type of every item.
query type_of(key: DefId) -> Ty<'tcx> {
desc { |tcx| "computing type of `{}`", tcx.def_path_str(key) }
Expand Down
99 changes: 95 additions & 4 deletions src/librustc_query_system/query/caches.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::dep_graph::DepNodeIndex;
use crate::query::config::QueryActiveStore;
use crate::query::plumbing::{QueryLookup, QueryState};
use crate::query::QueryContext;
use rustc_index::vec::{Idx, IndexVec};

use rustc_arena::TypedArena;
use rustc_data_structures::fx::FxHashMap;
Expand All @@ -27,6 +29,10 @@ pub trait QueryCache: QueryStorage {
type Key: Hash;
type Sharded: Default;

fn make_store<K, V>() -> QueryActiveStore<K, V> {
QueryActiveStore::Multi(Default::default())
}

/// Checks if the query is already computed and in the cache.
/// It returns the shard index and a lock guard to the shard,
/// which will be used if the query is not in the cache and we need
Expand Down Expand Up @@ -102,10 +108,10 @@ impl<K: Eq + Hash, V: Clone> QueryCache for DefaultCache<K, V> {
OnHit: FnOnce(&V, DepNodeIndex) -> R,
OnMiss: FnOnce(K, QueryLookup<'_, CTX, K, Self::Sharded>) -> R,
{
let mut lookup = state.get_lookup(&key);
let (mut lookup, key_hash) = state.get_lookup(&key, true);
let lock = &mut *lookup.lock;

let result = lock.cache.raw_entry().from_key_hashed_nocheck(lookup.key_hash, &key);
let result = lock.cache.raw_entry().from_key_hashed_nocheck(key_hash.unwrap(), &key);

if let Some((_, value)) = result { on_hit(&value.0, value.1) } else { on_miss(key, lookup) }
}
Expand Down Expand Up @@ -180,10 +186,10 @@ impl<'tcx, K: Eq + Hash, V: 'tcx> QueryCache for ArenaCache<'tcx, K, V> {
OnHit: FnOnce(&&'tcx V, DepNodeIndex) -> R,
OnMiss: FnOnce(K, QueryLookup<'_, CTX, K, Self::Sharded>) -> R,
{
let mut lookup = state.get_lookup(&key);
let (mut lookup, key_hash) = state.get_lookup(&key, true);
let lock = &mut *lookup.lock;

let result = lock.cache.raw_entry().from_key_hashed_nocheck(lookup.key_hash, &key);
let result = lock.cache.raw_entry().from_key_hashed_nocheck(key_hash.unwrap(), &key);

if let Some((_, value)) = result {
on_hit(&&value.0, value.1)
Expand Down Expand Up @@ -218,3 +224,88 @@ impl<'tcx, K: Eq + Hash, V: 'tcx> QueryCache for ArenaCache<'tcx, K, V> {
f(Box::new(results))
}
}

pub struct IndexVecCacheSelector;

impl<K: Eq + Hash, V: Clone> CacheSelector<K, V> for IndexVecCacheSelector {
type Cache = IndexVecCache<K, V>;
}

pub struct IndexVecCache<K, V>(PhantomData<(K, V)>);

impl<K, V> Default for IndexVecCache<K, V> {
fn default() -> Self {
IndexVecCache(PhantomData)
}
}

impl<K: Eq + Idx, V: Clone> QueryStorage for IndexVecCache<K, V> {
type Value = V;
type Stored = V;

#[inline]
fn store_nocache(&self, value: Self::Value) -> Self::Stored {
// We have no dedicated storage
value
}
}

impl<K: Eq + Idx, V: Clone> QueryCache for IndexVecCache<K, V> {
type Key = K;
type Sharded = IndexVec<K, Option<(K, V, DepNodeIndex)>>;

fn make_store<A, B>() -> QueryActiveStore<A, B> {
QueryActiveStore::Single(None)
}

#[inline(always)]
fn lookup<CTX: QueryContext, R, OnHit, OnMiss>(
&self,
state: &QueryState<CTX, Self>,
key: K,
on_hit: OnHit,
on_miss: OnMiss,
) -> R
where
OnHit: FnOnce(&V, DepNodeIndex) -> R,
OnMiss: FnOnce(K, QueryLookup<'_, CTX, K, Self::Sharded>) -> R,
{
let (mut lookup, _) = state.get_lookup(&key, false);
let lock = &mut *lookup.lock;

let result = lock.cache.get(key);

if let Some(Some(value)) = result {
on_hit(&value.1, value.2)
} else {
on_miss(key, lookup)
}
}

#[inline]
fn complete(
&self,
lock_sharded_storage: &mut Self::Sharded,
key: K,
value: V,
index: DepNodeIndex,
) -> Self::Stored {
lock_sharded_storage.ensure_contains_elem(key, || None);
lock_sharded_storage[key] = Some((key, value.clone(), index));
value
}

fn iter<R, L>(
&self,
shards: &Sharded<L>,
get_shard: impl Fn(&mut L) -> &mut Self::Sharded,
f: impl for<'a> FnOnce(Box<dyn Iterator<Item = (&'a K, &'a V, DepNodeIndex)> + 'a>) -> R,
) -> R {
let mut shards = shards.lock_shards();
let mut shards: Vec<_> = shards.iter_mut().map(|shard| get_shard(shard)).collect();
let results = shards.iter_mut().flat_map(|shard| {
shard.iter().flat_map(|v| v.as_ref().map(|val| (&val.0, &val.1, val.2)))
});
f(Box::new(results))
}
}
111 changes: 111 additions & 0 deletions src/librustc_query_system/query/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ use crate::dep_graph::SerializedDepNodeIndex;
use crate::query::caches::QueryCache;
use crate::query::plumbing::CycleError;
use crate::query::{QueryContext, QueryState};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::profiling::ProfileCategory;

use rustc_data_structures::fingerprint::Fingerprint;
use std::borrow::Cow;
use std::collections::hash_map::Entry;
use std::fmt::Debug;
use std::hash::Hash;

Expand Down Expand Up @@ -70,6 +72,115 @@ impl<CTX: QueryContext, K, V> QueryVtable<CTX, K, V> {
}
}

pub enum QueryActiveStore<K, V> {
Single(Option<(K, V)>),
Multi(FxHashMap<K, V>),
}

impl<K: Eq + Hash, V> QueryActiveStore<K, V> {
pub fn is_empty(&self) -> bool {
match self {
QueryActiveStore::Single(val) => val.is_none(),
QueryActiveStore::Multi(val) => val.is_empty(),
}
}
pub fn iter(&self) -> Box<dyn Iterator<Item = (&K, &V)> + '_> {
match self {
QueryActiveStore::Single(val) => {
Box::new(val.as_ref().map(|entry| (&entry.0, &entry.1)).into_iter())
}
QueryActiveStore::Multi(val) => Box::new(val.iter()),
}
}
pub fn get_or_insert<R>(
&mut self,
key: K,
present: impl FnOnce(&mut V) -> R,
absent: impl FnOnce() -> (V, R),
) -> R {
match self {
QueryActiveStore::Single(entry) => {
if let Some((_key, val)) = entry.as_mut() {
present(val)
} else {
let (val, res) = absent();
*entry = Some((key, val));
res
}
}
QueryActiveStore::Multi(map) => match map.entry(key) {
Entry::Occupied(mut entry) => present(entry.get_mut()),
Entry::Vacant(entry) => {
let (val, res) = absent();
entry.insert(val);
res
}
},
}
}
pub fn insert(&mut self, key: K, val: V) {
match self {
QueryActiveStore::Single(entry) => *entry = Some((key, val)),
QueryActiveStore::Multi(map) => {
map.insert(key, val);
}
}
}
pub fn remove(&mut self, key: &K) -> Option<V> {
match self {
QueryActiveStore::Single(entry) => entry.take().map(|(_k, v)| v),
QueryActiveStore::Multi(map) => map.remove(key),
}
}
}

/*pub trait QueryActiveStore<K: Eq + Hash, V> {
fn is_empty(&self) -> bool;
//fn iter(&self) -> Box<dyn Iterator<Item = (&K, &V)> + '_>;
fn get_or_insert<R>(&mut self, key: K, present: impl FnOnce(&mut V) -> R, absent: impl FnOnce() -> (V, R)) -> R;
fn remove(&mut self, key: &K);
}

impl<K: Eq + Hash, V> QueryActiveStore<K, V> for FxHashMap<K, V> {
fn is_empty(&self) -> bool { FxHashMap::is_empty(self) }
//fn iter(&self) -> Box<dyn Iterator<Item = (&K, &V)> + '_> { Box::new(FxHashMap::iter(self)) }
fn get_or_insert<R>(&mut self, key: K, present: impl FnOnce(&mut V) -> R, absent: impl FnOnce() -> (V, R)) -> R {
match self.entry(key) {
Entry::Occupied(mut entry) => {
present(entry.get_mut())
}
Entry::Vacant(entry) => {
let (val, res) = absent();
entry.insert(val);
res
}
}
}
fn remove(&mut self, key: &K) {
FxHashMap::remove(self, key);
}
}

impl<K: Eq + Hash, V> QueryActiveStore<K, V> for RefCell<Option<(K, V)>> {
fn is_empty(&self) -> bool { self.borrow().is_none() }
/*fn iter(&self) -> Box<dyn Iterator<Item = (&K, &V)> + '_> {
Box::new(self.borrow().as_ref().map(|val| (&val.0, &val.1)).into_iter())
}*/
fn get_or_insert<R>(&mut self, key: K, present: impl FnOnce(&mut V) -> R, absent: impl FnOnce() -> (V, R)) -> R {
let entry = &mut *self.borrow_mut();
if let Some((_key, val)) = entry {
present(val)
} else {
let (val, res) = absent();
*entry = Some((key, val));
res
}
}
fn remove(&mut self, key: &K) {
self.borrow_mut().take();
}
}*/

pub trait QueryAccessors<CTX: QueryContext>: QueryConfig<CTX> {
const ANON: bool;
const EVAL_ALWAYS: bool;
Expand Down
Loading