Skip to content

Commit 089860b

Browse files
incr.comp.: Manage dependency graph on main thread.
1 parent 13e87d1 commit 089860b

File tree

7 files changed

+175
-478
lines changed

7 files changed

+175
-478
lines changed

src/librustc/dep_graph/edges.rs

+101-88
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,16 @@
99
// except according to those terms.
1010

1111
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
12+
use std::env;
1213
use super::{DepGraphQuery, DepNode};
14+
use super::debug::EdgeFilter;
1315

1416
pub struct DepGraphEdges {
1517
nodes: Vec<DepNode>,
1618
indices: FxHashMap<DepNode, IdIndex>,
1719
edges: FxHashSet<(IdIndex, IdIndex)>,
18-
open_nodes: Vec<OpenNode>,
20+
task_stack: Vec<OpenTask>,
21+
forbidden_edge: Option<EdgeFilter>,
1922
}
2023

2124
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
@@ -35,125 +38,109 @@ impl IdIndex {
3538
}
3639

3740
#[derive(Clone, Debug, PartialEq)]
38-
enum OpenNode {
39-
Node(IdIndex),
41+
enum OpenTask {
42+
Regular {
43+
node: DepNode,
44+
reads: Vec<DepNode>,
45+
read_set: FxHashSet<DepNode>,
46+
},
4047
Ignore,
4148
}
4249

4350
impl DepGraphEdges {
4451
pub fn new() -> DepGraphEdges {
52+
let forbidden_edge = if cfg!(debug_assertions) {
53+
match env::var("RUST_FORBID_DEP_GRAPH_EDGE") {
54+
Ok(s) => {
55+
match EdgeFilter::new(&s) {
56+
Ok(f) => Some(f),
57+
Err(err) => bug!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err),
58+
}
59+
}
60+
Err(_) => None,
61+
}
62+
} else {
63+
None
64+
};
65+
4566
DepGraphEdges {
4667
nodes: vec![],
4768
indices: FxHashMap(),
4869
edges: FxHashSet(),
49-
open_nodes: Vec::new()
70+
task_stack: Vec::new(),
71+
forbidden_edge,
5072
}
5173
}
5274

5375
fn id(&self, index: IdIndex) -> DepNode {
54-
self.nodes[index.index()].clone()
55-
}
56-
57-
/// Creates a node for `id` in the graph.
58-
fn make_node(&mut self, id: DepNode) -> IdIndex {
59-
if let Some(&i) = self.indices.get(&id) {
60-
return i;
61-
}
62-
63-
let index = IdIndex::new(self.nodes.len());
64-
self.nodes.push(id.clone());
65-
self.indices.insert(id, index);
66-
index
67-
}
68-
69-
/// Top of the stack of open nodes.
70-
fn current_node(&self) -> Option<OpenNode> {
71-
self.open_nodes.last().cloned()
76+
self.nodes[index.index()]
7277
}
7378

7479
pub fn push_ignore(&mut self) {
75-
self.open_nodes.push(OpenNode::Ignore);
80+
self.task_stack.push(OpenTask::Ignore);
7681
}
7782

7883
pub fn pop_ignore(&mut self) {
79-
let popped_node = self.open_nodes.pop().unwrap();
80-
assert_eq!(popped_node, OpenNode::Ignore);
84+
let popped_node = self.task_stack.pop().unwrap();
85+
debug_assert_eq!(popped_node, OpenTask::Ignore);
8186
}
8287

8388
pub fn push_task(&mut self, key: DepNode) {
84-
let top_node = self.current_node();
85-
86-
let new_node = self.make_node(key);
87-
self.open_nodes.push(OpenNode::Node(new_node));
88-
89-
// if we are in the midst of doing task T, then this new task
90-
// N is a subtask of T, so add an edge N -> T.
91-
if let Some(top_node) = top_node {
92-
self.add_edge_from_open_node(top_node, |t| (new_node, t));
93-
}
89+
self.task_stack.push(OpenTask::Regular {
90+
node: key,
91+
reads: Vec::new(),
92+
read_set: FxHashSet(),
93+
});
9494
}
9595

9696
pub fn pop_task(&mut self, key: DepNode) {
97-
let popped_node = self.open_nodes.pop().unwrap();
98-
assert_eq!(OpenNode::Node(self.indices[&key]), popped_node);
97+
let popped_node = self.task_stack.pop().unwrap();
98+
99+
if let OpenTask::Regular {
100+
node,
101+
read_set: _,
102+
reads
103+
} = popped_node {
104+
debug_assert_eq!(node, key);
105+
106+
let target_id = self.get_or_create_node(node);
107+
108+
for read in reads.into_iter() {
109+
let source_id = self.get_or_create_node(read);
110+
self.edges.insert((source_id, target_id));
111+
}
112+
} else {
113+
bug!("pop_task() - Expected regular task to be popped")
114+
}
99115
}
100116

101117
/// Indicates that the current task `C` reads `v` by adding an
102118
/// edge from `v` to `C`. If there is no current task, has no
103119
/// effect. Note that *reading* from tracked state is harmless if
104120
/// you are not in a task; what is bad is *writing* to tracked
105121
/// state (and leaking data that you read into a tracked task).
106-
pub fn read(&mut self, v: DepNode) {
107-
if self.current_node().is_some() {
108-
let source = self.make_node(v);
109-
self.add_edge_from_current_node(|current| (source, current))
110-
}
111-
}
112-
113-
/// Indicates that the current task `C` writes `v` by adding an
114-
/// edge from `C` to `v`. If there is no current task, panics. If
115-
/// you want to suppress this edge, use `ignore`.
116-
pub fn write(&mut self, v: DepNode) {
117-
let target = self.make_node(v);
118-
self.add_edge_from_current_node(|current| (current, target))
119-
}
120-
121-
/// Invoke `add_edge_from_open_node` with the top of the stack, or
122-
/// panic if stack is empty.
123-
fn add_edge_from_current_node<OP>(&mut self,
124-
op: OP)
125-
where OP: FnOnce(IdIndex) -> (IdIndex, IdIndex)
126-
{
127-
match self.current_node() {
128-
Some(open_node) => self.add_edge_from_open_node(open_node, op),
129-
None => bug!("no current node, cannot add edge into dependency graph")
130-
}
131-
}
132-
133-
/// Adds an edge to or from the `open_node`, assuming `open_node`
134-
/// is not `Ignore`. The direction of the edge is determined by
135-
/// the closure `op` --- we pass as argument the open node `n`,
136-
/// and the closure returns a (source, target) tuple, which should
137-
/// include `n` in one spot or another.
138-
fn add_edge_from_open_node<OP>(&mut self,
139-
open_node: OpenNode,
140-
op: OP)
141-
where OP: FnOnce(IdIndex) -> (IdIndex, IdIndex)
142-
{
143-
let (source, target) = match open_node {
144-
OpenNode::Node(n) => op(n),
145-
OpenNode::Ignore => { return; }
146-
};
147-
148-
// ignore trivial self edges, which are not very interesting
149-
if source == target {
150-
return;
151-
}
152-
153-
if self.edges.insert((source, target)) {
154-
debug!("adding edge from {:?} to {:?}",
155-
self.id(source),
156-
self.id(target));
122+
pub fn read(&mut self, source: DepNode) {
123+
match self.task_stack.last_mut() {
124+
Some(&mut OpenTask::Regular {
125+
node: target,
126+
ref mut reads,
127+
ref mut read_set,
128+
}) => {
129+
if read_set.insert(source) {
130+
reads.push(source);
131+
132+
if cfg!(debug_assertions) {
133+
if let Some(ref forbidden_edge) = self.forbidden_edge {
134+
if forbidden_edge.test(&source, &target) {
135+
bug!("forbidden edge {:?} -> {:?} created", source, target)
136+
}
137+
}
138+
}
139+
}
140+
}
141+
Some(&mut OpenTask::Ignore) | None => {
142+
// ignore
143+
}
157144
}
158145
}
159146

@@ -163,4 +150,30 @@ impl DepGraphEdges {
163150
.collect();
164151
DepGraphQuery::new(&self.nodes, &edges)
165152
}
153+
154+
#[inline]
155+
pub fn add_edge(&mut self, source: DepNode, target: DepNode) {
156+
let source = self.get_or_create_node(source);
157+
let target = self.get_or_create_node(target);
158+
self.edges.insert((source, target));
159+
}
160+
161+
pub fn add_node(&mut self, node: DepNode) {
162+
self.get_or_create_node(node);
163+
}
164+
165+
#[inline]
166+
fn get_or_create_node(&mut self, dep_node: DepNode) -> IdIndex {
167+
let DepGraphEdges {
168+
ref mut indices,
169+
ref mut nodes,
170+
..
171+
} = *self;
172+
173+
*indices.entry(dep_node).or_insert_with(|| {
174+
let next_id = nodes.len();
175+
nodes.push(dep_node);
176+
IdIndex::new(next_id)
177+
})
178+
}
166179
}

0 commit comments

Comments
 (0)