use crate::dep_graph::DepKind;
use crate::ty::context::TyCtxt;
+use crate::ty::query::config::QueryContext;
use crate::ty::query::plumbing::CycleError;
use crate::ty::query::Query;
use crate::ty::tls;
/// Represents a span and a query key.
#[derive(Clone, Debug)]
-pub struct QueryInfo<'tcx> {
+pub struct QueryInfo<CTX: QueryContext> {
/// The span corresponding to the reason for which this query was required.
pub span: Span,
- pub query: Query<'tcx>,
+ pub query: CTX::Query,
}
-type QueryMap<'tcx> = FxHashMap<QueryJobId, QueryJobInfo<'tcx>>;
+type QueryMap<'tcx> = FxHashMap<QueryJobId, QueryJobInfo<TyCtxt<'tcx>>>;
/// A value uniquely identifiying an active query job within a shard in the query cache.
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
}
#[cfg(parallel_compiler)]
- fn latch<'a, 'tcx>(self, map: &'a QueryMap<'tcx>) -> Option<&'a QueryLatch<'tcx>> {
+ fn latch<'a, 'tcx>(self, map: &'a QueryMap<'tcx>) -> Option<&'a QueryLatch<TyCtxt<'tcx>>> {
map.get(&self).unwrap().job.latch.as_ref()
}
}
-pub struct QueryJobInfo<'tcx> {
- pub info: QueryInfo<'tcx>,
- pub job: QueryJob<'tcx>,
+pub struct QueryJobInfo<CTX: QueryContext> {
+ pub info: QueryInfo<CTX>,
+ pub job: QueryJob<CTX>,
}
/// Represents an active query job.
#[derive(Clone)]
-pub struct QueryJob<'tcx> {
+pub struct QueryJob<CTX: QueryContext> {
pub id: QueryShardJobId,
/// The span corresponding to the reason for which this query was required.
/// The latch that is used to wait on this job.
#[cfg(parallel_compiler)]
- latch: Option<QueryLatch<'tcx>>,
+ latch: Option<QueryLatch<CTX>>,
- dummy: PhantomData<QueryLatch<'tcx>>,
+ dummy: PhantomData<QueryLatch<CTX>>,
}
-impl<'tcx> QueryJob<'tcx> {
+impl<CTX: QueryContext> QueryJob<CTX> {
/// Creates a new query job.
pub fn new(id: QueryShardJobId, span: Span, parent: Option<QueryJobId>) -> Self {
QueryJob {
}
#[cfg(parallel_compiler)]
- pub(super) fn latch(&mut self, _id: QueryJobId) -> QueryLatch<'tcx> {
+ pub(super) fn latch(&mut self, _id: QueryJobId) -> QueryLatch<CTX> {
if self.latch.is_none() {
self.latch = Some(QueryLatch::new());
}
}
#[cfg(not(parallel_compiler))]
- pub(super) fn latch(&mut self, id: QueryJobId) -> QueryLatch<'tcx> {
+ pub(super) fn latch(&mut self, id: QueryJobId) -> QueryLatch<CTX> {
QueryLatch { id, dummy: PhantomData }
}
#[cfg(not(parallel_compiler))]
#[derive(Clone)]
-pub(super) struct QueryLatch<'tcx> {
+pub(super) struct QueryLatch<CTX> {
id: QueryJobId,
- dummy: PhantomData<&'tcx ()>,
+ dummy: PhantomData<CTX>,
}
#[cfg(not(parallel_compiler))]
-impl<'tcx> QueryLatch<'tcx> {
- pub(super) fn find_cycle_in_stack(&self, tcx: TyCtxt<'tcx>, span: Span) -> CycleError<'tcx> {
+impl<'tcx> QueryLatch<TyCtxt<'tcx>> {
+ pub(super) fn find_cycle_in_stack(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ span: Span,
+ ) -> CycleError<TyCtxt<'tcx>> {
let query_map = tcx.queries.try_collect_active_jobs().unwrap();
// Get the current executing query (waiter) and find the waitee amongst its parents
}
#[cfg(parallel_compiler)]
-struct QueryWaiter<'tcx> {
+struct QueryWaiter<CTX: QueryContext> {
query: Option<QueryJobId>,
condvar: Condvar,
span: Span,
- cycle: Lock<Option<CycleError<'tcx>>>,
+ cycle: Lock<Option<CycleError<CTX>>>,
}
#[cfg(parallel_compiler)]
-impl<'tcx> QueryWaiter<'tcx> {
+impl<CTX: QueryContext> QueryWaiter<CTX> {
fn notify(&self, registry: &rayon_core::Registry) {
rayon_core::mark_unblocked(registry);
self.condvar.notify_one();
}
#[cfg(parallel_compiler)]
-struct QueryLatchInfo<'tcx> {
+struct QueryLatchInfo<CTX: QueryContext> {
complete: bool,
- waiters: Vec<Lrc<QueryWaiter<'tcx>>>,
+ waiters: Vec<Lrc<QueryWaiter<CTX>>>,
}
#[cfg(parallel_compiler)]
#[derive(Clone)]
-pub(super) struct QueryLatch<'tcx> {
- info: Lrc<Mutex<QueryLatchInfo<'tcx>>>,
+pub(super) struct QueryLatch<CTX: QueryContext> {
+ info: Lrc<Mutex<QueryLatchInfo<CTX>>>,
}
#[cfg(parallel_compiler)]
-impl<'tcx> QueryLatch<'tcx> {
+impl<CTX: QueryContext> QueryLatch<CTX> {
fn new() -> Self {
QueryLatch {
info: Lrc::new(Mutex::new(QueryLatchInfo { complete: false, waiters: Vec::new() })),
}
}
+}
+#[cfg(parallel_compiler)]
+impl<'tcx> QueryLatch<TyCtxt<'tcx>> {
/// Awaits for the query job to complete.
- #[cfg(parallel_compiler)]
- pub(super) fn wait_on(&self, tcx: TyCtxt<'tcx>, span: Span) -> Result<(), CycleError<'tcx>> {
+ pub(super) fn wait_on(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ span: Span,
+ ) -> Result<(), CycleError<TyCtxt<'tcx>>> {
tls::with_related_context(tcx, move |icx| {
let waiter = Lrc::new(QueryWaiter {
query: icx.query,
}
})
}
+}
+#[cfg(parallel_compiler)]
+impl<CTX: QueryContext> QueryLatch<CTX> {
/// Awaits the caller on this latch by blocking the current thread.
- fn wait_on_inner(&self, waiter: &Lrc<QueryWaiter<'tcx>>) {
+ fn wait_on_inner(&self, waiter: &Lrc<QueryWaiter<CTX>>) {
let mut info = self.info.lock();
if !info.complete {
// We push the waiter on to the `waiters` list. It can be accessed inside
/// Removes a single waiter from the list of waiters.
/// This is used to break query cycles.
- fn extract_waiter(&self, waiter: usize) -> Lrc<QueryWaiter<'tcx>> {
+ fn extract_waiter(&self, waiter: usize) -> Lrc<QueryWaiter<CTX>> {
let mut info = self.info.lock();
debug_assert!(!info.complete);
// Remove the waiter from the list of waiters
fn remove_cycle<'tcx>(
query_map: &QueryMap<'tcx>,
jobs: &mut Vec<QueryJobId>,
- wakelist: &mut Vec<Lrc<QueryWaiter<'tcx>>>,
+ wakelist: &mut Vec<Lrc<QueryWaiter<TyCtxt<'tcx>>>>,
tcx: TyCtxt<'tcx>,
) -> bool {
let mut visited = FxHashSet::default();
use crate::dep_graph::{DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex};
use crate::ty::query::caches::QueryCache;
-use crate::ty::query::config::QueryDescription;
+use crate::ty::query::config::{QueryContext, QueryDescription};
use crate::ty::query::job::{QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryShardJobId};
use crate::ty::query::Query;
use crate::ty::tls;
#[cfg(debug_assertions)]
use std::sync::atomic::{AtomicUsize, Ordering};
-pub(crate) struct QueryStateShard<'tcx, K, C> {
+pub(crate) struct QueryStateShard<CTX: QueryContext, K, C> {
cache: C,
- active: FxHashMap<K, QueryResult<'tcx>>,
+ active: FxHashMap<K, QueryResult<CTX>>,
/// Used to generate unique ids for active jobs.
jobs: u32,
}
-impl<'tcx, K, C> QueryStateShard<'tcx, K, C> {
+impl<CTX: QueryContext, K, C> QueryStateShard<CTX, K, C> {
fn get_cache(&mut self) -> &mut C {
&mut self.cache
}
}
-impl<'tcx, K, C: Default> Default for QueryStateShard<'tcx, K, C> {
- fn default() -> QueryStateShard<'tcx, K, C> {
+impl<CTX: QueryContext, K, C: Default> Default for QueryStateShard<CTX, K, C> {
+ fn default() -> QueryStateShard<CTX, K, C> {
QueryStateShard { cache: Default::default(), active: Default::default(), jobs: 0 }
}
}
-pub(crate) struct QueryState<'tcx, C: QueryCache> {
+pub(crate) struct QueryState<CTX: QueryContext, C: QueryCache> {
cache: C,
- shards: Sharded<QueryStateShard<'tcx, C::Key, C::Sharded>>,
+ shards: Sharded<QueryStateShard<CTX, C::Key, C::Sharded>>,
#[cfg(debug_assertions)]
pub(super) cache_hits: AtomicUsize,
}
-impl<'tcx, C: QueryCache> QueryState<'tcx, C> {
+impl<CTX: QueryContext, C: QueryCache> QueryState<CTX, C> {
pub(super) fn get_lookup<K2: Hash>(
&'tcx self,
key: &K2,
- ) -> QueryLookup<'tcx, C::Key, C::Sharded> {
+ ) -> QueryLookup<'tcx, CTX, C::Key, C::Sharded> {
// We compute the key's hash once and then use it for both the
// shard lookup and the hashmap lookup. This relies on the fact
// that both of them use `FxHasher`.
}
/// Indicates the state of a query for a given key in a query map.
-enum QueryResult<'tcx> {
+enum QueryResult<CTX: QueryContext> {
/// An already executing query. The query job can be used to await for its completion.
- Started(QueryJob<'tcx>),
+ Started(QueryJob<CTX>),
/// The query panicked. Queries trying to wait on this will raise a fatal error which will
/// silently panic.
Poisoned,
}
-impl<'tcx, C: QueryCache> QueryState<'tcx, C> {
+impl<CTX: QueryContext, C: QueryCache> QueryState<CTX, C> {
pub(super) fn iter_results<R>(
&self,
f: impl for<'a> FnOnce(
pub(super) fn try_collect_active_jobs(
&self,
kind: DepKind,
- make_query: fn(C::Key) -> Query<'tcx>,
- jobs: &mut FxHashMap<QueryJobId, QueryJobInfo<'tcx>>,
+ make_query: fn(C::Key) -> CTX::Query,
+ jobs: &mut FxHashMap<QueryJobId, QueryJobInfo<CTX>>,
) -> Option<()>
where
C::Key: Clone,
}
}
-impl<'tcx, C: QueryCache> Default for QueryState<'tcx, C> {
- fn default() -> QueryState<'tcx, C> {
+impl<CTX: QueryContext, C: QueryCache> Default for QueryState<CTX, C> {
+ fn default() -> QueryState<CTX, C> {
QueryState {
cache: C::default(),
shards: Default::default(),
}
/// Values used when checking a query cache which can be reused on a cache-miss to execute the query.
-pub(crate) struct QueryLookup<'tcx, K, C> {
+pub(crate) struct QueryLookup<'tcx, CTX: QueryContext, K, C> {
pub(super) key_hash: u64,
shard: usize,
- pub(super) lock: LockGuard<'tcx, QueryStateShard<'tcx, K, C>>,
+ pub(super) lock: LockGuard<'tcx, QueryStateShard<CTX, K, C>>,
}
/// A type representing the responsibility to execute the job in the `job` field.
/// This will poison the relevant query if dropped.
-struct JobOwner<'tcx, C>
+struct JobOwner<'tcx, CTX: QueryContext, C>
where
C: QueryCache,
C::Key: Eq + Hash + Clone + Debug,
C::Value: Clone,
{
- state: &'tcx QueryState<'tcx, C>,
+ state: &'tcx QueryState<CTX, C>,
key: C::Key,
id: QueryJobId,
}
-impl<'tcx, C: QueryCache> JobOwner<'tcx, C>
+impl<'tcx, C: QueryCache> JobOwner<'tcx, TyCtxt<'tcx>, C>
where
C: QueryCache,
C::Key: Eq + Hash + Clone + Debug,
tcx: TyCtxt<'tcx>,
span: Span,
key: &C::Key,
- mut lookup: QueryLookup<'tcx, C::Key, C::Sharded>,
+ mut lookup: QueryLookup<'tcx, TyCtxt<'tcx>, C::Key, C::Sharded>,
) -> TryGetJob<'tcx, C>
where
Q: QueryDescription<'tcx, Key = C::Key, Value = C::Value, Cache = C>,
return TryGetJob::JobCompleted(cached);
}
}
+}
+impl<'tcx, CTX: QueryContext, C: QueryCache> JobOwner<'tcx, CTX, C>
+where
+ C: QueryCache,
+ C::Key: Eq + Hash + Clone + Debug,
+ C::Value: Clone,
+{
/// Completes the query by updating the query cache with the `result`,
/// signals the waiter and forgets the JobOwner, so it won't poison the query
#[inline(always)]
(result, diagnostics.into_inner())
}
-impl<'tcx, C: QueryCache> Drop for JobOwner<'tcx, C>
+impl<'tcx, CTX: QueryContext, C: QueryCache> Drop for JobOwner<'tcx, CTX, C>
where
C::Key: Eq + Hash + Clone + Debug,
C::Value: Clone,
}
#[derive(Clone)]
-pub(crate) struct CycleError<'tcx> {
+pub(crate) struct CycleError<CTX: QueryContext> {
/// The query and related span that uses the cycle.
- pub(super) usage: Option<(Span, Query<'tcx>)>,
- pub(super) cycle: Vec<QueryInfo<'tcx>>,
+ pub(super) usage: Option<(Span, CTX::Query)>,
+ pub(super) cycle: Vec<QueryInfo<CTX>>,
}
/// The result of `try_start`.
C::Value: Clone,
{
/// The query is not yet started. Contains a guard to the cache eventually used to start it.
- NotYetStarted(JobOwner<'tcx, C>),
+ NotYetStarted(JobOwner<'tcx, TyCtxt<'tcx>, C>),
/// The query was already completed.
/// Returns the result of the query and its dep-node index
Cycle(C::Value),
}
+impl QueryContext for TyCtxt<'tcx> {
+ type Query = Query<'tcx>;
+}
+
impl<'tcx> TyCtxt<'tcx> {
/// Executes a job by changing the `ImplicitCtxt` to point to the
/// new query job while it executes. It returns the diagnostics
#[cold]
pub(super) fn report_cycle(
self,
- CycleError { usage, cycle: stack }: CycleError<'tcx>,
+ CycleError { usage, cycle: stack }: CycleError<TyCtxt<'tcx>>,
) -> DiagnosticBuilder<'tcx> {
assert!(!stack.is_empty());
#[inline(always)]
fn try_get_cached<C, R, OnHit, OnMiss>(
self,
- state: &'tcx QueryState<'tcx, C>,
+ state: &'tcx QueryState<TyCtxt<'tcx>, C>,
key: C::Key,
// `on_hit` can be called while holding a lock to the query cache
on_hit: OnHit,
where
C: QueryCache,
OnHit: FnOnce(&C::Value, DepNodeIndex) -> R,
- OnMiss: FnOnce(C::Key, QueryLookup<'tcx, C::Key, C::Sharded>) -> R,
+ OnMiss: FnOnce(C::Key, QueryLookup<'tcx, TyCtxt<'tcx>, C::Key, C::Sharded>) -> R,
{
state.cache.lookup(
state,
- QueryStateShard::<C::Key, C::Sharded>::get_cache,
+ QueryStateShard::<TyCtxt<'tcx>, C::Key, C::Sharded>::get_cache,
key,
|value, index| {
if unlikely!(self.prof.enabled()) {
self,
span: Span,
key: Q::Key,
- lookup: QueryLookup<'tcx, Q::Key, <Q::Cache as QueryCache>::Sharded>,
+ lookup: QueryLookup<'tcx, TyCtxt<'tcx>, Q::Key, <Q::Cache as QueryCache>::Sharded>,
) -> Q::Value {
let job = match JobOwner::try_start::<Q>(self, span, &key, lookup) {
TryGetJob::NotYetStarted(job) => job,
fn force_query_with_job<Q: QueryDescription<'tcx> + 'tcx>(
self,
key: Q::Key,
- job: JobOwner<'tcx, Q::Cache>,
+ job: JobOwner<'tcx, TyCtxt<'tcx>, Q::Cache>,
dep_node: DepNode,
) -> (Q::Value, DepNodeIndex) {
// If the following assertion triggers, it can have two reasons:
const CATEGORY: ProfileCategory = $category;
}
- impl<$tcx> QueryAccessors<$tcx> for queries::$name<$tcx> {
+ impl<$tcx> QueryAccessors<TyCtxt<$tcx>> for queries::$name<$tcx> {
const ANON: bool = is_anon!([$($modifiers)*]);
const EVAL_ALWAYS: bool = is_eval_always!([$($modifiers)*]);
const DEP_KIND: dep_graph::DepKind = dep_graph::DepKind::$node;
type Cache = query_storage!([$($modifiers)*][$K, $V]);
#[inline(always)]
- fn query_state<'a>(tcx: TyCtxt<$tcx>) -> &'a QueryState<$tcx, Self::Cache> {
+ fn query_state<'a>(tcx: TyCtxt<$tcx>) -> &'a QueryState<TyCtxt<$tcx>, Self::Cache> {
&tcx.queries.$name
}
fn handle_cycle_error(
tcx: TyCtxt<'tcx>,
- error: CycleError<'tcx>
+ error: CycleError<TyCtxt<'tcx>>
) -> Self::Value {
handle_cycle_error!([$($modifiers)*][tcx, error])
}
fallback_extern_providers: Box<Providers<$tcx>>,
$($(#[$attr])* $name: QueryState<
- $tcx,
- <queries::$name<$tcx> as QueryAccessors<'tcx>>::Cache,
+ TyCtxt<$tcx>,
+ <queries::$name<$tcx> as QueryAccessors<TyCtxt<'tcx>>>::Cache,
>,)*
}
pub(crate) fn try_collect_active_jobs(
&self
- ) -> Option<FxHashMap<QueryJobId, QueryJobInfo<'tcx>>> {
+ ) -> Option<FxHashMap<QueryJobId, QueryJobInfo<TyCtxt<'tcx>>>> {
let mut jobs = FxHashMap::default();
$(
self.$name.try_collect_active_jobs(
- <queries::$name<'tcx> as QueryAccessors<'tcx>>::DEP_KIND,
+ <queries::$name<'tcx> as QueryAccessors<TyCtxt<'tcx>>>::DEP_KIND,
Query::$name,
&mut jobs,
)?;