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

This commit is contained in:
Zalathar 2026-02-17 18:22:25 +11:00
parent 8387095803
commit 9eaedddb7f
12 changed files with 193 additions and 161 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`.
@ -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)]
@ -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)]
@ -25,8 +25,8 @@ impl<'tcx> DepNodeKey<'tcx> for () {
impl<'tcx> DepNodeKey<'tcx> for DefId {
#[inline(always)]
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::DefPathHash
fn key_fingerprint_style() -> KeyFingerprintStyle {
KeyFingerprintStyle::DefPathHash
}
#[inline(always)]
@ -47,8 +47,8 @@ impl<'tcx> DepNodeKey<'tcx> for DefId {
impl<'tcx> DepNodeKey<'tcx> for LocalDefId {
#[inline(always)]
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::DefPathHash
fn key_fingerprint_style() -> KeyFingerprintStyle {
KeyFingerprintStyle::DefPathHash
}
#[inline(always)]
@ -69,8 +69,8 @@ impl<'tcx> DepNodeKey<'tcx> for LocalDefId {
impl<'tcx> DepNodeKey<'tcx> for OwnerId {
#[inline(always)]
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::DefPathHash
fn key_fingerprint_style() -> KeyFingerprintStyle {
KeyFingerprintStyle::DefPathHash
}
#[inline(always)]
@ -91,8 +91,8 @@ impl<'tcx> DepNodeKey<'tcx> for OwnerId {
impl<'tcx> DepNodeKey<'tcx> for CrateNum {
#[inline(always)]
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::DefPathHash
fn key_fingerprint_style() -> KeyFingerprintStyle {
KeyFingerprintStyle::DefPathHash
}
#[inline(always)]
@ -114,8 +114,8 @@ impl<'tcx> DepNodeKey<'tcx> for CrateNum {
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
@ -167,8 +167,8 @@ 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();
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)]
@ -206,8 +206,8 @@ impl<'tcx> DepNodeKey<'tcx> for ModDefId {
impl<'tcx> DepNodeKey<'tcx> for LocalModDefId {
#[inline(always)]
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::DefPathHash
fn key_fingerprint_style() -> KeyFingerprintStyle {
KeyFingerprintStyle::DefPathHash
}
#[inline(always)]

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

@ -397,7 +397,10 @@ 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)
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

View file

@ -46,6 +46,7 @@ unstalled = "unstalled" # short for un-stalled
#
# tidy-alphabetical-start
definitinon = "definition"
dependy = ""
similarlty = "similarity"
# tidy-alphabetical-end