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, DepNodeIndex>,
23 edges: FxHashSet<(DepNodeIndex, DepNodeIndex)>,
24 task_stack: Vec<OpenTask>,
25 forbidden_edge: Option<EdgeFilter>,
28 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
29 pub struct DepNodeIndex {
35 pub const INVALID: DepNodeIndex = DepNodeIndex { index: ::std::u32::MAX };
37 fn new(v: usize) -> DepNodeIndex {
38 assert!((v & 0xFFFF_FFFF) == v);
39 DepNodeIndex { index: v as u32 }
42 fn index(self) -> usize {
47 #[derive(Clone, Debug, PartialEq)]
52 read_set: FxHashSet<DepNode>,
56 read_set: FxHashSet<DepNode>,
62 pub fn new() -> DepGraphEdges {
63 let forbidden_edge = if cfg!(debug_assertions) {
64 match env::var("RUST_FORBID_DEP_GRAPH_EDGE") {
66 match EdgeFilter::new(&s) {
68 Err(err) => bug!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err),
81 task_stack: Vec::new(),
86 fn id(&self, index: DepNodeIndex) -> DepNode {
87 self.nodes[index.index()]
90 pub fn push_ignore(&mut self) {
91 self.task_stack.push(OpenTask::Ignore);
94 pub fn pop_ignore(&mut self) {
95 let popped_node = self.task_stack.pop().unwrap();
96 debug_assert_eq!(popped_node, OpenTask::Ignore);
99 pub fn push_task(&mut self, key: DepNode) {
100 self.task_stack.push(OpenTask::Regular {
103 read_set: FxHashSet(),
107 pub fn pop_task(&mut self, key: DepNode) -> DepNodeIndex {
108 let popped_node = self.task_stack.pop().unwrap();
110 if let OpenTask::Regular {
115 debug_assert_eq!(node, key);
117 let target_id = self.get_or_create_node(node);
119 for read in reads.into_iter() {
120 let source_id = self.get_or_create_node(read);
121 self.edges.insert((source_id, target_id));
126 bug!("pop_task() - Expected regular task to be popped")
130 pub fn push_anon_task(&mut self) {
131 self.task_stack.push(OpenTask::Anon {
133 read_set: FxHashSet(),
137 pub fn pop_anon_task(&mut self, kind: DepKind) -> DepNodeIndex {
138 let popped_node = self.task_stack.pop().unwrap();
140 if let OpenTask::Anon {
144 let mut fingerprint = Fingerprint::zero();
145 let mut hasher = StableHasher::new();
147 for read in reads.iter() {
148 mem::discriminant(&read.kind).hash(&mut hasher);
150 // Fingerprint::combine() is faster than sending Fingerprint
151 // through the StableHasher (at least as long as StableHasher
153 fingerprint = fingerprint.combine(read.hash);
156 fingerprint = fingerprint.combine(hasher.finish());
158 let target_dep_node = DepNode {
163 if let Some(&index) = self.indices.get(&target_dep_node) {
167 let target_id = self.get_or_create_node(target_dep_node);
169 for read in reads.into_iter() {
170 let source_id = self.get_or_create_node(read);
171 self.edges.insert((source_id, target_id));
176 bug!("pop_anon_task() - Expected anonymous task to be popped")
180 /// Indicates that the current task `C` reads `v` by adding an
181 /// edge from `v` to `C`. If there is no current task, has no
182 /// effect. Note that *reading* from tracked state is harmless if
183 /// you are not in a task; what is bad is *writing* to tracked
184 /// state (and leaking data that you read into a tracked task).
185 pub fn read(&mut self, source: DepNode) {
186 match self.task_stack.last_mut() {
187 Some(&mut OpenTask::Regular {
192 if read_set.insert(source) {
195 if cfg!(debug_assertions) {
196 if let Some(ref forbidden_edge) = self.forbidden_edge {
197 if forbidden_edge.test(&source, &target) {
198 bug!("forbidden edge {:?} -> {:?} created", source, target)
204 Some(&mut OpenTask::Anon {
208 if read_set.insert(source) {
212 Some(&mut OpenTask::Ignore) | None => {
218 pub fn read_index(&mut self, source: DepNodeIndex) {
219 let dep_node = self.nodes[source.index()];
223 pub fn query(&self) -> DepGraphQuery {
224 let edges: Vec<_> = self.edges.iter()
225 .map(|&(i, j)| (self.id(i), self.id(j)))
227 DepGraphQuery::new(&self.nodes, &edges)
231 pub fn add_edge(&mut self, source: DepNode, target: DepNode) {
232 let source = self.get_or_create_node(source);
233 let target = self.get_or_create_node(target);
234 self.edges.insert((source, target));
237 pub fn add_node(&mut self, node: DepNode) {
238 self.get_or_create_node(node);
242 fn get_or_create_node(&mut self, dep_node: DepNode) -> DepNodeIndex {
249 *indices.entry(dep_node).or_insert_with(|| {
250 let next_id = nodes.len();
251 nodes.push(dep_node);
252 DepNodeIndex::new(next_id)