From 94a0819fe3a0d679c3042a77bfe6a2afc505daea Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:11:28 +0200 Subject: Adding upstream version 1.66.0+dfsg1. Signed-off-by: Daniel Baumann --- .../rustc_query_system/src/dep_graph/dep_node.rs | 73 ++++++++++++++++++++++ compiler/rustc_query_system/src/dep_graph/mod.rs | 45 ++++++++++--- 2 files changed, 111 insertions(+), 7 deletions(-) (limited to 'compiler/rustc_query_system/src/dep_graph') diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs index 162c274d8..5c6ce0556 100644 --- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs +++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs @@ -47,6 +47,7 @@ use crate::ich::StableHashingContext; use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_hir::definitions::DefPathHash; use std::fmt; use std::hash::Hash; @@ -88,6 +89,17 @@ impl DepNode { dep_node } + + /// Construct a DepNode from the given DepKind and DefPathHash. This + /// method will assert that the given DepKind actually requires a + /// single DefId/DefPathHash parameter. + pub fn from_def_path_hash(tcx: Ctxt, def_path_hash: DefPathHash, kind: K) -> Self + where + Ctxt: super::DepContext, + { + debug_assert!(tcx.fingerprint_style(kind) == FingerprintStyle::DefPathHash); + DepNode { kind, hash: def_path_hash.0.into() } + } } impl fmt::Debug for DepNode { @@ -149,6 +161,67 @@ where } } +/// This struct stores metadata about each DepKind. +/// +/// Information is retrieved by indexing the `DEP_KINDS` array using the integer value +/// of the `DepKind`. Overall, this allows to implement `DepContext` using this manual +/// jump table instead of large matches. +pub struct DepKindStruct { + /// Anonymous queries cannot be replayed from one compiler invocation to the next. + /// When their result is needed, it is recomputed. They are useful for fine-grained + /// dependency tracking, and caching within one compiler invocation. + pub is_anon: bool, + + /// Eval-always queries do not track their dependencies, and are always recomputed, even if + /// their inputs have not changed since the last compiler invocation. The result is still + /// cached within one compiler invocation. + pub is_eval_always: bool, + + /// Whether the query key can be recovered from the hashed fingerprint. + /// See [DepNodeParams] trait for the behaviour of each key type. + pub fingerprint_style: FingerprintStyle, + + /// The red/green evaluation system will try to mark a specific DepNode in the + /// dependency graph as green by recursively trying to mark the dependencies of + /// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode` + /// where we don't know if it is red or green and we therefore actually have + /// to recompute its value in order to find out. Since the only piece of + /// information that we have at that point is the `DepNode` we are trying to + /// re-evaluate, we need some way to re-run a query from just that. This is what + /// `force_from_dep_node()` implements. + /// + /// In the general case, a `DepNode` consists of a `DepKind` and an opaque + /// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint + /// is usually constructed by computing a stable hash of the query-key that the + /// `DepNode` corresponds to. Consequently, it is not in general possible to go + /// back from hash to query-key (since hash functions are not reversible). For + /// this reason `force_from_dep_node()` is expected to fail from time to time + /// because we just cannot find out, from the `DepNode` alone, what the + /// corresponding query-key is and therefore cannot re-run the query. + /// + /// The system deals with this case letting `try_mark_green` fail which forces + /// the root query to be re-evaluated. + /// + /// Now, if `force_from_dep_node()` would always fail, it would be pretty useless. + /// Fortunately, we can use some contextual information that will allow us to + /// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we + /// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a + /// valid `DefPathHash`. Since we also always build a huge table that maps every + /// `DefPathHash` in the current codebase to the corresponding `DefId`, we have + /// everything we need to re-run the query. + /// + /// Take the `mir_promoted` query as an example. Like many other queries, it + /// just has a single parameter: the `DefId` of the item it will compute the + /// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode` + /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode` + /// is actually a `DefPathHash`, and can therefore just look up the corresponding + /// `DefId` in `tcx.def_path_hash_to_def_id`. + pub force_from_dep_node: Option) -> bool>, + + /// Invoke a query to put the on-disk cached value in memory. + pub try_load_from_on_disk_cache: Option)>, +} + /// A "work product" corresponds to a `.o` (or other) file that we /// save in between runs. These IDs do not have a `DefId` but rather /// some independent path or string that persists between runs without diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index 342d95ca4..da2075fd5 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -4,7 +4,7 @@ mod graph; mod query; mod serialized; -pub use dep_node::{DepNode, DepNodeParams, WorkProductId}; +pub use dep_node::{DepKindStruct, DepNode, DepNodeParams, WorkProductId}; pub use graph::{ hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, TaskDepsRef, WorkProduct, }; @@ -34,16 +34,43 @@ pub trait DepContext: Copy { /// Access the compiler session. fn sess(&self) -> &Session; - /// Return whether this kind always require evaluation. - fn is_eval_always(&self, kind: Self::DepKind) -> bool; + fn dep_kind_info(&self, dep_node: Self::DepKind) -> &DepKindStruct; - fn fingerprint_style(&self, kind: Self::DepKind) -> FingerprintStyle; + #[inline(always)] + fn fingerprint_style(&self, kind: Self::DepKind) -> FingerprintStyle { + let data = self.dep_kind_info(kind); + if data.is_anon { + return FingerprintStyle::Opaque; + } + data.fingerprint_style + } + + #[inline(always)] + /// Return whether this kind always require evaluation. + fn is_eval_always(&self, kind: Self::DepKind) -> bool { + self.dep_kind_info(kind).is_eval_always + } /// Try to force a dep node to execute and see if it's green. - fn try_force_from_dep_node(&self, dep_node: DepNode) -> bool; + fn try_force_from_dep_node(self, dep_node: DepNode) -> bool { + debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node); + + let cb = self.dep_kind_info(dep_node.kind); + if let Some(f) = cb.force_from_dep_node { + f(self, dep_node); + true + } else { + false + } + } /// Load data from the on-disk cache. - fn try_load_from_on_disk_cache(&self, dep_node: DepNode); + fn try_load_from_on_disk_cache(self, dep_node: DepNode) { + let cb = self.dep_kind_info(dep_node.kind); + if let Some(f) = cb.try_load_from_on_disk_cache { + f(self, dep_node) + } + } } pub trait HasDepContext: Copy { @@ -67,6 +94,8 @@ impl HasDepContext for T { pub enum FingerprintStyle { /// The fingerprint is actually a DefPathHash. DefPathHash, + /// The fingerprint is actually a HirId. + HirId, /// Query key was `()` or equivalent, so fingerprint is just zero. Unit, /// Some opaque hash. @@ -77,7 +106,9 @@ impl FingerprintStyle { #[inline] pub fn reconstructible(self) -> bool { match self { - FingerprintStyle::DefPathHash | FingerprintStyle::Unit => true, + FingerprintStyle::DefPathHash | FingerprintStyle::Unit | FingerprintStyle::HirId => { + true + } FingerprintStyle::Opaque => false, } } -- cgit v1.2.3