| //! 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 "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 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 | |
| //! uniquely identify a given commit. The fingerprinting approach has | |
| //! a few advantages: | |
| //! | |
| //! * A `DepNode` can simply be serialized to disk and loaded in another session | |
| //! without the need to do any "rebasing" (like we have to do for Spans and | |
| //! NodeIds) or "retracing" (like we had to do for `DefId` in earlier | |
| //! implementations of the dependency graph). | |
| //! * A `Fingerprint` is just a bunch of bits, which allows `DepNode` to | |
| //! implement `Copy`, `Sync`, `Send`, `Freeze`, etc. | |
| //! * Since we just have a bit pattern, `DepNode` can be mapped from disk into | |
| //! memory without any post-processing (e.g., "abomination-style" pointer | |
| //! reconstruction). | |
| //! * Because a `DepNode` is self-contained, we can instantiate `DepNodes` that | |
| //! refer to things that do not exist anymore. In previous implementations | |
| //! `DepNode` contained a `DefId`. A `DepNode` referring to something that | |
| //! had been removed between the previous and the current compilation session | |
| //! could not be instantiated because the current compilation session | |
| //! contained no `DefId` for thing that had been removed. | |
| //! | |
| //! `DepNode` definition happens in `rustc_middle` with the | |
| //! `define_dep_nodes!()` macro. This macro defines the `DepKind` enum. Each | |
| //! `DepKind` has its own parameters that are needed at runtime in order to | |
| //! construct a valid `DepNode` fingerprint. However, only `CompileCodegenUnit` | |
| //! and `CompileMonoItem` are constructed explicitly (with | |
| //! `make_compile_codegen_unit` and `make_compile_mono_item`). | |
| //! | |
| //! Because the macro sees what parameters a given `DepKind` requires, it can | |
| //! "infer" some properties for each kind of `DepNode`: | |
| //! | |
| //! * Whether a `DepNode` of a given kind has any parameters at all. Some | |
| //! `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 key fingerprint back to the | |
| //! `DefId` it was computed from. In other cases, too much information gets | |
| //! lost when computing a key fingerprint. | |
| //! | |
| //! [dependency graph]: https://rustc-dev-guide.rust-lang.org/query.html | |
| use std::fmt; | |
| use std::hash::Hash; | |
| use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint}; | |
| use rustc_data_structures::stable_hash::{StableHasher, StableOrd}; | |
| use rustc_hir::def_id::DefId; | |
| use rustc_hir::definitions::DefPathHash; | |
| use rustc_macros::{Decodable, Encodable, StableHash}; | |
| use rustc_span::Symbol; | |
| use super::{DepNodeIndex, KeyFingerprintStyle, SerializedDepNodeIndex}; | |
| use crate::dep_graph::DepNodeKey; | |
| use crate::mono::MonoItem; | |
| use crate::ty::{TyCtxt, tls}; | |
| // `enum DepKind` is generated by `define_dep_nodes!` below. | |
| impl DepKind { | |
| #[inline] | |
| pub(crate) fn from_u16(u: u16) -> Self { | |
| if u > Self::MAX { | |
| panic!("Invalid DepKind {u}"); | |
| } | |
| // SAFETY: `DepKind` is `repr(u16)`, its variants are `0..=MAX`, and `u` was checked | |
| // against `MAX` above. | |
| unsafe { std::mem::transmute(u) } | |
| } | |
| #[inline] | |
| pub(crate) const fn as_u16(&self) -> u16 { | |
| *self as u16 | |
| } | |
| #[inline] | |
| pub const fn as_usize(&self) -> usize { | |
| *self as usize | |
| } | |
| /// The number of dep kind variants. | |
| pub(crate) const NUM_VARIANTS: usize = std::mem::variant_count::<DepKind>(); | |
| /// This is the highest value a `DepKind` can have. It's used during encoding to | |
| /// pack information into the unused bits. u16 matches the `repr(u16)` on `DepKind`. | |
| pub(crate) const MAX: u16 = { | |
| let max = Self::NUM_VARIANTS - 1; | |
| assert!(max < u16::MAX as usize); | |
| max as u16 | |
| }; | |
| } | |
| /// 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, | |
| /// If `kind` is a query method, then its "key fingerprint" is always a | |
| /// stable hash of the query key. | |
| /// | |
| /// For non-query nodes, the content of this field varies: | |
| /// - Some dep kinds always use a dummy `ZERO` fingerprint. | |
| /// - Some dep kinds use the stable hash of some relevant key-like value. | |
| /// - Some dep kinds use the `with_anon_task` mechanism, and set their key | |
| /// fingerprint to a hash derived from the task's dependencies. | |
| /// | |
| /// In some cases the key value can be reconstructed from this fingerprint; | |
| /// see [`KeyFingerprintStyle`]. | |
| pub key_fingerprint: PackedFingerprint, | |
| } | |
| impl DepNode { | |
| /// Creates a new, parameterless DepNode. This method will assert | |
| /// 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.key_fingerprint_style(kind), KeyFingerprintStyle::Unit); | |
| DepNode { kind, key_fingerprint: Fingerprint::ZERO.into() } | |
| } | |
| pub fn construct<'tcx, Key>(tcx: TyCtxt<'tcx>, kind: DepKind, key: &Key) -> DepNode | |
| where | |
| Key: DepNodeKey<'tcx>, | |
| { | |
| DepNode { kind, key_fingerprint: key.to_fingerprint(tcx).into() } | |
| } | |
| /// 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>( | |
| tcx: TyCtxt<'tcx>, | |
| def_path_hash: DefPathHash, | |
| kind: DepKind, | |
| ) -> Self { | |
| debug_assert!(tcx.key_fingerprint_style(kind) == KeyFingerprintStyle::DefPathHash); | |
| DepNode { kind, key_fingerprint: def_path_hash.0.into() } | |
| } | |
| } | |
| impl fmt::Debug for DepNode { | |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| tls::with_opt(|opt_tcx| { | |
| if let Some(tcx) = opt_tcx | |
| && let Some(def_id) = self.extract_def_id(tcx) | |
| { | |
| write!(f, "{:?}({})", self.kind, tcx.def_path_debug_str(def_id))?; | |
| } else { | |
| write!(f, "{:?}({})", self.kind, self.key_fingerprint)?; | |
| } | |
| Ok(()) | |
| }) | |
| } | |
| } | |
| /// This struct stores function pointers and other metadata for a particular 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 DepKindVTable<'tcx> { | |
| /// 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, | |
| /// 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 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 | |
| /// 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 | |
| /// "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 | |
| /// 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 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. | |
| /// | |
| /// 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 `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_fn: Option< | |
| fn(tcx: TyCtxt<'tcx>, dep_node: DepNode, prev_index: SerializedDepNodeIndex) -> bool, | |
| >, | |
| /// Load the on-disk cached value of a query into memory. The node is known | |
| /// to be green, with `prev_index` its index in the previous session's dep | |
| /// graph and `dep_node_index` its index in the current session's dep graph. | |
| pub promote_from_disk_fn: Option< | |
| fn( | |
| tcx: TyCtxt<'tcx>, | |
| dep_node: DepNode, | |
| prev_index: SerializedDepNodeIndex, | |
| dep_node_index: DepNodeIndex, | |
| ), | |
| >, | |
| } | |
| /// 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 | |
| /// the need to be mapped or unmapped. (This ensures we can serialize | |
| /// them even in the absence of a tcx.) | |
| #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] | |
| #[derive(Encodable, Decodable, StableHash)] | |
| pub struct WorkProductId { | |
| hash: Fingerprint, | |
| } | |
| impl WorkProductId { | |
| pub fn from_cgu_name(cgu_name: &str) -> WorkProductId { | |
| let mut hasher = StableHasher::new(); | |
| cgu_name.hash(&mut hasher); | |
| WorkProductId { hash: hasher.finish() } | |
| } | |
| } | |
| impl StableOrd for WorkProductId { | |
| // Fingerprint can use unstable (just a tuple of `u64`s), so WorkProductId can as well | |
| const CAN_USE_UNSTABLE_SORT: bool = true; | |
| // `WorkProductId` sort order is not affected by (de)serialization. | |
| const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = (); | |
| } | |
| // Note: `$K` and `$V` are unused but present so this can be called by `rustc_with_all_queries`. | |
| macro_rules! define_dep_nodes { | |
| ( | |
| queries { | |
| $( | |
| $(#[$q_attr:meta])* | |
| fn $q_name:ident($K:ty) -> $V:ty | |
| // Search for (QMODLIST) to find all occurrences of this query modifier list. | |
| // Query modifiers are currently not used here, so skip the whole list. | |
| { $($modifiers:tt)* } | |
| )* | |
| } | |
| non_queries { | |
| $( | |
| $(#[$nq_attr:meta])* | |
| $nq_name:ident, | |
| )* | |
| } | |
| ) => { | |
| // This enum has more than u8::MAX variants so we need some kind of multi-byte | |
| // encoding. The derived Encodable/Decodable uses leb128 encoding which is | |
| // dense when only considering this enum. But DepKind is encoded in a larger | |
| // struct, and there we can take advantage of the unused bits in the u16. | |
| #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | |
| #[allow(non_camel_case_types)] | |
| #[repr(u16)] // Must be kept in sync with the rest of `DepKind`. | |
| pub enum DepKind { | |
| $( $(#[$nq_attr])* $nq_name, )* | |
| $( $(#[$q_attr])* $q_name, )* | |
| } | |
| /// Converts a string to a `DepKind`. Used for handling attributes like `rustc_clean` that | |
| /// name dep kinds. | |
| fn dep_kind_from_label_string(label: &str) -> Result<DepKind, ()> { | |
| match label { | |
| $( stringify!($nq_name) => Ok(self::DepKind::$nq_name), )* | |
| $( stringify!($q_name) => Ok(self::DepKind::$q_name), )* | |
| _ => Err(()), | |
| } | |
| } | |
| }; | |
| } | |
| // Create various data structures for each query, and also for a few things that aren't queries. | |
| crate::queries::rustc_with_all_queries! { define_dep_nodes! } | |
| // WARNING: `construct` is generic and does not know that `CompileCodegenUnit` takes `Symbol`s as keys. | |
| // Be very careful changing this type signature! | |
| pub(crate) fn make_compile_codegen_unit(tcx: TyCtxt<'_>, name: Symbol) -> DepNode { | |
| DepNode::construct(tcx, DepKind::CompileCodegenUnit, &name) | |
| } | |
| // WARNING: `construct` is generic and does not know that `CompileMonoItem` takes `MonoItem`s as keys. | |
| // Be very careful changing this type signature! | |
| pub(crate) fn make_compile_mono_item<'tcx>( | |
| tcx: TyCtxt<'tcx>, | |
| mono_item: &MonoItem<'tcx>, | |
| ) -> DepNode { | |
| DepNode::construct(tcx, DepKind::CompileMonoItem, mono_item) | |
| } | |
| // WARNING: `construct` is generic and does not know that `Metadata` takes `()`s as keys. | |
| // Be very careful changing this type signature! | |
| pub(crate) fn make_metadata(tcx: TyCtxt<'_>) -> DepNode { | |
| DepNode::construct(tcx, DepKind::Metadata, &()) | |
| } | |
| impl DepNode { | |
| /// Extracts the DefId corresponding to this DepNode. This will work | |
| /// if two conditions are met: | |
| /// | |
| /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and | |
| /// 2. the item that the DefPath refers to exists in the current tcx. | |
| /// | |
| /// Condition (1) is determined by the DepKind variant of the | |
| /// DepNode. Condition (2) might not be fulfilled if a 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.key_fingerprint_style(self.kind) == KeyFingerprintStyle::DefPathHash { | |
| tcx.def_path_hash_to_def_id(DefPathHash(self.key_fingerprint.into())) | |
| } else { | |
| None | |
| } | |
| } | |
| pub fn from_label_string( | |
| tcx: TyCtxt<'_>, | |
| label: &str, | |
| def_path_hash: DefPathHash, | |
| ) -> Result<DepNode, ()> { | |
| let kind = dep_kind_from_label_string(label)?; | |
| 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)) | |
| } | |
| } | |
| } | |
| pub fn has_label_string(label: &str) -> bool { | |
| dep_kind_from_label_string(label).is_ok() | |
| } | |
| } | |
| /// Maps a query label to its DepKind. Panics if a query with the given label does not exist. | |
| pub fn dep_kind_from_label(label: &str) -> DepKind { | |
| dep_kind_from_label_string(label) | |
| .unwrap_or_else(|_| panic!("Query label {label} does not exist")) | |
| } | |
| // Some types are used a lot. Make sure they don't unintentionally get bigger. | |
| #[cfg(target_pointer_width = "64")] | |
| mod size_asserts { | |
| use rustc_data_structures::static_assert_size; | |
| use super::*; | |
| // tidy-alphabetical-start | |
| static_assert_size!(DepKind, 2); | |
| static_assert_size!(DepNode, 18); | |
| // tidy-alphabetical-end | |
| } |