From f64cd87ca6169f118bad20ee23acced0e67cc6ea Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 8 Jan 2022 18:22:06 -0500 Subject: [PATCH] Introduce new `TaskDepsRef` enum to track allow/ignore/forbid status --- compiler/rustc_middle/src/dep_graph/mod.rs | 6 +- compiler/rustc_middle/src/ty/context.rs | 12 +- .../rustc_query_system/src/dep_graph/graph.rs | 123 ++++++++++-------- .../rustc_query_system/src/dep_graph/mod.rs | 9 +- 4 files changed, 88 insertions(+), 62 deletions(-) diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index 79d7ca32f35..cf50378ad60 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -1,6 +1,5 @@ use crate::ty::{self, TyCtxt}; use rustc_data_structures::profiling::SelfProfilerRef; -use rustc_data_structures::sync::Lock; use rustc_query_system::ich::StableHashingContext; use rustc_session::Session; @@ -17,6 +16,7 @@ crate use dep_node::{make_compile_codegen_unit, make_compile_mono_item}; pub type DepGraph = rustc_query_system::dep_graph::DepGraph; pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps; +pub type TaskDepsRef<'a> = rustc_query_system::dep_graph::TaskDepsRef<'a, DepKind>; pub type DepGraphQuery = rustc_query_system::dep_graph::DepGraphQuery; pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph; pub type EdgeFilter = rustc_query_system::dep_graph::debug::EdgeFilter; @@ -45,7 +45,7 @@ impl rustc_query_system::dep_graph::DepKind for DepKind { write!(f, ")") } - fn with_deps(task_deps: Option<&Lock>, op: OP) -> R + fn with_deps(task_deps: TaskDepsRef<'_>, op: OP) -> R where OP: FnOnce() -> R, { @@ -58,7 +58,7 @@ impl rustc_query_system::dep_graph::DepKind for DepKind { fn read_deps(op: OP) where - OP: for<'a> FnOnce(Option<&'a Lock>), + OP: for<'a> FnOnce(TaskDepsRef<'a>), { ty::tls::with_context_opt(|icx| { let icx = if let Some(icx) = icx { icx } else { return }; diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index dd571e29bf6..7c863efcfdf 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1661,7 +1661,7 @@ CloneLiftImpls! { for<'tcx> { Constness, traits::WellFormedLoc, } } pub mod tls { use super::{ptr_eq, GlobalCtxt, TyCtxt}; - use crate::dep_graph::{DepKind, TaskDeps}; + use crate::dep_graph::{DepKind, TaskDepsRef}; use crate::ty::query; use rustc_data_structures::sync::{self, Lock}; use rustc_data_structures::thin_vec::ThinVec; @@ -1697,13 +1697,19 @@ pub mod tls { /// The current dep graph task. This is used to add dependencies to queries /// when executing them. - pub task_deps: Option<&'a Lock>, + pub task_deps: TaskDepsRef<'a>, } impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> { pub fn new(gcx: &'tcx GlobalCtxt<'tcx>) -> Self { let tcx = TyCtxt { gcx }; - ImplicitCtxt { tcx, query: None, diagnostics: None, layout_depth: 0, task_deps: None } + ImplicitCtxt { + tcx, + query: None, + diagnostics: None, + layout_depth: 0, + task_deps: TaskDepsRef::Ignore, + } } } diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 7c96f68ffb3..a080b4a3e9a 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -9,6 +9,7 @@ use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering}; use rustc_index::vec::IndexVec; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use smallvec::{smallvec, SmallVec}; +use std::assert_matches::assert_matches; use std::collections::hash_map::Entry; use std::fmt::Debug; use std::hash::Hash; @@ -165,7 +166,11 @@ impl DepGraph { pub fn assert_ignored(&self) { if let Some(..) = self.data { K::read_deps(|task_deps| { - assert!(task_deps.is_none(), "expected no task dependency tracking"); + assert_matches!( + task_deps, + TaskDepsRef::Ignore, + "expected no task dependency tracking" + ); }) } } @@ -174,7 +179,7 @@ impl DepGraph { where OP: FnOnce() -> R, { - K::with_deps(None, op) + K::with_deps(TaskDepsRef::Ignore, op) } /// Used to wrap the deserialization of a query result from disk, @@ -227,10 +232,7 @@ impl DepGraph { where OP: FnOnce() -> R, { - let mut deps = TaskDeps::default(); - deps.read_allowed = false; - let deps = Lock::new(deps); - K::with_deps(Some(&deps), op) + K::with_deps(TaskDepsRef::Forbid, op) } /// Starts a new dep-graph task. Dep-graph tasks are specified @@ -313,10 +315,15 @@ impl DepGraph { reads: SmallVec::new(), read_set: Default::default(), phantom_data: PhantomData, - read_allowed: true, })) }; - let result = K::with_deps(task_deps.as_ref(), || task(cx, arg)); + + let task_deps_ref = match &task_deps { + Some(deps) => TaskDepsRef::Allow(deps), + None => TaskDepsRef::Ignore, + }; + + let result = K::with_deps(task_deps_ref, || task(cx, arg)); let edges = task_deps.map_or_else(|| smallvec![], |lock| lock.into_inner().reads); let dcx = cx.dep_context(); @@ -369,7 +376,7 @@ impl DepGraph { if let Some(ref data) = self.data { let task_deps = Lock::new(TaskDeps::default()); - let result = K::with_deps(Some(&task_deps), op); + let result = K::with_deps(TaskDepsRef::Allow(&task_deps), op); let task_deps = task_deps.into_inner(); let task_deps = task_deps.reads; @@ -422,47 +429,47 @@ impl DepGraph { pub fn read_index(&self, dep_node_index: DepNodeIndex) { if let Some(ref data) = self.data { K::read_deps(|task_deps| { - if let Some(task_deps) = task_deps { - let mut task_deps = task_deps.lock(); - let task_deps = &mut *task_deps; + let mut task_deps = match task_deps { + TaskDepsRef::Allow(deps) => deps.lock(), + TaskDepsRef::Ignore => return, + TaskDepsRef::Forbid => { + panic!("Illegal read of: {:?}", dep_node_index) + } + }; + let task_deps = &mut *task_deps; - if !task_deps.read_allowed { - panic!("Illegal read of: {:?}", dep_node_index); + if cfg!(debug_assertions) { + data.current.total_read_count.fetch_add(1, Relaxed); + } + + // As long as we only have a low number of reads we can avoid doing a hash + // insert and potentially allocating/reallocating the hashmap + let new_read = if task_deps.reads.len() < TASK_DEPS_READS_CAP { + task_deps.reads.iter().all(|other| *other != dep_node_index) + } else { + task_deps.read_set.insert(dep_node_index) + }; + if new_read { + task_deps.reads.push(dep_node_index); + if task_deps.reads.len() == TASK_DEPS_READS_CAP { + // Fill `read_set` with what we have so far so we can use the hashset + // next time + task_deps.read_set.extend(task_deps.reads.iter().copied()); } - if cfg!(debug_assertions) { - data.current.total_read_count.fetch_add(1, Relaxed); - } - - // As long as we only have a low number of reads we can avoid doing a hash - // insert and potentially allocating/reallocating the hashmap - let new_read = if task_deps.reads.len() < TASK_DEPS_READS_CAP { - task_deps.reads.iter().all(|other| *other != dep_node_index) - } else { - task_deps.read_set.insert(dep_node_index) - }; - if new_read { - task_deps.reads.push(dep_node_index); - if task_deps.reads.len() == TASK_DEPS_READS_CAP { - // Fill `read_set` with what we have so far so we can use the hashset - // next time - task_deps.read_set.extend(task_deps.reads.iter().copied()); - } - - #[cfg(debug_assertions)] - { - if let Some(target) = task_deps.node { - if let Some(ref forbidden_edge) = data.current.forbidden_edge { - let src = forbidden_edge.index_to_node.lock()[&dep_node_index]; - if forbidden_edge.test(&src, &target) { - panic!("forbidden edge {:?} -> {:?} created", src, target) - } + #[cfg(debug_assertions)] + { + if let Some(target) = task_deps.node { + if let Some(ref forbidden_edge) = data.current.forbidden_edge { + let src = forbidden_edge.index_to_node.lock()[&dep_node_index]; + if forbidden_edge.test(&src, &target) { + panic!("forbidden edge {:?} -> {:?} created", src, target) } } } - } else if cfg!(debug_assertions) { - data.current.total_duplicate_read_count.fetch_add(1, Relaxed); } + } else if cfg!(debug_assertions) { + data.current.total_duplicate_read_count.fetch_add(1, Relaxed); } }) } @@ -1185,21 +1192,34 @@ impl CurrentDepGraph { const TASK_DEPS_READS_CAP: usize = 8; type EdgesVec = SmallVec<[DepNodeIndex; TASK_DEPS_READS_CAP]>; -pub struct TaskDeps { +#[derive(Debug, Clone, Copy)] +pub enum TaskDepsRef<'a, K: DepKind> { + /// New dependencies can be added to the + /// `TaskDeps`. This is used when executing a 'normal' query + /// (no `eval_always` modifier) + Allow(&'a Lock>), + /// New dependencies are ignored. This is used when + /// executing an `eval_always` query, since there's no + /// need to track dependencies for a query that's always + /// re-executed. This is also used for `dep_graph.with_ignore` + Ignore, + /// Any attempt to add new dependencies will cause a panic. + /// This is used when decoding a query result from disk, + /// to ensure that the decoding process doesn't itself + /// require the execution of any queries. + Forbid, +} + +#[derive(Debug)] +pub struct TaskDeps { #[cfg(debug_assertions)] node: Option>, reads: EdgesVec, read_set: FxHashSet, phantom_data: PhantomData>, - /// Whether or not we allow `DepGraph::read_index` to run. - /// This is normally true, except inside `with_query_deserialization`, - /// where it set to `false` to enforce that no new `DepNode` edges are - /// created. See the documentation of `with_query_deserialization` for - /// more details. - read_allowed: bool, } -impl Default for TaskDeps { +impl Default for TaskDeps { fn default() -> Self { Self { #[cfg(debug_assertions)] @@ -1207,7 +1227,6 @@ impl Default for TaskDeps { reads: EdgesVec::new(), read_set: FxHashSet::default(), phantom_data: PhantomData, - read_allowed: true, } } } diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index 047fc9f10cc..5907ae309ca 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -5,13 +5,14 @@ mod query; mod serialized; pub use dep_node::{DepNode, DepNodeParams, WorkProductId}; -pub use graph::{hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, WorkProduct}; +pub use graph::{ + hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, TaskDepsRef, WorkProduct, +}; pub use query::DepGraphQuery; pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex}; use crate::ich::StableHashingContext; use rustc_data_structures::profiling::SelfProfilerRef; -use rustc_data_structures::sync::Lock; use rustc_serialize::{opaque::FileEncoder, Encodable}; use rustc_session::Session; @@ -90,12 +91,12 @@ pub trait DepKind: Copy + fmt::Debug + Eq + Hash + Send + Encodable fn debug_node(node: &DepNode, f: &mut fmt::Formatter<'_>) -> fmt::Result; /// Execute the operation with provided dependencies. - fn with_deps(deps: Option<&Lock>>, op: OP) -> R + fn with_deps(deps: TaskDepsRef<'_, Self>, op: OP) -> R where OP: FnOnce() -> R; /// Access dependencies from current implicit context. fn read_deps(op: OP) where - OP: for<'a> FnOnce(Option<&'a Lock>>); + OP: for<'a> FnOnce(TaskDepsRef<'a, Self>); }