Rollup merge of #152751 - Zalathar:fingerprint, r=nnethercote

Rename dep node "fingerprints" to distinguish key and value hashes

In the query system's dependency graph, each node is associated with two *fingerprints*: one that is typically a hash of the query key, and one that is typically a hash of the query's return value when called with that key.

Unfortunately, many identifiers and comments fail to clearly distinguish between these two kinds of fingerprint, which have very different roles in dependency tracking. This is a frequent source of confusion.

This PR therefore tries to establish a clear distinction between:

- **Key fingerprints** that help to uniquely identify a node (along with its `DepKind`), and are typically a hash of the query key
- **Value fingerprints** that help to determine whether a node can be marked green (despite having red dependencies), and are typically a hash of the query value

There should be no change to compiler behaviour.

r? nnethercote (or compiler)
This commit is contained in:
Stuart Cook 2026-02-18 17:29:43 +11:00 committed by GitHub
commit 7312ac389f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 207 additions and 175 deletions

View file

@ -322,7 +322,7 @@ impl<'tcx> CleanVisitor<'tcx> {
if let Some(def_id) = dep_node.extract_def_id(self.tcx) {
format!("{:?}({})", dep_node.kind, self.tcx.def_path_str(def_id))
} else {
format!("{:?}({:?})", dep_node.kind, dep_node.hash)
format!("{:?}({:?})", dep_node.kind, dep_node.key_fingerprint)
}
}

View file

@ -1,10 +1,10 @@
//! This module defines the [`DepNode`] type which the compiler uses to represent
//! nodes in the [dependency graph]. A `DepNode` consists of a [`DepKind`] (which
//! specifies the kind of thing it represents, like a piece of HIR, MIR, etc.)
//! and a [`Fingerprint`], a 128-bit hash value, the exact meaning of which
//! depends on the node's `DepKind`. Together, the kind and the fingerprint
//! and a "key fingerprint", a 128-bit hash value, the exact meaning of which
//! depends on the node's `DepKind`. Together, the kind and the key fingerprint
//! fully identify a dependency node, even across multiple compilation sessions.
//! In other words, the value of the fingerprint does not depend on anything
//! In other words, the value of the key fingerprint does not depend on anything
//! that is specific to a given compilation session, like an unpredictable
//! interning key (e.g., `NodeId`, `DefId`, `Symbol`) or the numeric value of a
//! pointer. The concept behind this could be compared to how git commit hashes
@ -41,17 +41,9 @@
//! `DepNode`s could represent global concepts with only one value.
//! * Whether it is possible, in principle, to reconstruct a query key from a
//! given `DepNode`. Many `DepKind`s only require a single `DefId` parameter,
//! in which case it is possible to map the node's fingerprint back to the
//! in which case it is possible to map the node's key fingerprint back to the
//! `DefId` it was computed from. In other cases, too much information gets
//! lost during fingerprint computation.
//!
//! `make_compile_codegen_unit` and `make_compile_mono_items`, together with
//! `DepNode::new()`, ensure that only valid `DepNode` instances can be
//! constructed. For example, the API does not allow for constructing
//! parameterless `DepNode`s with anything other than a zeroed out fingerprint.
//! More generally speaking, it relieves the user of the `DepNode` API of
//! having to know how to compute the expected fingerprint for a given set of
//! node parameters.
//! lost when computing a key fingerprint.
//!
//! [dependency graph]: https://rustc-dev-guide.rust-lang.org/query.html
@ -65,7 +57,7 @@ use rustc_hir::definitions::DefPathHash;
use rustc_macros::{Decodable, Encodable};
use rustc_span::Symbol;
use super::{FingerprintStyle, SerializedDepNodeIndex};
use super::{KeyFingerprintStyle, SerializedDepNodeIndex};
use crate::ich::StableHashingContext;
use crate::mir::mono::MonoItem;
use crate::ty::{TyCtxt, tls};
@ -125,10 +117,20 @@ impl fmt::Debug for DepKind {
}
}
/// Combination of a [`DepKind`] and a key fingerprint that uniquely identifies
/// a node in the dep graph.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct DepNode {
pub kind: DepKind,
pub hash: PackedFingerprint,
/// This is _typically_ a hash of the query key, but sometimes not.
///
/// For example, `anon` nodes have a fingerprint that is derived from their
/// dependencies instead of a key.
///
/// In some cases the key value can be reconstructed from this fingerprint;
/// see [`KeyFingerprintStyle`].
pub key_fingerprint: PackedFingerprint,
}
impl DepNode {
@ -136,24 +138,23 @@ impl DepNode {
/// that the DepNode corresponding to the given DepKind actually
/// does not require any parameters.
pub fn new_no_params<'tcx>(tcx: TyCtxt<'tcx>, kind: DepKind) -> DepNode {
debug_assert_eq!(tcx.fingerprint_style(kind), FingerprintStyle::Unit);
DepNode { kind, hash: Fingerprint::ZERO.into() }
debug_assert_eq!(tcx.key_fingerprint_style(kind), KeyFingerprintStyle::Unit);
DepNode { kind, key_fingerprint: Fingerprint::ZERO.into() }
}
pub fn construct<'tcx, Key>(tcx: TyCtxt<'tcx>, kind: DepKind, arg: &Key) -> DepNode
pub fn construct<'tcx, Key>(tcx: TyCtxt<'tcx>, kind: DepKind, key: &Key) -> DepNode
where
Key: DepNodeKey<'tcx>,
{
let hash = arg.to_fingerprint(tcx);
let dep_node = DepNode { kind, hash: hash.into() };
let dep_node = DepNode { kind, key_fingerprint: key.to_fingerprint(tcx).into() };
#[cfg(debug_assertions)]
{
if !tcx.fingerprint_style(kind).reconstructible()
if !tcx.key_fingerprint_style(kind).reconstructible()
&& (tcx.sess.opts.unstable_opts.incremental_info
|| tcx.sess.opts.unstable_opts.query_dep_graph)
{
tcx.dep_graph.register_dep_node_debug_str(dep_node, || arg.to_debug_str(tcx));
tcx.dep_graph.register_dep_node_debug_str(dep_node, || key.to_debug_str(tcx));
}
}
@ -168,8 +169,8 @@ impl DepNode {
def_path_hash: DefPathHash,
kind: DepKind,
) -> Self {
debug_assert!(tcx.fingerprint_style(kind) == FingerprintStyle::DefPathHash);
DepNode { kind, hash: def_path_hash.0.into() }
debug_assert!(tcx.key_fingerprint_style(kind) == KeyFingerprintStyle::DefPathHash);
DepNode { kind, key_fingerprint: def_path_hash.0.into() }
}
}
@ -184,10 +185,10 @@ impl fmt::Debug for DepNode {
} else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*self) {
write!(f, "{s}")?;
} else {
write!(f, "{}", self.hash)?;
write!(f, "{}", self.key_fingerprint)?;
}
} else {
write!(f, "{}", self.hash)?;
write!(f, "{}", self.key_fingerprint)?;
}
Ok(())
})?;
@ -198,7 +199,7 @@ impl fmt::Debug for DepNode {
/// Trait for query keys as seen by dependency-node tracking.
pub trait DepNodeKey<'tcx>: fmt::Debug + Sized {
fn fingerprint_style() -> FingerprintStyle;
fn key_fingerprint_style() -> KeyFingerprintStyle;
/// This method turns a query key into an opaque `Fingerprint` to be used
/// in `DepNode`.
@ -212,7 +213,7 @@ pub trait DepNodeKey<'tcx>: fmt::Debug + Sized {
/// `fingerprint_style()` is not `FingerprintStyle::Opaque`.
/// It is always valid to return `None` here, in which case incremental
/// compilation will treat the query as having changed instead of forcing it.
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self>;
fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self>;
}
// Blanket impl of `DepNodeKey`, which is specialized by other impls elsewhere.
@ -221,8 +222,8 @@ where
T: for<'a> HashStable<StableHashingContext<'a>> + fmt::Debug,
{
#[inline(always)]
default fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::Opaque
default fn key_fingerprint_style() -> KeyFingerprintStyle {
KeyFingerprintStyle::Opaque
}
#[inline(always)]
@ -243,7 +244,7 @@ where
}
#[inline(always)]
default fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
default fn try_recover_key(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
None
}
}
@ -264,10 +265,11 @@ pub struct DepKindVTable<'tcx> {
/// cached within one compiler invocation.
pub is_eval_always: bool,
/// Indicates whether and how the query key can be recovered from its hashed fingerprint.
/// Indicates whether and how a query key can be reconstructed from the
/// key fingerprint of a dep node with this [`DepKind`].
///
/// The [`DepNodeKey`] trait determines the fingerprint style for each key type.
pub fingerprint_style: FingerprintStyle,
pub key_fingerprint_style: KeyFingerprintStyle,
/// 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
@ -279,7 +281,7 @@ pub struct DepKindVTable<'tcx> {
/// `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
/// "key fingerprint" that will uniquely identify the node. This key 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
@ -293,7 +295,7 @@ pub struct DepKindVTable<'tcx> {
/// 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
/// enforce by construction that the key 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.
@ -301,7 +303,7 @@ pub struct DepKindVTable<'tcx> {
/// 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`
/// with kind `mir_promoted`, we know that the key 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<
@ -472,8 +474,8 @@ impl DepNode {
/// refers to something from the previous compilation session that
/// has been removed.
pub fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
if tcx.fingerprint_style(self.kind) == FingerprintStyle::DefPathHash {
tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into()))
if tcx.key_fingerprint_style(self.kind) == KeyFingerprintStyle::DefPathHash {
tcx.def_path_hash_to_def_id(DefPathHash(self.key_fingerprint.into()))
} else {
None
}
@ -486,10 +488,10 @@ impl DepNode {
) -> Result<DepNode, ()> {
let kind = dep_kind_from_label_string(label)?;
match tcx.fingerprint_style(kind) {
FingerprintStyle::Opaque | FingerprintStyle::HirId => Err(()),
FingerprintStyle::Unit => Ok(DepNode::new_no_params(tcx, kind)),
FingerprintStyle::DefPathHash => {
match tcx.key_fingerprint_style(kind) {
KeyFingerprintStyle::Opaque | KeyFingerprintStyle::HirId => Err(()),
KeyFingerprintStyle::Unit => Ok(DepNode::new_no_params(tcx, kind)),
KeyFingerprintStyle::DefPathHash => {
Ok(DepNode::from_def_path_hash(tcx, def_path_hash, kind))
}
}

View file

@ -3,13 +3,13 @@ use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalModDefId,
use rustc_hir::definitions::DefPathHash;
use rustc_hir::{HirId, ItemLocalId, OwnerId};
use crate::dep_graph::{DepNode, DepNodeKey, FingerprintStyle};
use crate::dep_graph::{DepNode, DepNodeKey, KeyFingerprintStyle};
use crate::ty::TyCtxt;
impl<'tcx> DepNodeKey<'tcx> for () {
#[inline(always)]
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::Unit
fn key_fingerprint_style() -> KeyFingerprintStyle {
KeyFingerprintStyle::Unit
}
#[inline(always)]
@ -18,15 +18,15 @@ impl<'tcx> DepNodeKey<'tcx> for () {
}
#[inline(always)]
fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
fn try_recover_key(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
Some(())
}
}
impl<'tcx> DepNodeKey<'tcx> for DefId {
#[inline(always)]
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::DefPathHash
fn key_fingerprint_style() -> KeyFingerprintStyle {
KeyFingerprintStyle::DefPathHash
}
#[inline(always)]
@ -40,15 +40,15 @@ impl<'tcx> DepNodeKey<'tcx> for DefId {
}
#[inline(always)]
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
dep_node.extract_def_id(tcx)
}
}
impl<'tcx> DepNodeKey<'tcx> for LocalDefId {
#[inline(always)]
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::DefPathHash
fn key_fingerprint_style() -> KeyFingerprintStyle {
KeyFingerprintStyle::DefPathHash
}
#[inline(always)]
@ -62,15 +62,15 @@ impl<'tcx> DepNodeKey<'tcx> for LocalDefId {
}
#[inline(always)]
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
dep_node.extract_def_id(tcx).map(|id| id.expect_local())
}
}
impl<'tcx> DepNodeKey<'tcx> for OwnerId {
#[inline(always)]
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::DefPathHash
fn key_fingerprint_style() -> KeyFingerprintStyle {
KeyFingerprintStyle::DefPathHash
}
#[inline(always)]
@ -84,15 +84,15 @@ impl<'tcx> DepNodeKey<'tcx> for OwnerId {
}
#[inline(always)]
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
dep_node.extract_def_id(tcx).map(|id| OwnerId { def_id: id.expect_local() })
}
}
impl<'tcx> DepNodeKey<'tcx> for CrateNum {
#[inline(always)]
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::DefPathHash
fn key_fingerprint_style() -> KeyFingerprintStyle {
KeyFingerprintStyle::DefPathHash
}
#[inline(always)]
@ -107,15 +107,15 @@ impl<'tcx> DepNodeKey<'tcx> for CrateNum {
}
#[inline(always)]
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
dep_node.extract_def_id(tcx).map(|id| id.krate)
}
}
impl<'tcx> DepNodeKey<'tcx> for (DefId, DefId) {
#[inline(always)]
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::Opaque
fn key_fingerprint_style() -> KeyFingerprintStyle {
KeyFingerprintStyle::Opaque
}
// We actually would not need to specialize the implementation of this
@ -141,8 +141,8 @@ impl<'tcx> DepNodeKey<'tcx> for (DefId, DefId) {
impl<'tcx> DepNodeKey<'tcx> for HirId {
#[inline(always)]
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::HirId
fn key_fingerprint_style() -> KeyFingerprintStyle {
KeyFingerprintStyle::HirId
}
// We actually would not need to specialize the implementation of this
@ -166,9 +166,9 @@ impl<'tcx> DepNodeKey<'tcx> for HirId {
}
#[inline(always)]
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
if tcx.fingerprint_style(dep_node.kind) == FingerprintStyle::HirId {
let (local_hash, local_id) = Fingerprint::from(dep_node.hash).split();
fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
if tcx.key_fingerprint_style(dep_node.kind) == KeyFingerprintStyle::HirId {
let (local_hash, local_id) = Fingerprint::from(dep_node.key_fingerprint).split();
let def_path_hash = DefPathHash::new(tcx.stable_crate_id(LOCAL_CRATE), local_hash);
let def_id = tcx.def_path_hash_to_def_id(def_path_hash)?.expect_local();
let local_id = local_id
@ -184,8 +184,8 @@ impl<'tcx> DepNodeKey<'tcx> for HirId {
impl<'tcx> DepNodeKey<'tcx> for ModDefId {
#[inline(always)]
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::DefPathHash
fn key_fingerprint_style() -> KeyFingerprintStyle {
KeyFingerprintStyle::DefPathHash
}
#[inline(always)]
@ -199,15 +199,15 @@ impl<'tcx> DepNodeKey<'tcx> for ModDefId {
}
#[inline(always)]
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
DefId::recover(tcx, dep_node).map(ModDefId::new_unchecked)
fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
DefId::try_recover_key(tcx, dep_node).map(ModDefId::new_unchecked)
}
}
impl<'tcx> DepNodeKey<'tcx> for LocalModDefId {
#[inline(always)]
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::DefPathHash
fn key_fingerprint_style() -> KeyFingerprintStyle {
KeyFingerprintStyle::DefPathHash
}
#[inline(always)]
@ -221,7 +221,7 @@ impl<'tcx> DepNodeKey<'tcx> for LocalModDefId {
}
#[inline(always)]
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
LocalDefId::recover(tcx, dep_node).map(LocalModDefId::new_unchecked)
fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
LocalDefId::try_recover_key(tcx, dep_node).map(LocalModDefId::new_unchecked)
}
}

View file

@ -142,15 +142,17 @@ impl DepGraph {
// Instantiate a node with zero dependencies only once for anonymous queries.
let _green_node_index = current.alloc_new_node(
DepNode { kind: DepKind::ANON_ZERO_DEPS, hash: current.anon_id_seed.into() },
DepNode { kind: DepKind::ANON_ZERO_DEPS, key_fingerprint: current.anon_id_seed.into() },
EdgesVec::new(),
Fingerprint::ZERO,
);
assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_ZERO_DEPS_ANON_NODE);
// Instantiate a dependy-less red node only once for anonymous queries.
// Create a single always-red node, with no dependencies of its own.
// Other nodes can use the always-red node as a fake dependency, to
// ensure that their dependency list will never be all-green.
let red_node_index = current.alloc_new_node(
DepNode { kind: DepKind::RED, hash: Fingerprint::ZERO.into() },
DepNode { kind: DepKind::RED, key_fingerprint: Fingerprint::ZERO.into() },
EdgesVec::new(),
Fingerprint::ZERO,
);
@ -418,7 +420,7 @@ impl DepGraphData {
// Fingerprint::combine() is faster than sending Fingerprint
// through the StableHasher (at least as long as StableHasher
// is so slow).
hash: self.current.anon_id_seed.combine(hasher.finish()).into(),
key_fingerprint: self.current.anon_id_seed.combine(hasher.finish()).into(),
};
// The DepNodes generated by the process above are not unique. 2 queries could
@ -585,7 +587,7 @@ impl DepGraph {
data.current.record_edge(
dep_node_index,
node,
data.prev_fingerprint_of(prev_index),
data.prev_value_fingerprint_of(prev_index),
);
}
@ -658,8 +660,8 @@ impl DepGraphData {
}
#[inline]
pub fn prev_fingerprint_of(&self, prev_index: SerializedDepNodeIndex) -> Fingerprint {
self.previous.fingerprint_by_index(prev_index)
pub fn prev_value_fingerprint_of(&self, prev_index: SerializedDepNodeIndex) -> Fingerprint {
self.previous.value_fingerprint_for_index(prev_index)
}
#[inline]
@ -679,7 +681,7 @@ impl DepGraphData {
let dep_node_index = self.current.encoder.send_new(
DepNode {
kind: DepKind::SIDE_EFFECT,
hash: PackedFingerprint::from(Fingerprint::ZERO),
key_fingerprint: PackedFingerprint::from(Fingerprint::ZERO),
},
Fingerprint::ZERO,
// We want the side effect node to always be red so it will be forced and emit the
@ -712,7 +714,7 @@ impl DepGraphData {
&self.colors,
DepNode {
kind: DepKind::SIDE_EFFECT,
hash: PackedFingerprint::from(Fingerprint::ZERO),
key_fingerprint: PackedFingerprint::from(Fingerprint::ZERO),
},
Fingerprint::ZERO,
std::iter::once(DepNodeIndex::FOREVER_RED_NODE).collect(),
@ -727,12 +729,12 @@ impl DepGraphData {
&self,
key: DepNode,
edges: EdgesVec,
fingerprint: Option<Fingerprint>,
value_fingerprint: Option<Fingerprint>,
) -> DepNodeIndex {
if let Some(prev_index) = self.previous.node_to_index_opt(&key) {
// Determine the color and index of the new `DepNode`.
let is_green = if let Some(fingerprint) = fingerprint {
if fingerprint == self.previous.fingerprint_by_index(prev_index) {
let is_green = if let Some(value_fingerprint) = value_fingerprint {
if value_fingerprint == self.previous.value_fingerprint_for_index(prev_index) {
// This is a green node: it existed in the previous compilation,
// its query was re-executed, and it has the same result as before.
true
@ -749,22 +751,22 @@ impl DepGraphData {
false
};
let fingerprint = fingerprint.unwrap_or(Fingerprint::ZERO);
let value_fingerprint = value_fingerprint.unwrap_or(Fingerprint::ZERO);
let dep_node_index = self.current.encoder.send_and_color(
prev_index,
&self.colors,
key,
fingerprint,
value_fingerprint,
edges,
is_green,
);
self.current.record_node(dep_node_index, key, fingerprint);
self.current.record_node(dep_node_index, key, value_fingerprint);
dep_node_index
} else {
self.current.alloc_new_node(key, edges, fingerprint.unwrap_or(Fingerprint::ZERO))
self.current.alloc_new_node(key, edges, value_fingerprint.unwrap_or(Fingerprint::ZERO))
}
}
@ -781,7 +783,7 @@ impl DepGraphData {
self.current.record_edge(
dep_node_index,
*self.previous.index_to_node(prev_index),
self.previous.fingerprint_by_index(prev_index),
self.previous.value_fingerprint_for_index(prev_index),
);
}
@ -925,7 +927,7 @@ impl DepGraphData {
if !tcx.is_eval_always(dep_dep_node.kind) {
debug!(
"state of dependency {:?} ({}) is unknown, trying to mark it green",
dep_dep_node, dep_dep_node.hash,
dep_dep_node, dep_dep_node.key_fingerprint,
);
let node_index = self.try_mark_previous_green(tcx, parent_dep_node_index, Some(frame));
@ -1154,10 +1156,10 @@ pub(super) struct CurrentDepGraph {
encoder: GraphEncoder,
anon_node_to_index: ShardedHashMap<DepNode, DepNodeIndex>,
/// This is used to verify that fingerprints do not change between the creation of a node
/// and its recomputation.
/// This is used to verify that value fingerprints do not change between the
/// creation of a node and its recomputation.
#[cfg(debug_assertions)]
fingerprints: Lock<IndexVec<DepNodeIndex, Option<Fingerprint>>>,
value_fingerprints: Lock<IndexVec<DepNodeIndex, Option<Fingerprint>>>,
/// Used to trap when a specific edge is added to the graph.
/// This is used for debug purposes and is only active with `debug_assertions`.
@ -1224,7 +1226,7 @@ impl CurrentDepGraph {
#[cfg(debug_assertions)]
forbidden_edge,
#[cfg(debug_assertions)]
fingerprints: Lock::new(IndexVec::from_elem_n(None, new_node_count_estimate)),
value_fingerprints: Lock::new(IndexVec::from_elem_n(None, new_node_count_estimate)),
nodes_in_current_session: new_node_dbg.then(|| {
Lock::new(FxHashMap::with_capacity_and_hasher(
new_node_count_estimate,
@ -1237,12 +1239,20 @@ impl CurrentDepGraph {
}
#[cfg(debug_assertions)]
fn record_edge(&self, dep_node_index: DepNodeIndex, key: DepNode, fingerprint: Fingerprint) {
fn record_edge(
&self,
dep_node_index: DepNodeIndex,
key: DepNode,
value_fingerprint: Fingerprint,
) {
if let Some(forbidden_edge) = &self.forbidden_edge {
forbidden_edge.index_to_node.lock().insert(dep_node_index, key);
}
let previous = *self.fingerprints.lock().get_or_insert_with(dep_node_index, || fingerprint);
assert_eq!(previous, fingerprint, "Unstable fingerprints for {:?}", key);
let prior_value_fingerprint = *self
.value_fingerprints
.lock()
.get_or_insert_with(dep_node_index, || value_fingerprint);
assert_eq!(prior_value_fingerprint, value_fingerprint, "Unstable fingerprints for {key:?}");
}
#[inline(always)]
@ -1250,10 +1260,10 @@ impl CurrentDepGraph {
&self,
dep_node_index: DepNodeIndex,
key: DepNode,
_current_fingerprint: Fingerprint,
_value_fingerprint: Fingerprint,
) {
#[cfg(debug_assertions)]
self.record_edge(dep_node_index, key, _current_fingerprint);
self.record_edge(dep_node_index, key, _value_fingerprint);
if let Some(ref nodes_in_current_session) = self.nodes_in_current_session {
outline(|| {
@ -1271,11 +1281,11 @@ impl CurrentDepGraph {
&self,
key: DepNode,
edges: EdgesVec,
current_fingerprint: Fingerprint,
value_fingerprint: Fingerprint,
) -> DepNodeIndex {
let dep_node_index = self.encoder.send_new(key, current_fingerprint, edges);
let dep_node_index = self.encoder.send_new(key, value_fingerprint, edges);
self.record_node(dep_node_index, key, current_fingerprint);
self.record_node(dep_node_index, key, value_fingerprint);
dep_node_index
}

View file

@ -30,7 +30,7 @@ mod serialized;
/// This is mainly for determining whether and how we can reconstruct a key
/// from the fingerprint.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum FingerprintStyle {
pub enum KeyFingerprintStyle {
/// The fingerprint is actually a DefPathHash.
DefPathHash,
/// The fingerprint is actually a HirId.
@ -41,14 +41,14 @@ pub enum FingerprintStyle {
Opaque,
}
impl FingerprintStyle {
impl KeyFingerprintStyle {
#[inline]
pub const fn reconstructible(self) -> bool {
match self {
FingerprintStyle::DefPathHash | FingerprintStyle::Unit | FingerprintStyle::HirId => {
true
}
FingerprintStyle::Opaque => false,
KeyFingerprintStyle::DefPathHash
| KeyFingerprintStyle::Unit
| KeyFingerprintStyle::HirId => true,
KeyFingerprintStyle::Opaque => false,
}
}
}
@ -86,8 +86,8 @@ impl<'tcx> TyCtxt<'tcx> {
}
#[inline(always)]
pub fn fingerprint_style(self, kind: DepKind) -> FingerprintStyle {
self.dep_kind_vtable(kind).fingerprint_style
pub fn key_fingerprint_style(self, kind: DepKind) -> KeyFingerprintStyle {
self.dep_kind_vtable(kind).key_fingerprint_style
}
/// Try to force a dep node to execute and see if it's green.

View file

@ -90,9 +90,13 @@ const DEP_NODE_WIDTH_BITS: usize = DEP_NODE_SIZE / 2;
pub struct SerializedDepGraph {
/// The set of all DepNodes in the graph
nodes: IndexVec<SerializedDepNodeIndex, DepNode>,
/// The set of all Fingerprints in the graph. Each Fingerprint corresponds to
/// the DepNode at the same index in the nodes vector.
fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>,
/// A value fingerprint associated with each [`DepNode`] in [`Self::nodes`],
/// typically a hash of the value returned by the node's query in the
/// previous incremental-compilation session.
///
/// Some nodes don't have a meaningful value hash (e.g. queries with `no_hash`),
/// so they store a dummy value here instead (e.g. [`Fingerprint::ZERO`]).
value_fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>,
/// For each DepNode, stores the list of edges originating from that
/// DepNode. Encoded as a [start, end) pair indexing into edge_list_data,
/// which holds the actual DepNodeIndices of the target nodes.
@ -100,8 +104,8 @@ pub struct SerializedDepGraph {
/// A flattened list of all edge targets in the graph, stored in the same
/// varint encoding that we use on disk. Edge sources are implicit in edge_list_indices.
edge_list_data: Vec<u8>,
/// Stores a map from fingerprints to nodes per dep node kind.
/// This is the reciprocal of `nodes`.
/// For each dep kind, stores a map from key fingerprints back to the index
/// of the corresponding node. This is the inverse of `nodes`.
index: Vec<UnhashMap<PackedFingerprint, SerializedDepNodeIndex>>,
/// The number of previous compilation sessions. This is used to generate
/// unique anon dep nodes per session.
@ -138,12 +142,15 @@ impl SerializedDepGraph {
#[inline]
pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option<SerializedDepNodeIndex> {
self.index.get(dep_node.kind.as_usize())?.get(&dep_node.hash).cloned()
self.index.get(dep_node.kind.as_usize())?.get(&dep_node.key_fingerprint).copied()
}
#[inline]
pub fn fingerprint_by_index(&self, dep_node_index: SerializedDepNodeIndex) -> Fingerprint {
self.fingerprints[dep_node_index]
pub fn value_fingerprint_for_index(
&self,
dep_node_index: SerializedDepNodeIndex,
) -> Fingerprint {
self.value_fingerprints[dep_node_index]
}
#[inline]
@ -212,10 +219,13 @@ impl SerializedDepGraph {
let graph_bytes = d.len() - (3 * IntEncodedWithFixedSize::ENCODED_SIZE) - d.position();
let mut nodes = IndexVec::from_elem_n(
DepNode { kind: DepKind::NULL, hash: PackedFingerprint::from(Fingerprint::ZERO) },
DepNode {
kind: DepKind::NULL,
key_fingerprint: PackedFingerprint::from(Fingerprint::ZERO),
},
node_max,
);
let mut fingerprints = IndexVec::from_elem_n(Fingerprint::ZERO, node_max);
let mut value_fingerprints = IndexVec::from_elem_n(Fingerprint::ZERO, node_max);
let mut edge_list_indices =
IndexVec::from_elem_n(EdgeHeader { repr: 0, num_edges: 0 }, node_max);
@ -243,7 +253,7 @@ impl SerializedDepGraph {
assert!(node_header.node().kind != DepKind::NULL && node.kind == DepKind::NULL);
*node = node_header.node();
fingerprints[index] = node_header.fingerprint();
value_fingerprints[index] = node_header.value_fingerprint();
// If the length of this node's edge list is small, the length is stored in the header.
// If it is not, we fall back to another decoder call.
@ -275,7 +285,7 @@ impl SerializedDepGraph {
let session_count = d.read_u64();
for (idx, node) in nodes.iter_enumerated() {
if index[node.kind.as_usize()].insert(node.hash, idx).is_some() {
if index[node.kind.as_usize()].insert(node.key_fingerprint, idx).is_some() {
// Empty nodes and side effect nodes can have duplicates
if node.kind != DepKind::NULL && node.kind != DepKind::SIDE_EFFECT {
let name = node.kind.name();
@ -291,7 +301,7 @@ impl SerializedDepGraph {
Arc::new(SerializedDepGraph {
nodes,
fingerprints,
value_fingerprints,
edge_list_indices,
edge_list_data,
index,
@ -303,8 +313,8 @@ impl SerializedDepGraph {
/// A packed representation of all the fixed-size fields in a `NodeInfo`.
///
/// This stores in one byte array:
/// * The `Fingerprint` in the `NodeInfo`
/// * The `Fingerprint` in `DepNode` that is in this `NodeInfo`
/// * The value `Fingerprint` in the `NodeInfo`
/// * The key `Fingerprint` in `DepNode` that is in this `NodeInfo`
/// * The `DepKind`'s discriminant (a u16, but not all bits are used...)
/// * The byte width of the encoded edges for this node
/// * In whatever bits remain, the length of the edge list for this node, if it fits
@ -323,8 +333,8 @@ struct Unpacked {
bytes_per_index: usize,
kind: DepKind,
index: SerializedDepNodeIndex,
hash: PackedFingerprint,
fingerprint: Fingerprint,
key_fingerprint: PackedFingerprint,
value_fingerprint: Fingerprint,
}
// Bit fields, where
@ -345,7 +355,7 @@ impl SerializedNodeHeader {
fn new(
node: &DepNode,
index: DepNodeIndex,
fingerprint: Fingerprint,
value_fingerprint: Fingerprint,
edge_max_index: u32,
edge_count: usize,
) -> Self {
@ -363,19 +373,19 @@ impl SerializedNodeHeader {
head |= (edge_count as u16 + 1) << (Self::KIND_BITS + Self::WIDTH_BITS);
}
let hash: Fingerprint = node.hash.into();
let hash: Fingerprint = node.key_fingerprint.into();
// Using half-open ranges ensures an unconditional panic if we get the magic numbers wrong.
let mut bytes = [0u8; 38];
bytes[..2].copy_from_slice(&head.to_le_bytes());
bytes[2..6].copy_from_slice(&index.as_u32().to_le_bytes());
bytes[6..22].copy_from_slice(&hash.to_le_bytes());
bytes[22..].copy_from_slice(&fingerprint.to_le_bytes());
bytes[22..].copy_from_slice(&value_fingerprint.to_le_bytes());
#[cfg(debug_assertions)]
{
let res = Self { bytes };
assert_eq!(fingerprint, res.fingerprint());
assert_eq!(value_fingerprint, res.value_fingerprint());
assert_eq!(*node, res.node());
if let Some(len) = res.len() {
assert_eq!(edge_count, len as usize);
@ -388,8 +398,8 @@ impl SerializedNodeHeader {
fn unpack(&self) -> Unpacked {
let head = u16::from_le_bytes(self.bytes[..2].try_into().unwrap());
let index = u32::from_le_bytes(self.bytes[2..6].try_into().unwrap());
let hash = self.bytes[6..22].try_into().unwrap();
let fingerprint = self.bytes[22..].try_into().unwrap();
let key_fingerprint = self.bytes[6..22].try_into().unwrap();
let value_fingerprint = self.bytes[22..].try_into().unwrap();
let kind = head & mask(Self::KIND_BITS) as u16;
let bytes_per_index = (head >> Self::KIND_BITS) & mask(Self::WIDTH_BITS) as u16;
@ -400,8 +410,8 @@ impl SerializedNodeHeader {
bytes_per_index: bytes_per_index as usize + 1,
kind: DepKind::new(kind),
index: SerializedDepNodeIndex::from_u32(index),
hash: Fingerprint::from_le_bytes(hash).into(),
fingerprint: Fingerprint::from_le_bytes(fingerprint),
key_fingerprint: Fingerprint::from_le_bytes(key_fingerprint).into(),
value_fingerprint: Fingerprint::from_le_bytes(value_fingerprint),
}
}
@ -421,14 +431,14 @@ impl SerializedNodeHeader {
}
#[inline]
fn fingerprint(&self) -> Fingerprint {
self.unpack().fingerprint
fn value_fingerprint(&self) -> Fingerprint {
self.unpack().value_fingerprint
}
#[inline]
fn node(&self) -> DepNode {
let Unpacked { kind, hash, .. } = self.unpack();
DepNode { kind, hash }
let Unpacked { kind, key_fingerprint, .. } = self.unpack();
DepNode { kind, key_fingerprint }
}
#[inline]
@ -443,15 +453,20 @@ impl SerializedNodeHeader {
#[derive(Debug)]
struct NodeInfo {
node: DepNode,
fingerprint: Fingerprint,
value_fingerprint: Fingerprint,
edges: EdgesVec,
}
impl NodeInfo {
fn encode(&self, e: &mut MemEncoder, index: DepNodeIndex) {
let NodeInfo { ref node, fingerprint, ref edges } = *self;
let header =
SerializedNodeHeader::new(node, index, fingerprint, edges.max_index(), edges.len());
let NodeInfo { ref node, value_fingerprint, ref edges } = *self;
let header = SerializedNodeHeader::new(
node,
index,
value_fingerprint,
edges.max_index(),
edges.len(),
);
e.write_array(header.bytes);
if header.len().is_none() {
@ -476,7 +491,7 @@ impl NodeInfo {
e: &mut MemEncoder,
node: &DepNode,
index: DepNodeIndex,
fingerprint: Fingerprint,
value_fingerprint: Fingerprint,
prev_index: SerializedDepNodeIndex,
colors: &DepNodeColorMap,
previous: &SerializedDepGraph,
@ -488,7 +503,8 @@ impl NodeInfo {
let edge_max =
edges.clone().map(|i| colors.current(i).unwrap().as_u32()).max().unwrap_or(0);
let header = SerializedNodeHeader::new(node, index, fingerprint, edge_max, edge_count);
let header =
SerializedNodeHeader::new(node, index, value_fingerprint, edge_max, edge_count);
e.write_array(header.bytes);
if header.len().is_none() {
@ -676,12 +692,12 @@ impl EncoderState {
local: &mut LocalEncoderState,
) {
let node = self.previous.index_to_node(prev_index);
let fingerprint = self.previous.fingerprint_by_index(prev_index);
let value_fingerprint = self.previous.value_fingerprint_for_index(prev_index);
let edge_count = NodeInfo::encode_promoted(
&mut local.encoder,
node,
index,
fingerprint,
value_fingerprint,
prev_index,
colors,
&self.previous,
@ -857,11 +873,11 @@ impl GraphEncoder {
pub(crate) fn send_new(
&self,
node: DepNode,
fingerprint: Fingerprint,
value_fingerprint: Fingerprint,
edges: EdgesVec,
) -> DepNodeIndex {
let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph");
let node = NodeInfo { node, fingerprint, edges };
let node = NodeInfo { node, value_fingerprint, edges };
let mut local = self.status.local.borrow_mut();
let index = self.status.next_index(&mut *local);
self.status.bump_index(&mut *local);
@ -877,12 +893,12 @@ impl GraphEncoder {
prev_index: SerializedDepNodeIndex,
colors: &DepNodeColorMap,
node: DepNode,
fingerprint: Fingerprint,
value_fingerprint: Fingerprint,
edges: EdgesVec,
is_green: bool,
) -> DepNodeIndex {
let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph");
let node = NodeInfo { node, fingerprint, edges };
let node = NodeInfo { node, value_fingerprint, edges };
let mut local = self.status.local.borrow_mut();

View file

@ -67,7 +67,7 @@ where
#[inline]
fn complete(&self, key: K, value: V, index: DepNodeIndex) {
// We may be overwriting another value. This is all right, since the dep-graph
// will check that the fingerprint matches.
// will check that the value fingerprint matches.
self.cache.insert(key, (value, index));
}

View file

@ -25,7 +25,7 @@ pub fn incremental_verify_ich<'tcx, V>(
tcx.with_stable_hashing_context(|mut hcx| f(&mut hcx, result))
});
let old_hash = dep_graph_data.prev_fingerprint_of(prev_index);
let old_hash = dep_graph_data.prev_value_fingerprint_of(prev_index);
if new_hash != old_hash {
incremental_verify_ich_failed(tcx, prev_index, &|| format_value(result));

View file

@ -1,5 +1,5 @@
use rustc_middle::bug;
use rustc_middle::dep_graph::{DepKindVTable, DepNodeKey, FingerprintStyle};
use rustc_middle::dep_graph::{DepKindVTable, DepNodeKey, KeyFingerprintStyle};
use rustc_middle::query::QueryCache;
use crate::plumbing::{force_from_dep_node_inner, try_load_from_on_disk_cache_inner};
@ -15,7 +15,7 @@ mod non_query {
DepKindVTable {
is_anon: false,
is_eval_always: false,
fingerprint_style: FingerprintStyle::Unit,
key_fingerprint_style: KeyFingerprintStyle::Unit,
force_from_dep_node: Some(|_, dep_node, _| {
bug!("force_from_dep_node: encountered {dep_node:?}")
}),
@ -29,7 +29,7 @@ mod non_query {
DepKindVTable {
is_anon: false,
is_eval_always: false,
fingerprint_style: FingerprintStyle::Unit,
key_fingerprint_style: KeyFingerprintStyle::Unit,
force_from_dep_node: Some(|_, dep_node, _| {
bug!("force_from_dep_node: encountered {dep_node:?}")
}),
@ -42,7 +42,7 @@ mod non_query {
DepKindVTable {
is_anon: false,
is_eval_always: false,
fingerprint_style: FingerprintStyle::Unit,
key_fingerprint_style: KeyFingerprintStyle::Unit,
force_from_dep_node: Some(|tcx, _, prev_index| {
tcx.dep_graph.force_diagnostic_node(tcx, prev_index);
true
@ -56,7 +56,7 @@ mod non_query {
DepKindVTable {
is_anon: true,
is_eval_always: false,
fingerprint_style: FingerprintStyle::Opaque,
key_fingerprint_style: KeyFingerprintStyle::Opaque,
force_from_dep_node: Some(|_, _, _| bug!("cannot force an anon node")),
try_load_from_on_disk_cache: None,
name: &"AnonZeroDeps",
@ -67,7 +67,7 @@ mod non_query {
DepKindVTable {
is_anon: true,
is_eval_always: false,
fingerprint_style: FingerprintStyle::Unit,
key_fingerprint_style: KeyFingerprintStyle::Unit,
force_from_dep_node: None,
try_load_from_on_disk_cache: None,
name: &"TraitSelect",
@ -78,7 +78,7 @@ mod non_query {
DepKindVTable {
is_anon: false,
is_eval_always: false,
fingerprint_style: FingerprintStyle::Opaque,
key_fingerprint_style: KeyFingerprintStyle::Opaque,
force_from_dep_node: None,
try_load_from_on_disk_cache: None,
name: &"CompileCodegenUnit",
@ -89,7 +89,7 @@ mod non_query {
DepKindVTable {
is_anon: false,
is_eval_always: false,
fingerprint_style: FingerprintStyle::Opaque,
key_fingerprint_style: KeyFingerprintStyle::Opaque,
force_from_dep_node: None,
try_load_from_on_disk_cache: None,
name: &"CompileMonoItem",
@ -100,7 +100,7 @@ mod non_query {
DepKindVTable {
is_anon: false,
is_eval_always: false,
fingerprint_style: FingerprintStyle::Unit,
key_fingerprint_style: KeyFingerprintStyle::Unit,
force_from_dep_node: None,
try_load_from_on_disk_cache: None,
name: &"Metadata",
@ -118,17 +118,17 @@ where
Cache: QueryCache + 'tcx,
{
let is_anon = FLAGS.is_anon;
let fingerprint_style = if is_anon {
FingerprintStyle::Opaque
let key_fingerprint_style = if is_anon {
KeyFingerprintStyle::Opaque
} else {
<Cache::Key as DepNodeKey<'tcx>>::fingerprint_style()
<Cache::Key as DepNodeKey<'tcx>>::key_fingerprint_style()
};
if is_anon || !fingerprint_style.reconstructible() {
if is_anon || !key_fingerprint_style.reconstructible() {
return DepKindVTable {
is_anon,
is_eval_always,
fingerprint_style,
key_fingerprint_style,
force_from_dep_node: None,
try_load_from_on_disk_cache: None,
name: Q::NAME,
@ -138,7 +138,7 @@ where
DepKindVTable {
is_anon,
is_eval_always,
fingerprint_style,
key_fingerprint_style,
force_from_dep_node: Some(|tcx, dep_node, _| {
force_from_dep_node_inner(Q::query_dispatcher(tcx), tcx, dep_node)
}),

View file

@ -509,7 +509,7 @@ fn try_load_from_disk_and_cache_in_memory<'tcx, C: QueryCache, const FLAGS: Quer
dep_graph_data.mark_debug_loaded_from_disk(*dep_node)
}
let prev_fingerprint = dep_graph_data.prev_fingerprint_of(prev_dep_node_index);
let prev_fingerprint = dep_graph_data.prev_value_fingerprint_of(prev_dep_node_index);
// If `-Zincremental-verify-ich` is specified, re-hash results from
// the cache and make sure that they have the expected fingerprint.
//
@ -538,7 +538,7 @@ fn try_load_from_disk_and_cache_in_memory<'tcx, C: QueryCache, const FLAGS: Quer
// can be forced from `DepNode`.
debug_assert!(
!query.will_cache_on_disk_for_key(tcx, key)
|| !tcx.fingerprint_style(dep_node.kind).reconstructible(),
|| !tcx.key_fingerprint_style(dep_node.kind).reconstructible(),
"missing on-disk cache entry for {dep_node:?}"
);

View file

@ -396,8 +396,11 @@ pub(crate) fn try_load_from_on_disk_cache_inner<'tcx, C: QueryCache, const FLAGS
) {
debug_assert!(tcx.dep_graph.is_green(&dep_node));
let key = C::Key::recover(tcx, &dep_node).unwrap_or_else(|| {
panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash)
let key = C::Key::try_recover_key(tcx, &dep_node).unwrap_or_else(|| {
panic!(
"Failed to recover key for {dep_node:?} with key fingerprint {}",
dep_node.key_fingerprint
)
});
if query.will_cache_on_disk_for_key(tcx, &key) {
// Call `tcx.$query(key)` for its side-effect of loading the disk-cached
@ -462,7 +465,7 @@ pub(crate) fn force_from_dep_node_inner<'tcx, C: QueryCache, const FLAGS: QueryF
"calling force_from_dep_node() on dep_kinds::codegen_unit"
);
if let Some(key) = C::Key::recover(tcx, &dep_node) {
if let Some(key) = C::Key::try_recover_key(tcx, &dep_node) {
force_query(query, tcx, key, dep_node);
true
} else {