]> git.proxmox.com Git - rustc.git/blame - src/librustc/dep_graph/edges.rs
New upstream version 1.20.0+dfsg1
[rustc.git] / src / librustc / dep_graph / edges.rs
CommitLineData
9cc50fc6
SL
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.
4//
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.
10
041b39d2 11use ich::Fingerprint;
476ff2be 12use rustc_data_structures::fx::{FxHashMap, FxHashSet};
041b39d2
XL
13use rustc_data_structures::stable_hasher::StableHasher;
14use std::env;
54a0048b 15use std::hash::Hash;
041b39d2
XL
16use std::mem;
17use super::{DepGraphQuery, DepKind, DepNode};
18use super::debug::EdgeFilter;
19
20pub struct DepGraphEdges {
21 nodes: Vec<DepNode>,
22 indices: FxHashMap<DepNode, DepNodeIndex>,
23 edges: FxHashSet<(DepNodeIndex, DepNodeIndex)>,
24 task_stack: Vec<OpenTask>,
25 forbidden_edge: Option<EdgeFilter>,
9cc50fc6
SL
26}
27
28#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
041b39d2 29pub struct DepNodeIndex {
9cc50fc6
SL
30 index: u32
31}
32
041b39d2
XL
33impl DepNodeIndex {
34
35 pub const INVALID: DepNodeIndex = DepNodeIndex { index: ::std::u32::MAX };
36
37 fn new(v: usize) -> DepNodeIndex {
9cc50fc6 38 assert!((v & 0xFFFF_FFFF) == v);
041b39d2 39 DepNodeIndex { index: v as u32 }
9cc50fc6
SL
40 }
41
42 fn index(self) -> usize {
43 self.index as usize
44 }
45}
46
47#[derive(Clone, Debug, PartialEq)]
041b39d2
XL
48enum OpenTask {
49 Regular {
50 node: DepNode,
51 reads: Vec<DepNode>,
52 read_set: FxHashSet<DepNode>,
53 },
54 Anon {
55 reads: Vec<DepNode>,
56 read_set: FxHashSet<DepNode>,
57 },
9cc50fc6
SL
58 Ignore,
59}
60
041b39d2
XL
61impl DepGraphEdges {
62 pub fn new() -> DepGraphEdges {
63 let forbidden_edge = if cfg!(debug_assertions) {
64 match env::var("RUST_FORBID_DEP_GRAPH_EDGE") {
65 Ok(s) => {
66 match EdgeFilter::new(&s) {
67 Ok(f) => Some(f),
68 Err(err) => bug!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err),
69 }
70 }
71 Err(_) => None,
72 }
73 } else {
74 None
75 };
76
9cc50fc6
SL
77 DepGraphEdges {
78 nodes: vec![],
476ff2be
SL
79 indices: FxHashMap(),
80 edges: FxHashSet(),
041b39d2
XL
81 task_stack: Vec::new(),
82 forbidden_edge,
9cc50fc6
SL
83 }
84 }
85
041b39d2
XL
86 fn id(&self, index: DepNodeIndex) -> DepNode {
87 self.nodes[index.index()]
9cc50fc6
SL
88 }
89
041b39d2
XL
90 pub fn push_ignore(&mut self) {
91 self.task_stack.push(OpenTask::Ignore);
9cc50fc6
SL
92 }
93
041b39d2
XL
94 pub fn pop_ignore(&mut self) {
95 let popped_node = self.task_stack.pop().unwrap();
96 debug_assert_eq!(popped_node, OpenTask::Ignore);
9cc50fc6
SL
97 }
98
041b39d2
XL
99 pub fn push_task(&mut self, key: DepNode) {
100 self.task_stack.push(OpenTask::Regular {
101 node: key,
102 reads: Vec::new(),
103 read_set: FxHashSet(),
104 });
9cc50fc6
SL
105 }
106
041b39d2
XL
107 pub fn pop_task(&mut self, key: DepNode) -> DepNodeIndex {
108 let popped_node = self.task_stack.pop().unwrap();
109
110 if let OpenTask::Regular {
111 node,
112 read_set: _,
113 reads
114 } = popped_node {
115 debug_assert_eq!(node, key);
9cc50fc6 116
041b39d2 117 let target_id = self.get_or_create_node(node);
9cc50fc6 118
041b39d2
XL
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));
122 }
9cc50fc6 123
041b39d2
XL
124 target_id
125 } else {
126 bug!("pop_task() - Expected regular task to be popped")
9cc50fc6
SL
127 }
128 }
129
041b39d2
XL
130 pub fn push_anon_task(&mut self) {
131 self.task_stack.push(OpenTask::Anon {
132 reads: Vec::new(),
133 read_set: FxHashSet(),
134 });
135 }
136
137 pub fn pop_anon_task(&mut self, kind: DepKind) -> DepNodeIndex {
138 let popped_node = self.task_stack.pop().unwrap();
139
140 if let OpenTask::Anon {
141 read_set: _,
142 reads
143 } = popped_node {
144 let mut fingerprint = Fingerprint::zero();
145 let mut hasher = StableHasher::new();
146
147 for read in reads.iter() {
148 mem::discriminant(&read.kind).hash(&mut hasher);
149
150 // Fingerprint::combine() is faster than sending Fingerprint
151 // through the StableHasher (at least as long as StableHasher
152 // is so slow).
153 fingerprint = fingerprint.combine(read.hash);
154 }
155
156 fingerprint = fingerprint.combine(hasher.finish());
157
158 let target_dep_node = DepNode {
159 kind,
160 hash: fingerprint,
161 };
162
163 if let Some(&index) = self.indices.get(&target_dep_node) {
164 return index;
165 }
166
167 let target_id = self.get_or_create_node(target_dep_node);
168
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));
172 }
173
174 target_id
175 } else {
176 bug!("pop_anon_task() - Expected anonymous task to be popped")
177 }
9cc50fc6
SL
178 }
179
180 /// Indicates that the current task `C` reads `v` by adding an
cc61c64b
XL
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).
041b39d2
XL
185 pub fn read(&mut self, source: DepNode) {
186 match self.task_stack.last_mut() {
187 Some(&mut OpenTask::Regular {
188 node: target,
189 ref mut reads,
190 ref mut read_set,
191 }) => {
192 if read_set.insert(source) {
193 reads.push(source);
194
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)
199 }
200 }
201 }
202 }
203 }
204 Some(&mut OpenTask::Anon {
205 ref mut reads,
206 ref mut read_set,
207 }) => {
208 if read_set.insert(source) {
209 reads.push(source);
210 }
211 }
212 Some(&mut OpenTask::Ignore) | None => {
213 // ignore
214 }
9cc50fc6
SL
215 }
216 }
217
041b39d2
XL
218 pub fn read_index(&mut self, source: DepNodeIndex) {
219 let dep_node = self.nodes[source.index()];
220 self.read(dep_node);
9cc50fc6
SL
221 }
222
041b39d2 223 pub fn query(&self) -> DepGraphQuery {
9cc50fc6
SL
224 let edges: Vec<_> = self.edges.iter()
225 .map(|&(i, j)| (self.id(i), self.id(j)))
226 .collect();
227 DepGraphQuery::new(&self.nodes, &edges)
228 }
041b39d2
XL
229
230 #[inline]
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));
235 }
236
237 pub fn add_node(&mut self, node: DepNode) {
238 self.get_or_create_node(node);
239 }
240
241 #[inline]
242 fn get_or_create_node(&mut self, dep_node: DepNode) -> DepNodeIndex {
243 let DepGraphEdges {
244 ref mut indices,
245 ref mut nodes,
246 ..
247 } = *self;
248
249 *indices.entry(dep_node).or_insert_with(|| {
250 let next_id = nodes.len();
251 nodes.push(dep_node);
252 DepNodeIndex::new(next_id)
253 })
254 }
9cc50fc6 255}