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.
11 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
13 use super::{DepGraphQuery, DepNode};
14 use super::debug::EdgeFilter;
16 pub struct DepGraphEdges {
18 indices: FxHashMap<DepNode, IdIndex>,
19 edges: FxHashSet<(IdIndex, IdIndex)>,
20 task_stack: Vec<OpenTask>,
21 forbidden_edge: Option<EdgeFilter>,
24 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
30 fn new(v: usize) -> IdIndex {
31 assert!((v & 0xFFFF_FFFF) == v);
32 IdIndex { index: v as u32 }
35 fn index(self) -> usize {
40 #[derive(Clone, Debug, PartialEq)]
45 read_set: FxHashSet<DepNode>,
51 pub fn new() -> DepGraphEdges {
52 let forbidden_edge = if cfg!(debug_assertions) {
53 match env::var("RUST_FORBID_DEP_GRAPH_EDGE") {
55 match EdgeFilter::new(&s) {
57 Err(err) => bug!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err),
70 task_stack: Vec::new(),
75 fn id(&self, index: IdIndex) -> DepNode {
76 self.nodes[index.index()]
79 pub fn push_ignore(&mut self) {
80 self.task_stack.push(OpenTask::Ignore);
83 pub fn pop_ignore(&mut self) {
84 let popped_node = self.task_stack.pop().unwrap();
85 debug_assert_eq!(popped_node, OpenTask::Ignore);
88 pub fn push_task(&mut self, key: DepNode) {
89 self.task_stack.push(OpenTask::Regular {
92 read_set: FxHashSet(),
96 pub fn pop_task(&mut self, key: DepNode) {
97 let popped_node = self.task_stack.pop().unwrap();
99 if let OpenTask::Regular {
104 debug_assert_eq!(node, key);
106 let target_id = self.get_or_create_node(node);
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));
113 bug!("pop_task() - Expected regular task to be popped")
117 /// Indicates that the current task `C` reads `v` by adding an
118 /// edge from `v` to `C`. If there is no current task, has no
119 /// effect. Note that *reading* from tracked state is harmless if
120 /// you are not in a task; what is bad is *writing* to tracked
121 /// state (and leaking data that you read into a tracked task).
122 pub fn read(&mut self, source: DepNode) {
123 match self.task_stack.last_mut() {
124 Some(&mut OpenTask::Regular {
129 if read_set.insert(source) {
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)
141 Some(&mut OpenTask::Ignore) | None => {
147 pub fn query(&self) -> DepGraphQuery {
148 let edges: Vec<_> = self.edges.iter()
149 .map(|&(i, j)| (self.id(i), self.id(j)))
151 DepGraphQuery::new(&self.nodes, &edges)
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));
161 pub fn add_node(&mut self, node: DepNode) {
162 self.get_or_create_node(node);
166 fn get_or_create_node(&mut self, dep_node: DepNode) -> IdIndex {
173 *indices.entry(dep_node).or_insert_with(|| {
174 let next_id = nodes.len();
175 nodes.push(dep_node);
176 IdIndex::new(next_id)