9
9
// except according to those terms.
10
10
11
11
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
12
+ use std:: env;
12
13
use super :: { DepGraphQuery , DepNode } ;
14
+ use super :: debug:: EdgeFilter ;
13
15
14
16
pub struct DepGraphEdges {
15
17
nodes : Vec < DepNode > ,
16
18
indices : FxHashMap < DepNode , IdIndex > ,
17
19
edges : FxHashSet < ( IdIndex , IdIndex ) > ,
18
- open_nodes : Vec < OpenNode > ,
20
+ task_stack : Vec < OpenTask > ,
21
+ forbidden_edge : Option < EdgeFilter > ,
19
22
}
20
23
21
24
#[ derive( Copy , Clone , Debug , PartialEq , Eq , Hash ) ]
@@ -35,125 +38,109 @@ impl IdIndex {
35
38
}
36
39
37
40
#[ 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
+ } ,
40
47
Ignore ,
41
48
}
42
49
43
50
impl DepGraphEdges {
44
51
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
+
45
66
DepGraphEdges {
46
67
nodes : vec ! [ ] ,
47
68
indices : FxHashMap ( ) ,
48
69
edges : FxHashSet ( ) ,
49
- open_nodes : Vec :: new ( )
70
+ task_stack : Vec :: new ( ) ,
71
+ forbidden_edge,
50
72
}
51
73
}
52
74
53
75
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 ( ) ]
72
77
}
73
78
74
79
pub fn push_ignore ( & mut self ) {
75
- self . open_nodes . push ( OpenNode :: Ignore ) ;
80
+ self . task_stack . push ( OpenTask :: Ignore ) ;
76
81
}
77
82
78
83
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 ) ;
81
86
}
82
87
83
88
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
+ } ) ;
94
94
}
95
95
96
96
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
+ }
99
115
}
100
116
101
117
/// Indicates that the current task `C` reads `v` by adding an
102
118
/// edge from `v` to `C`. If there is no current task, has no
103
119
/// effect. Note that *reading* from tracked state is harmless if
104
120
/// you are not in a task; what is bad is *writing* to tracked
105
121
/// 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
+ }
157
144
}
158
145
}
159
146
@@ -163,4 +150,30 @@ impl DepGraphEdges {
163
150
. collect ( ) ;
164
151
DepGraphQuery :: new ( & self . nodes , & edges)
165
152
}
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
+ }
166
179
}
0 commit comments