1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
12 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
13 use rustc_data_structures::stable_hasher::StableHasher;
17 use super::{DepGraphQuery, DepKind, DepNode};
18 use super::debug::EdgeFilter;
20 pub struct DepGraphEdges {
22 indices: FxHashMap<DepNode, IdIndex>,
23 edges: FxHashSet<(IdIndex, IdIndex)>,
24 task_stack: Vec<OpenTask>,
25 forbidden_edge: Option<EdgeFilter>,
28 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
34 fn new(v: usize) -> IdIndex {
35 assert!((v & 0xFFFF_FFFF) == v);
36 IdIndex { index: v as u32 }
39 fn index(self) -> usize {
44 #[derive(Clone, Debug, PartialEq)]
49 read_set: FxHashSet<DepNode>,
53 read_set: FxHashSet<DepNode>,
59 pub fn new() -> DepGraphEdges {
60 let forbidden_edge = if cfg!(debug_assertions) {
61 match env::var("RUST_FORBID_DEP_GRAPH_EDGE") {
63 match EdgeFilter::new(&s) {
65 Err(err) => bug!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err),
78 task_stack: Vec::new(),
83 fn id(&self, index: IdIndex) -> DepNode {
84 self.nodes[index.index()]
87 pub fn push_ignore(&mut self) {
88 self.task_stack.push(OpenTask::Ignore);
91 pub fn pop_ignore(&mut self) {
92 let popped_node = self.task_stack.pop().unwrap();
93 debug_assert_eq!(popped_node, OpenTask::Ignore);
96 pub fn push_task(&mut self, key: DepNode) {
97 self.task_stack.push(OpenTask::Regular {
100 read_set: FxHashSet(),
104 pub fn pop_task(&mut self, key: DepNode) {
105 let popped_node = self.task_stack.pop().unwrap();
107 if let OpenTask::Regular {
112 debug_assert_eq!(node, key);
114 let target_id = self.get_or_create_node(node);
116 for read in reads.into_iter() {
117 let source_id = self.get_or_create_node(read);
118 self.edges.insert((source_id, target_id));
121 bug!("pop_task() - Expected regular task to be popped")
125 pub fn push_anon_task(&mut self) {
126 self.task_stack.push(OpenTask::Anon {
128 read_set: FxHashSet(),
132 pub fn pop_anon_task(&mut self, kind: DepKind) -> DepNode {
133 let popped_node = self.task_stack.pop().unwrap();
135 if let OpenTask::Anon {
139 let mut fingerprint = Fingerprint::zero();
140 let mut hasher = StableHasher::new();
142 for read in reads.iter() {
143 mem::discriminant(&read.kind).hash(&mut hasher);
145 // Fingerprint::combine() is faster than sending Fingerprint
146 // through the StableHasher (at least as long as StableHasher
148 fingerprint = fingerprint.combine(read.hash);
151 fingerprint = fingerprint.combine(hasher.finish());
153 let target_dep_node = DepNode {
158 if self.indices.contains_key(&target_dep_node) {
159 return target_dep_node;
162 let target_id = self.get_or_create_node(target_dep_node);
164 for read in reads.into_iter() {
165 let source_id = self.get_or_create_node(read);
166 self.edges.insert((source_id, target_id));
171 bug!("pop_anon_task() - Expected anonymous task to be popped")
175 /// Indicates that the current task `C` reads `v` by adding an
176 /// edge from `v` to `C`. If there is no current task, has no
177 /// effect. Note that *reading* from tracked state is harmless if
178 /// you are not in a task; what is bad is *writing* to tracked
179 /// state (and leaking data that you read into a tracked task).
180 pub fn read(&mut self, source: DepNode) {
181 match self.task_stack.last_mut() {
182 Some(&mut OpenTask::Regular {
187 if read_set.insert(source) {
190 if cfg!(debug_assertions) {
191 if let Some(ref forbidden_edge) = self.forbidden_edge {
192 if forbidden_edge.test(&source, &target) {
193 bug!("forbidden edge {:?} -> {:?} created", source, target)
199 Some(&mut OpenTask::Anon {
203 if read_set.insert(source) {
207 Some(&mut OpenTask::Ignore) | None => {
213 pub fn query(&self) -> DepGraphQuery {
214 let edges: Vec<_> = self.edges.iter()
215 .map(|&(i, j)| (self.id(i), self.id(j)))
217 DepGraphQuery::new(&self.nodes, &edges)
221 pub fn add_edge(&mut self, source: DepNode, target: DepNode) {
222 let source = self.get_or_create_node(source);
223 let target = self.get_or_create_node(target);
224 self.edges.insert((source, target));
227 pub fn add_node(&mut self, node: DepNode) {
228 self.get_or_create_node(node);
232 fn get_or_create_node(&mut self, dep_node: DepNode) -> IdIndex {
239 *indices.entry(dep_node).or_insert_with(|| {
240 let next_id = nodes.len();
241 nodes.push(dep_node);
242 IdIndex::new(next_id)