Skip to content
Open
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
63 changes: 40 additions & 23 deletions compiler/rustc_middle/src/dep_graph/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,10 @@ impl DepGraph {
);
assert_eq!(red_node_index, DepNodeIndex::FOREVER_RED_NODE);
if prev_graph_node_count > 0 {
colors.insert_red(SerializedDepNodeIndex::from_u32(
DepNodeIndex::FOREVER_RED_NODE.as_u32(),
));
let prev_index =
const { SerializedDepNodeIndex::from_u32(DepNodeIndex::FOREVER_RED_NODE.as_u32()) };
let result = colors.try_set_color(prev_index, DesiredColor::Red);
assert_matches!(result, TrySetColorResult::Success);
}

DepGraph {
Expand Down Expand Up @@ -1415,28 +1416,29 @@ impl DepNodeColorMap {
if value <= DepNodeIndex::MAX_AS_U32 { Some(DepNodeIndex::from_u32(value)) } else { None }
}

/// This tries to atomically mark a node green and assign `index` as the new
/// index if `green` is true, otherwise it will try to atomicaly mark it red.
/// Atomically sets the color of a previous-session dep node to either green
/// or red, if it has not already been colored.
///
/// This returns `Ok` if `index` gets assigned or the node is marked red, otherwise it returns
/// the already allocated index in `Err` if it is green already. If it was already
/// red, `Err(None)` is returned.
/// If the node already has a color, the new color is ignored, and the
/// return value indicates the existing color.
#[inline(always)]
pub(super) fn try_mark(
pub(super) fn try_set_color(
&self,
prev_index: SerializedDepNodeIndex,
index: DepNodeIndex,
green: bool,
) -> Result<(), Option<DepNodeIndex>> {
let value = &self.values[prev_index];
match value.compare_exchange(
color: DesiredColor,
) -> TrySetColorResult {
match self.values[prev_index].compare_exchange(
COMPRESSED_UNKNOWN,
if green { index.as_u32() } else { COMPRESSED_RED },
match color {
DesiredColor::Red => COMPRESSED_RED,
DesiredColor::Green { index } => index.as_u32(),
},
Ordering::Relaxed,
Ordering::Relaxed,
) {
Ok(_) => Ok(()),
Err(v) => Err(if v == COMPRESSED_RED { None } else { Some(DepNodeIndex::from_u32(v)) }),
Ok(_) => TrySetColorResult::Success,
Err(COMPRESSED_RED) => TrySetColorResult::AlreadyRed,
Err(index) => TrySetColorResult::AlreadyGreen { index: DepNodeIndex::from_u32(index) },
}
}

Expand All @@ -1454,13 +1456,28 @@ impl DepNodeColorMap {
DepNodeColor::Unknown
}
}
}

#[inline]
pub(super) fn insert_red(&self, index: SerializedDepNodeIndex) {
let value = self.values[index].swap(COMPRESSED_RED, Ordering::Release);
// Sanity check for duplicate nodes
assert_eq!(value, COMPRESSED_UNKNOWN, "tried to color an already colored node as red");
}
/// The color that [`DepNodeColorMap::try_set_color`] should try to apply to a node.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, I find these comments saying which functions use a type to be not that useful, and prone to getting out of date. The comments on the variants themselves are much more useful.

#[derive(Clone, Copy, Debug)]
pub(super) enum DesiredColor {
/// Try to mark the node red.
Red,
/// Try to mark the node green, associating it with a current-session node index.
Green { index: DepNodeIndex },
}

/// Return value of [`DepNodeColorMap::try_set_color`], indicating success or failure,
/// and (on failure) what the existing color is.
#[derive(Clone, Copy, Debug)]
pub(super) enum TrySetColorResult {
/// The [`DesiredColor`] was freshly applied to the node.
Success,
/// Coloring failed because the node was already marked red.
AlreadyRed,
/// Coloring failed because the node was already marked green,
/// and corresponds to node `index` in the current-session dep graph.
AlreadyGreen { index: DepNodeIndex },
}

#[inline(never)]
Expand Down
25 changes: 14 additions & 11 deletions compiler/rustc_middle/src/dep_graph/serialized.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_session::Session;
use tracing::{debug, instrument};

use super::graph::{CurrentDepGraph, DepNodeColorMap};
use super::graph::{CurrentDepGraph, DepNodeColorMap, DesiredColor, TrySetColorResult};
use super::retained::RetainedDepGraph;
use super::{DepKind, DepNode, DepNodeIndex};
use crate::dep_graph::edges::EdgesVec;
Expand Down Expand Up @@ -905,13 +905,14 @@ impl GraphEncoder {
let mut local = self.status.local.borrow_mut();

let index = self.status.next_index(&mut *local);
let color = if is_green { DesiredColor::Green { index } } else { DesiredColor::Red };

// Use `try_mark` to avoid racing when `send_promoted` is called concurrently
// Use `try_set_color` to avoid racing when `send_promoted` is called concurrently
// on the same index.
match colors.try_mark(prev_index, index, is_green) {
Ok(()) => (),
Err(None) => panic!("dep node {:?} is unexpectedly red", prev_index),
Err(Some(dep_node_index)) => return dep_node_index,
match colors.try_set_color(prev_index, color) {
TrySetColorResult::Success => {}
TrySetColorResult::AlreadyRed => panic!("dep node {prev_index:?} is unexpectedly red"),
TrySetColorResult::AlreadyGreen { index } => return index,
}

self.status.bump_index(&mut *local);
Expand All @@ -923,7 +924,8 @@ impl GraphEncoder {
/// from the previous dep graph and expects all edges to already have a new dep node index
/// assigned.
///
/// This will also ensure the dep node is marked green if `Some` is returned.
/// Tries to mark the dep node green, and returns Some if it is now green,
/// or None if had already been concurrently marked red.
#[inline]
pub(crate) fn send_promoted(
&self,
Expand All @@ -935,10 +937,10 @@ impl GraphEncoder {
let mut local = self.status.local.borrow_mut();
let index = self.status.next_index(&mut *local);

// Use `try_mark_green` to avoid racing when `send_promoted` or `send_and_color`
// Use `try_set_color` to avoid racing when `send_promoted` or `send_and_color`
// is called concurrently on the same index.
match colors.try_mark(prev_index, index, true) {
Ok(()) => {
match colors.try_set_color(prev_index, DesiredColor::Green { index }) {
TrySetColorResult::Success => {
self.status.bump_index(&mut *local);
self.status.encode_promoted_node(
index,
Expand All @@ -949,7 +951,8 @@ impl GraphEncoder {
);
Some(index)
}
Err(dep_node_index) => dep_node_index,
TrySetColorResult::AlreadyRed => None,
TrySetColorResult::AlreadyGreen { index } => Some(index),
}
}

Expand Down
1 change: 1 addition & 0 deletions typos.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ unstalled = "unstalled" # short for un-stalled
# the non-empty form can be automatically fixed by `--bless`.
#
# tidy-alphabetical-start
atomicaly = "atomically"
definitinon = "definition"
dependy = ""
similarlty = "similarity"
Expand Down
Loading