Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce new TaskDepsRef enum to track allow/ignore/forbid status #92681

Merged
merged 1 commit into from
Jan 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions compiler/rustc_middle/src/dep_graph/mod.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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<DepKind>;
pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps<DepKind>;
pub type TaskDepsRef<'a> = rustc_query_system::dep_graph::TaskDepsRef<'a, DepKind>;
pub type DepGraphQuery = rustc_query_system::dep_graph::DepGraphQuery<DepKind>;
pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph<DepKind>;
pub type EdgeFilter = rustc_query_system::dep_graph::debug::EdgeFilter<DepKind>;
Expand Down Expand Up @@ -45,7 +45,7 @@ impl rustc_query_system::dep_graph::DepKind for DepKind {
write!(f, ")")
}

fn with_deps<OP, R>(task_deps: Option<&Lock<TaskDeps>>, op: OP) -> R
fn with_deps<OP, R>(task_deps: TaskDepsRef<'_>, op: OP) -> R
where
OP: FnOnce() -> R,
{
Expand All @@ -58,7 +58,7 @@ impl rustc_query_system::dep_graph::DepKind for DepKind {

fn read_deps<OP>(op: OP)
where
OP: for<'a> FnOnce(Option<&'a Lock<TaskDeps>>),
OP: for<'a> FnOnce(TaskDepsRef<'a>),
{
ty::tls::with_context_opt(|icx| {
let icx = if let Some(icx) = icx { icx } else { return };
Expand Down
12 changes: 9 additions & 3 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<TaskDeps>>,
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,
}
}
}

Expand Down
121 changes: 70 additions & 51 deletions compiler/rustc_query_system/src/dep_graph/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -165,7 +166,11 @@ impl<K: DepKind> DepGraph<K> {
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"
);
})
}
}
Expand All @@ -174,7 +179,7 @@ impl<K: DepKind> DepGraph<K> {
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,
Expand Down Expand Up @@ -227,10 +232,7 @@ impl<K: DepKind> DepGraph<K> {
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
Expand Down Expand Up @@ -313,10 +315,15 @@ impl<K: DepKind> DepGraph<K> {
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();
Expand Down Expand Up @@ -369,7 +376,7 @@ impl<K: DepKind> DepGraph<K> {

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;

Expand Down Expand Up @@ -422,47 +429,47 @@ impl<K: DepKind> DepGraph<K> {
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;

if !task_deps.read_allowed {
panic!("Illegal read of: {:?}", dep_node_index);
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 cfg!(debug_assertions) {
data.current.total_read_count.fetch_add(1, Relaxed);
}
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());
}
// 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);
}
})
}
Expand Down Expand Up @@ -1185,29 +1192,41 @@ impl<K: DepKind> CurrentDepGraph<K> {
const TASK_DEPS_READS_CAP: usize = 8;
type EdgesVec = SmallVec<[DepNodeIndex; TASK_DEPS_READS_CAP]>;

pub struct TaskDeps<K> {
#[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<TaskDeps<K>>),
/// 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<K: DepKind> {
#[cfg(debug_assertions)]
node: Option<DepNode<K>>,
reads: EdgesVec,
read_set: FxHashSet<DepNodeIndex>,
phantom_data: PhantomData<DepNode<K>>,
/// 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<K> Default for TaskDeps<K> {
impl<K: DepKind> Default for TaskDeps<K> {
fn default() -> Self {
Self {
#[cfg(debug_assertions)]
node: None,
reads: EdgesVec::new(),
read_set: FxHashSet::default(),
phantom_data: PhantomData,
read_allowed: true,
}
}
}
Expand Down
9 changes: 5 additions & 4 deletions compiler/rustc_query_system/src/dep_graph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -90,12 +91,12 @@ pub trait DepKind: Copy + fmt::Debug + Eq + Hash + Send + Encodable<FileEncoder>
fn debug_node(node: &DepNode<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result;

/// Execute the operation with provided dependencies.
fn with_deps<OP, R>(deps: Option<&Lock<TaskDeps<Self>>>, op: OP) -> R
fn with_deps<OP, R>(deps: TaskDepsRef<'_, Self>, op: OP) -> R
where
OP: FnOnce() -> R;

/// Access dependencies from current implicit context.
fn read_deps<OP>(op: OP)
where
OP: for<'a> FnOnce(Option<&'a Lock<TaskDeps<Self>>>);
OP: for<'a> FnOnce(TaskDepsRef<'a, Self>);
}