OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/graph-visualizer.h" | 5 #include "src/compiler/graph-visualizer.h" |
6 | 6 |
7 #include <sstream> | 7 #include <sstream> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
11 #include "src/compiler/generic-algorithm.h" | |
12 #include "src/compiler/generic-node.h" | 11 #include "src/compiler/generic-node.h" |
13 #include "src/compiler/generic-node-inl.h" | 12 #include "src/compiler/generic-node-inl.h" |
14 #include "src/compiler/graph.h" | 13 #include "src/compiler/graph.h" |
15 #include "src/compiler/graph-inl.h" | 14 #include "src/compiler/graph-inl.h" |
16 #include "src/compiler/node.h" | 15 #include "src/compiler/node.h" |
17 #include "src/compiler/node-properties.h" | 16 #include "src/compiler/node-properties.h" |
18 #include "src/compiler/node-properties-inl.h" | 17 #include "src/compiler/node-properties-inl.h" |
19 #include "src/compiler/opcodes.h" | 18 #include "src/compiler/opcodes.h" |
20 #include "src/compiler/operator.h" | 19 #include "src/compiler/operator.h" |
21 #include "src/compiler/register-allocator.h" | 20 #include "src/compiler/register-allocator.h" |
22 #include "src/compiler/schedule.h" | 21 #include "src/compiler/schedule.h" |
23 #include "src/compiler/scheduler.h" | 22 #include "src/compiler/scheduler.h" |
24 #include "src/ostreams.h" | 23 #include "src/ostreams.h" |
25 | 24 |
26 namespace v8 { | 25 namespace v8 { |
27 namespace internal { | 26 namespace internal { |
28 namespace compiler { | 27 namespace compiler { |
29 | 28 |
| 29 static int SafeId(Node* node) { return node == NULL ? -1 : node->id(); } |
| 30 |
30 #define DEAD_COLOR "#999999" | 31 #define DEAD_COLOR "#999999" |
31 | 32 |
| 33 class AllNodes { |
| 34 public: |
| 35 enum State { kDead, kGray, kLive }; |
| 36 |
| 37 AllNodes(Zone* local_zone, const Graph* graph) |
| 38 : state(graph->NodeCount(), kDead, local_zone), |
| 39 live(local_zone), |
| 40 gray(local_zone) { |
| 41 Node* end = graph->end(); |
| 42 state[end->id()] = kLive; |
| 43 live.push_back(end); |
| 44 // Find all live nodes reachable from end. |
| 45 for (size_t i = 0; i < live.size(); i++) { |
| 46 for (Node* const input : live[i]->inputs()) { |
| 47 if (input == NULL) { |
| 48 // TODO(titzer): print a warning. |
| 49 continue; |
| 50 } |
| 51 if (input->id() >= graph->NodeCount()) { |
| 52 // TODO(titzer): print a warning. |
| 53 continue; |
| 54 } |
| 55 if (state[input->id()] != kLive) { |
| 56 live.push_back(input); |
| 57 state[input->id()] = kLive; |
| 58 } |
| 59 } |
| 60 } |
| 61 |
| 62 // Find all nodes that are not reachable from end that use live nodes. |
| 63 for (size_t i = 0; i < live.size(); i++) { |
| 64 for (Node* const use : live[i]->uses()) { |
| 65 if (state[use->id()] == kDead) { |
| 66 gray.push_back(use); |
| 67 state[use->id()] = kGray; |
| 68 } |
| 69 } |
| 70 } |
| 71 } |
| 72 |
| 73 bool IsLive(Node* node) { |
| 74 return node != NULL && node->id() < static_cast<int>(state.size()) && |
| 75 state[node->id()] == kLive; |
| 76 } |
| 77 |
| 78 ZoneVector<State> state; |
| 79 NodeVector live; |
| 80 NodeVector gray; |
| 81 }; |
| 82 |
| 83 |
32 class Escaped { | 84 class Escaped { |
33 public: | 85 public: |
34 explicit Escaped(const std::ostringstream& os, | 86 explicit Escaped(const std::ostringstream& os, |
35 const char* escaped_chars = "<>|{}") | 87 const char* escaped_chars = "<>|{}") |
36 : str_(os.str()), escaped_chars_(escaped_chars) {} | 88 : str_(os.str()), escaped_chars_(escaped_chars) {} |
37 | 89 |
38 friend std::ostream& operator<<(std::ostream& os, const Escaped& e) { | 90 friend std::ostream& operator<<(std::ostream& os, const Escaped& e) { |
39 for (std::string::const_iterator i = e.str_.begin(); i != e.str_.end(); | 91 for (std::string::const_iterator i = e.str_.begin(); i != e.str_.end(); |
40 ++i) { | 92 ++i) { |
41 if (e.needs_escape(*i)) os << "\\"; | 93 if (e.needs_escape(*i)) os << "\\"; |
42 os << *i; | 94 os << *i; |
43 } | 95 } |
44 return os; | 96 return os; |
45 } | 97 } |
46 | 98 |
47 private: | 99 private: |
48 bool needs_escape(char ch) const { | 100 bool needs_escape(char ch) const { |
49 for (size_t i = 0; i < strlen(escaped_chars_); ++i) { | 101 for (size_t i = 0; i < strlen(escaped_chars_); ++i) { |
50 if (ch == escaped_chars_[i]) return true; | 102 if (ch == escaped_chars_[i]) return true; |
51 } | 103 } |
52 return false; | 104 return false; |
53 } | 105 } |
54 | 106 |
55 const std::string str_; | 107 const std::string str_; |
56 const char* const escaped_chars_; | 108 const char* const escaped_chars_; |
57 }; | 109 }; |
58 | 110 |
59 class JSONGraphNodeWriter : public NullNodeVisitor { | 111 class JSONGraphNodeWriter { |
60 public: | 112 public: |
61 JSONGraphNodeWriter(std::ostream& os, Zone* zone, | 113 JSONGraphNodeWriter(std::ostream& os, Zone* zone, const Graph* graph) |
62 const Graph* graph) // NOLINT | 114 : os_(os), all_(zone, graph), first_node_(true) {} |
63 : os_(os), | |
64 graph_(graph), | |
65 first_node_(true) {} | |
66 | 115 |
67 void Print() { const_cast<Graph*>(graph_)->VisitNodeInputsFromEnd(this); } | 116 void Print() { |
| 117 for (Node* const node : all_.live) PrintNode(node); |
| 118 } |
68 | 119 |
69 void Pre(Node* node); | 120 void PrintNode(Node* node) { |
| 121 if (first_node_) { |
| 122 first_node_ = false; |
| 123 } else { |
| 124 os_ << ","; |
| 125 } |
| 126 std::ostringstream label; |
| 127 label << *node->op(); |
| 128 os_ << "{\"id\":" << SafeId(node) << ",\"label\":\"" << Escaped(label, "\"") |
| 129 << "\""; |
| 130 IrOpcode::Value opcode = node->opcode(); |
| 131 if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) { |
| 132 os_ << ",\"rankInputs\":[0," << NodeProperties::FirstControlIndex(node) |
| 133 << "]"; |
| 134 os_ << ",\"rankWithInput\":[" << NodeProperties::FirstControlIndex(node) |
| 135 << "]"; |
| 136 } else if (opcode == IrOpcode::kIfTrue || opcode == IrOpcode::kIfFalse || |
| 137 opcode == IrOpcode::kLoop) { |
| 138 os_ << ",\"rankInputs\":[" << NodeProperties::FirstControlIndex(node) |
| 139 << "]"; |
| 140 } |
| 141 if (opcode == IrOpcode::kBranch) { |
| 142 os_ << ",\"rankInputs\":[0]"; |
| 143 } |
| 144 os_ << ",\"opcode\":\"" << IrOpcode::Mnemonic(node->opcode()) << "\""; |
| 145 os_ << ",\"control\":" << (NodeProperties::IsControl(node) ? "true" |
| 146 : "false"); |
| 147 os_ << "}"; |
| 148 } |
70 | 149 |
71 private: | 150 private: |
72 std::ostream& os_; | 151 std::ostream& os_; |
73 const Graph* const graph_; | 152 AllNodes all_; |
74 bool first_node_; | 153 bool first_node_; |
75 | 154 |
76 DISALLOW_COPY_AND_ASSIGN(JSONGraphNodeWriter); | 155 DISALLOW_COPY_AND_ASSIGN(JSONGraphNodeWriter); |
77 }; | 156 }; |
78 | 157 |
79 | 158 |
80 void JSONGraphNodeWriter::Pre(Node* node) { | 159 class JSONGraphEdgeWriter { |
81 if (first_node_) { | 160 public: |
82 first_node_ = false; | 161 JSONGraphEdgeWriter(std::ostream& os, Zone* zone, const Graph* graph) |
83 } else { | 162 : os_(os), all_(zone, graph), first_edge_(true) {} |
84 os_ << ","; | 163 |
| 164 void Print() { |
| 165 for (Node* const node : all_.live) PrintEdges(node); |
85 } | 166 } |
86 std::ostringstream label; | 167 |
87 label << *node->op(); | 168 void PrintEdges(Node* node) { |
88 os_ << "{\"id\":" << node->id() << ",\"label\":\"" << Escaped(label, "\"") | 169 for (int i = 0; i < node->InputCount(); i++) { |
89 << "\""; | 170 Node* input = node->InputAt(i); |
90 IrOpcode::Value opcode = node->opcode(); | 171 if (input == NULL) continue; |
91 if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) { | 172 PrintEdge(node, i, input); |
92 os_ << ",\"rankInputs\":[0," << NodeProperties::FirstControlIndex(node) | 173 } |
93 << "]"; | |
94 os_ << ",\"rankWithInput\":[" << NodeProperties::FirstControlIndex(node) | |
95 << "]"; | |
96 } else if (opcode == IrOpcode::kIfTrue || opcode == IrOpcode::kIfFalse || | |
97 opcode == IrOpcode::kLoop) { | |
98 os_ << ",\"rankInputs\":[" << NodeProperties::FirstControlIndex(node) | |
99 << "]"; | |
100 } | 174 } |
101 if (opcode == IrOpcode::kBranch) { | 175 |
102 os_ << ",\"rankInputs\":[0]"; | 176 void PrintEdge(Node* from, int index, Node* to) { |
| 177 if (first_edge_) { |
| 178 first_edge_ = false; |
| 179 } else { |
| 180 os_ << ","; |
| 181 } |
| 182 const char* edge_type = NULL; |
| 183 if (index < NodeProperties::FirstValueIndex(from)) { |
| 184 edge_type = "unknown"; |
| 185 } else if (index < NodeProperties::FirstContextIndex(from)) { |
| 186 edge_type = "value"; |
| 187 } else if (index < NodeProperties::FirstFrameStateIndex(from)) { |
| 188 edge_type = "context"; |
| 189 } else if (index < NodeProperties::FirstEffectIndex(from)) { |
| 190 edge_type = "frame-state"; |
| 191 } else if (index < NodeProperties::FirstControlIndex(from)) { |
| 192 edge_type = "effect"; |
| 193 } else { |
| 194 edge_type = "control"; |
| 195 } |
| 196 os_ << "{\"source\":" << SafeId(to) << ",\"target\":" << SafeId(from) |
| 197 << ",\"index\":" << index << ",\"type\":\"" << edge_type << "\"}"; |
103 } | 198 } |
104 os_ << ",\"opcode\":\"" << IrOpcode::Mnemonic(node->opcode()) << "\""; | |
105 os_ << ",\"control\":" << (NodeProperties::IsControl(node) ? "true" | |
106 : "false"); | |
107 os_ << "}"; | |
108 } | |
109 | |
110 | |
111 class JSONGraphEdgeWriter : public NullNodeVisitor { | |
112 public: | |
113 JSONGraphEdgeWriter(std::ostream& os, Zone* zone, | |
114 const Graph* graph) // NOLINT | |
115 : os_(os), | |
116 graph_(graph), | |
117 first_edge_(true) {} | |
118 | |
119 void Print() { const_cast<Graph*>(graph_)->VisitNodeInputsFromEnd(this); } | |
120 | |
121 void PreEdge(Node* from, int index, Node* to); | |
122 | 199 |
123 private: | 200 private: |
124 std::ostream& os_; | 201 std::ostream& os_; |
125 const Graph* const graph_; | 202 AllNodes all_; |
126 bool first_edge_; | 203 bool first_edge_; |
127 | 204 |
128 DISALLOW_COPY_AND_ASSIGN(JSONGraphEdgeWriter); | 205 DISALLOW_COPY_AND_ASSIGN(JSONGraphEdgeWriter); |
129 }; | 206 }; |
130 | 207 |
131 | 208 |
132 void JSONGraphEdgeWriter::PreEdge(Node* from, int index, Node* to) { | |
133 if (first_edge_) { | |
134 first_edge_ = false; | |
135 } else { | |
136 os_ << ","; | |
137 } | |
138 const char* edge_type = NULL; | |
139 if (index < NodeProperties::FirstValueIndex(from)) { | |
140 edge_type = "unknown"; | |
141 } else if (index < NodeProperties::FirstContextIndex(from)) { | |
142 edge_type = "value"; | |
143 } else if (index < NodeProperties::FirstFrameStateIndex(from)) { | |
144 edge_type = "context"; | |
145 } else if (index < NodeProperties::FirstEffectIndex(from)) { | |
146 edge_type = "frame-state"; | |
147 } else if (index < NodeProperties::FirstControlIndex(from)) { | |
148 edge_type = "effect"; | |
149 } else { | |
150 edge_type = "control"; | |
151 } | |
152 os_ << "{\"source\":" << to->id() << ",\"target\":" << from->id() | |
153 << ",\"index\":" << index << ",\"type\":\"" << edge_type << "\"}"; | |
154 } | |
155 | |
156 | |
157 std::ostream& operator<<(std::ostream& os, const AsJSON& ad) { | 209 std::ostream& operator<<(std::ostream& os, const AsJSON& ad) { |
158 Zone tmp_zone(ad.graph.zone()->isolate()); | 210 Zone tmp_zone(ad.graph.zone()->isolate()); |
159 os << "{\"nodes\":["; | 211 os << "{\"nodes\":["; |
160 JSONGraphNodeWriter(os, &tmp_zone, &ad.graph).Print(); | 212 JSONGraphNodeWriter(os, &tmp_zone, &ad.graph).Print(); |
161 os << "],\"edges\":["; | 213 os << "],\"edges\":["; |
162 JSONGraphEdgeWriter(os, &tmp_zone, &ad.graph).Print(); | 214 JSONGraphEdgeWriter(os, &tmp_zone, &ad.graph).Print(); |
163 os << "]}"; | 215 os << "]}"; |
164 return os; | 216 return os; |
165 } | 217 } |
166 | 218 |
167 | 219 |
168 class GraphVisualizer : public NullNodeVisitor { | 220 class GraphVisualizer { |
169 public: | 221 public: |
170 GraphVisualizer(std::ostream& os, Zone* zone, const Graph* graph); // NOLINT | 222 GraphVisualizer(std::ostream& os, Zone* zone, const Graph* graph); // NOLINT |
171 | 223 |
172 void Print(); | 224 void Print(); |
173 | 225 |
174 void Pre(Node* node); | 226 void PrintNode(Node* node, bool gray); |
175 | 227 |
176 private: | 228 private: |
177 void AnnotateNode(Node* node); | |
178 void PrintEdge(Node::Edge edge); | 229 void PrintEdge(Node::Edge edge); |
179 | 230 |
180 Zone* zone_; | 231 Zone* zone_; |
181 NodeSet all_nodes_; | 232 AllNodes all_; |
182 NodeSet white_nodes_; | |
183 bool use_to_def_; | |
184 std::ostream& os_; | 233 std::ostream& os_; |
185 const Graph* const graph_; | 234 const Graph* const graph_; |
186 | 235 |
187 DISALLOW_COPY_AND_ASSIGN(GraphVisualizer); | 236 DISALLOW_COPY_AND_ASSIGN(GraphVisualizer); |
188 }; | 237 }; |
189 | 238 |
190 | 239 |
191 static Node* GetControlCluster(Node* node) { | 240 static Node* GetControlCluster(Node* node) { |
192 if (OperatorProperties::IsBasicBlockBegin(node->op())) { | 241 if (OperatorProperties::IsBasicBlockBegin(node->op())) { |
193 return node; | 242 return node; |
194 } else if (node->op()->ControlInputCount() == 1) { | 243 } else if (node->op()->ControlInputCount() == 1) { |
195 Node* control = NodeProperties::GetControlInput(node, 0); | 244 Node* control = NodeProperties::GetControlInput(node, 0); |
196 return OperatorProperties::IsBasicBlockBegin(control->op()) ? control | 245 return control != NULL && |
197 : NULL; | 246 OperatorProperties::IsBasicBlockBegin(control->op()) |
| 247 ? control |
| 248 : NULL; |
198 } else { | 249 } else { |
199 return NULL; | 250 return NULL; |
200 } | 251 } |
201 } | 252 } |
202 | 253 |
203 | 254 |
204 void GraphVisualizer::Pre(Node* node) { | 255 void GraphVisualizer::PrintNode(Node* node, bool gray) { |
205 if (all_nodes_.count(node) == 0) { | 256 Node* control_cluster = GetControlCluster(node); |
206 Node* control_cluster = GetControlCluster(node); | 257 if (control_cluster != NULL) { |
207 if (control_cluster != NULL) { | 258 os_ << " subgraph cluster_BasicBlock" << control_cluster->id() << " {\n"; |
208 os_ << " subgraph cluster_BasicBlock" << control_cluster->id() << " {\n"; | |
209 } | |
210 os_ << " ID" << node->id() << " [\n"; | |
211 AnnotateNode(node); | |
212 os_ << " ]\n"; | |
213 if (control_cluster != NULL) os_ << " }\n"; | |
214 all_nodes_.insert(node); | |
215 if (use_to_def_) white_nodes_.insert(node); | |
216 } | 259 } |
217 } | 260 os_ << " ID" << SafeId(node) << " [\n"; |
218 | |
219 | |
220 static bool IsLikelyBackEdge(Node* from, int index, Node* to) { | |
221 if (from->opcode() == IrOpcode::kPhi || | |
222 from->opcode() == IrOpcode::kEffectPhi) { | |
223 Node* control = NodeProperties::GetControlInput(from, 0); | |
224 return control->opcode() != IrOpcode::kMerge && control != to && index != 0; | |
225 } else if (from->opcode() == IrOpcode::kLoop) { | |
226 return index != 0; | |
227 } else { | |
228 return false; | |
229 } | |
230 } | |
231 | |
232 | |
233 void GraphVisualizer::AnnotateNode(Node* node) { | |
234 if (!use_to_def_) { | |
235 os_ << " style=\"filled\"\n" | |
236 << " fillcolor=\"" DEAD_COLOR "\"\n"; | |
237 } | |
238 | 261 |
239 os_ << " shape=\"record\"\n"; | 262 os_ << " shape=\"record\"\n"; |
240 switch (node->opcode()) { | 263 switch (node->opcode()) { |
241 case IrOpcode::kEnd: | 264 case IrOpcode::kEnd: |
242 case IrOpcode::kDead: | 265 case IrOpcode::kDead: |
243 case IrOpcode::kStart: | 266 case IrOpcode::kStart: |
244 os_ << " style=\"diagonals\"\n"; | 267 os_ << " style=\"diagonals\"\n"; |
245 break; | 268 break; |
246 case IrOpcode::kMerge: | 269 case IrOpcode::kMerge: |
247 case IrOpcode::kIfTrue: | 270 case IrOpcode::kIfTrue: |
248 case IrOpcode::kIfFalse: | 271 case IrOpcode::kIfFalse: |
249 case IrOpcode::kLoop: | 272 case IrOpcode::kLoop: |
250 os_ << " style=\"rounded\"\n"; | 273 os_ << " style=\"rounded\"\n"; |
251 break; | 274 break; |
252 default: | 275 default: |
253 break; | 276 break; |
254 } | 277 } |
255 | 278 |
| 279 if (gray) { |
| 280 os_ << " style=\"filled\"\n" |
| 281 << " fillcolor=\"" DEAD_COLOR "\"\n"; |
| 282 } |
| 283 |
256 std::ostringstream label; | 284 std::ostringstream label; |
257 label << *node->op(); | 285 label << *node->op(); |
258 os_ << " label=\"{{#" << node->id() << ":" << Escaped(label); | 286 os_ << " label=\"{{#" << SafeId(node) << ":" << Escaped(label); |
259 | 287 |
260 InputIter i = node->inputs().begin(); | 288 InputIter i = node->inputs().begin(); |
261 for (int j = node->op()->ValueInputCount(); j > 0; ++i, j--) { | 289 for (int j = node->op()->ValueInputCount(); j > 0; ++i, j--) { |
262 os_ << "|<I" << i.index() << ">#" << (*i)->id(); | 290 os_ << "|<I" << i.index() << ">#" << SafeId(*i); |
263 } | 291 } |
264 for (int j = OperatorProperties::GetContextInputCount(node->op()); j > 0; | 292 for (int j = OperatorProperties::GetContextInputCount(node->op()); j > 0; |
265 ++i, j--) { | 293 ++i, j--) { |
266 os_ << "|<I" << i.index() << ">X #" << (*i)->id(); | 294 os_ << "|<I" << i.index() << ">X #" << SafeId(*i); |
267 } | 295 } |
268 for (int j = OperatorProperties::GetFrameStateInputCount(node->op()); j > 0; | 296 for (int j = OperatorProperties::GetFrameStateInputCount(node->op()); j > 0; |
269 ++i, j--) { | 297 ++i, j--) { |
270 os_ << "|<I" << i.index() << ">F #" << (*i)->id(); | 298 os_ << "|<I" << i.index() << ">F #" << SafeId(*i); |
271 } | 299 } |
272 for (int j = node->op()->EffectInputCount(); j > 0; ++i, j--) { | 300 for (int j = node->op()->EffectInputCount(); j > 0; ++i, j--) { |
273 os_ << "|<I" << i.index() << ">E #" << (*i)->id(); | 301 os_ << "|<I" << i.index() << ">E #" << SafeId(*i); |
274 } | 302 } |
275 | 303 |
276 if (!use_to_def_ || OperatorProperties::IsBasicBlockBegin(node->op()) || | 304 if (OperatorProperties::IsBasicBlockBegin(node->op()) || |
277 GetControlCluster(node) == NULL) { | 305 GetControlCluster(node) == NULL) { |
278 for (int j = node->op()->ControlInputCount(); j > 0; ++i, j--) { | 306 for (int j = node->op()->ControlInputCount(); j > 0; ++i, j--) { |
279 os_ << "|<I" << i.index() << ">C #" << (*i)->id(); | 307 os_ << "|<I" << i.index() << ">C #" << SafeId(*i); |
280 } | 308 } |
281 } | 309 } |
282 os_ << "}"; | 310 os_ << "}"; |
283 | 311 |
284 if (FLAG_trace_turbo_types && NodeProperties::IsTyped(node)) { | 312 if (FLAG_trace_turbo_types && NodeProperties::IsTyped(node)) { |
285 Bounds bounds = NodeProperties::GetBounds(node); | 313 Bounds bounds = NodeProperties::GetBounds(node); |
286 std::ostringstream upper; | 314 std::ostringstream upper; |
287 bounds.upper->PrintTo(upper); | 315 bounds.upper->PrintTo(upper); |
288 std::ostringstream lower; | 316 std::ostringstream lower; |
289 bounds.lower->PrintTo(lower); | 317 bounds.lower->PrintTo(lower); |
290 os_ << "|" << Escaped(upper) << "|" << Escaped(lower); | 318 os_ << "|" << Escaped(upper) << "|" << Escaped(lower); |
291 } | 319 } |
292 os_ << "}\"\n"; | 320 os_ << "}\"\n"; |
| 321 |
| 322 os_ << " ]\n"; |
| 323 if (control_cluster != NULL) os_ << " }\n"; |
293 } | 324 } |
294 | 325 |
295 | 326 |
| 327 static bool IsLikelyBackEdge(Node* from, int index, Node* to) { |
| 328 if (from->opcode() == IrOpcode::kPhi || |
| 329 from->opcode() == IrOpcode::kEffectPhi) { |
| 330 Node* control = NodeProperties::GetControlInput(from, 0); |
| 331 return control != NULL && control->opcode() != IrOpcode::kMerge && |
| 332 control != to && index != 0; |
| 333 } else if (from->opcode() == IrOpcode::kLoop) { |
| 334 return index != 0; |
| 335 } else { |
| 336 return false; |
| 337 } |
| 338 } |
| 339 |
| 340 |
296 void GraphVisualizer::PrintEdge(Node::Edge edge) { | 341 void GraphVisualizer::PrintEdge(Node::Edge edge) { |
297 Node* from = edge.from(); | 342 Node* from = edge.from(); |
298 int index = edge.index(); | 343 int index = edge.index(); |
299 Node* to = edge.to(); | 344 Node* to = edge.to(); |
| 345 |
| 346 if (!all_.IsLive(to)) return; // skip inputs that point to dead or NULL. |
| 347 |
300 bool unconstrained = IsLikelyBackEdge(from, index, to); | 348 bool unconstrained = IsLikelyBackEdge(from, index, to); |
301 os_ << " ID" << from->id(); | 349 os_ << " ID" << SafeId(from); |
302 if (all_nodes_.count(to) == 0) { | 350 |
303 os_ << ":I" << index << ":n -> DEAD_INPUT"; | 351 if (OperatorProperties::IsBasicBlockBegin(from->op()) || |
304 } else if (OperatorProperties::IsBasicBlockBegin(from->op()) || | 352 GetControlCluster(from) == NULL || |
305 GetControlCluster(from) == NULL || | 353 (from->op()->ControlInputCount() > 0 && |
306 (from->op()->ControlInputCount() > 0 && | 354 NodeProperties::GetControlInput(from) != to)) { |
307 NodeProperties::GetControlInput(from) != to)) { | 355 os_ << ":I" << index << ":n -> ID" << SafeId(to) << ":s" |
308 os_ << ":I" << index << ":n -> ID" << to->id() << ":s" | |
309 << "[" << (unconstrained ? "constraint=false, " : "") | 356 << "[" << (unconstrained ? "constraint=false, " : "") |
310 << (NodeProperties::IsControlEdge(edge) ? "style=bold, " : "") | 357 << (NodeProperties::IsControlEdge(edge) ? "style=bold, " : "") |
311 << (NodeProperties::IsEffectEdge(edge) ? "style=dotted, " : "") | 358 << (NodeProperties::IsEffectEdge(edge) ? "style=dotted, " : "") |
312 << (NodeProperties::IsContextEdge(edge) ? "style=dashed, " : "") << "]"; | 359 << (NodeProperties::IsContextEdge(edge) ? "style=dashed, " : "") << "]"; |
313 } else { | 360 } else { |
314 os_ << " -> ID" << to->id() << ":s [color=transparent, " | 361 os_ << " -> ID" << SafeId(to) << ":s [color=transparent, " |
315 << (unconstrained ? "constraint=false, " : "") | 362 << (unconstrained ? "constraint=false, " : "") |
316 << (NodeProperties::IsControlEdge(edge) ? "style=dashed, " : "") << "]"; | 363 << (NodeProperties::IsControlEdge(edge) ? "style=dashed, " : "") << "]"; |
317 } | 364 } |
318 os_ << "\n"; | 365 os_ << "\n"; |
319 } | 366 } |
320 | 367 |
321 | 368 |
322 void GraphVisualizer::Print() { | 369 void GraphVisualizer::Print() { |
323 os_ << "digraph D {\n" | 370 os_ << "digraph D {\n" |
324 << " node [fontsize=8,height=0.25]\n" | 371 << " node [fontsize=8,height=0.25]\n" |
325 << " rankdir=\"BT\"\n" | 372 << " rankdir=\"BT\"\n" |
326 << " ranksep=\"1.2 equally\"\n" | 373 << " ranksep=\"1.2 equally\"\n" |
327 << " overlap=\"false\"\n" | 374 << " overlap=\"false\"\n" |
328 << " splines=\"true\"\n" | 375 << " splines=\"true\"\n" |
329 << " concentrate=\"true\"\n" | 376 << " concentrate=\"true\"\n" |
330 << " \n"; | 377 << " \n"; |
331 | 378 |
332 // Make sure all nodes have been output before writing out the edges. | 379 // Make sure all nodes have been output before writing out the edges. |
333 use_to_def_ = true; | 380 for (Node* const node : all_.live) PrintNode(node, false); |
334 // TODO(svenpanne) Remove the need for the const_casts. | 381 for (Node* const node : all_.gray) PrintNode(node, true); |
335 const_cast<Graph*>(graph_)->VisitNodeInputsFromEnd(this); | |
336 white_nodes_.insert(const_cast<Graph*>(graph_)->start()); | |
337 | |
338 // Visit all uses of white nodes. | |
339 use_to_def_ = false; | |
340 GenericGraphVisit::Visit<GraphVisualizer, NodeUseIterationTraits<Node> >( | |
341 const_cast<Graph*>(graph_), zone_, white_nodes_.begin(), | |
342 white_nodes_.end(), this); | |
343 | |
344 os_ << " DEAD_INPUT [\n" | |
345 << " style=\"filled\" \n" | |
346 << " fillcolor=\"" DEAD_COLOR "\"\n" | |
347 << " ]\n" | |
348 << "\n"; | |
349 | 382 |
350 // With all the nodes written, add the edges. | 383 // With all the nodes written, add the edges. |
351 for (NodeSetIter i = all_nodes_.begin(); i != all_nodes_.end(); ++i) { | 384 for (Node* const node : all_.live) { |
352 Node::Inputs inputs = (*i)->inputs(); | 385 for (UseIter i = node->uses().begin(); i != node->uses().end(); ++i) { |
353 for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end(); | 386 PrintEdge(i.edge()); |
354 ++iter) { | |
355 PrintEdge(iter.edge()); | |
356 } | 387 } |
357 } | 388 } |
358 os_ << "}\n"; | 389 os_ << "}\n"; |
359 } | 390 } |
360 | 391 |
361 | 392 |
362 GraphVisualizer::GraphVisualizer(std::ostream& os, Zone* zone, | 393 GraphVisualizer::GraphVisualizer(std::ostream& os, Zone* zone, |
363 const Graph* graph) // NOLINT | 394 const Graph* graph) // NOLINT |
364 : zone_(zone), | 395 : zone_(zone), |
365 all_nodes_(NodeSet::key_compare(), NodeSet::allocator_type(zone)), | 396 all_(zone, graph), |
366 white_nodes_(NodeSet::key_compare(), NodeSet::allocator_type(zone)), | |
367 use_to_def_(true), | |
368 os_(os), | 397 os_(os), |
369 graph_(graph) {} | 398 graph_(graph) {} |
370 | 399 |
371 | 400 |
372 std::ostream& operator<<(std::ostream& os, const AsDOT& ad) { | 401 std::ostream& operator<<(std::ostream& os, const AsDOT& ad) { |
373 Zone tmp_zone(ad.graph.zone()->isolate()); | 402 Zone tmp_zone(ad.graph.zone()->isolate()); |
374 GraphVisualizer(os, &tmp_zone, &ad.graph).Print(); | 403 GraphVisualizer(os, &tmp_zone, &ad.graph).Print(); |
375 return os; | 404 return os; |
376 } | 405 } |
377 | 406 |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
478 } else { | 507 } else { |
479 CodeStub::Major major_key = info->code_stub()->MajorKey(); | 508 CodeStub::Major major_key = info->code_stub()->MajorKey(); |
480 PrintStringProperty("name", CodeStub::MajorName(major_key, false)); | 509 PrintStringProperty("name", CodeStub::MajorName(major_key, false)); |
481 PrintStringProperty("method", "stub"); | 510 PrintStringProperty("method", "stub"); |
482 } | 511 } |
483 PrintLongProperty("date", | 512 PrintLongProperty("date", |
484 static_cast<int64_t>(base::OS::TimeCurrentMillis())); | 513 static_cast<int64_t>(base::OS::TimeCurrentMillis())); |
485 } | 514 } |
486 | 515 |
487 | 516 |
488 void GraphC1Visualizer::PrintNodeId(Node* n) { os_ << "n" << n->id(); } | 517 void GraphC1Visualizer::PrintNodeId(Node* n) { os_ << "n" << SafeId(n); } |
489 | 518 |
490 | 519 |
491 void GraphC1Visualizer::PrintNode(Node* n) { | 520 void GraphC1Visualizer::PrintNode(Node* n) { |
492 PrintNodeId(n); | 521 PrintNodeId(n); |
493 os_ << " " << *n->op() << " "; | 522 os_ << " " << *n->op() << " "; |
494 PrintInputs(n); | 523 PrintInputs(n); |
495 } | 524 } |
496 | 525 |
497 | 526 |
498 void GraphC1Visualizer::PrintInputs(InputIter* i, int count, | 527 void GraphC1Visualizer::PrintInputs(InputIter* i, int count, |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
759 | 788 |
760 | 789 |
761 std::ostream& operator<<(std::ostream& os, const AsC1VAllocator& ac) { | 790 std::ostream& operator<<(std::ostream& os, const AsC1VAllocator& ac) { |
762 Zone tmp_zone(ac.allocator_->code()->zone()->isolate()); | 791 Zone tmp_zone(ac.allocator_->code()->zone()->isolate()); |
763 GraphC1Visualizer(os, &tmp_zone).PrintAllocator(ac.phase_, ac.allocator_); | 792 GraphC1Visualizer(os, &tmp_zone).PrintAllocator(ac.phase_, ac.allocator_); |
764 return os; | 793 return os; |
765 } | 794 } |
766 } | 795 } |
767 } | 796 } |
768 } // namespace v8::internal::compiler | 797 } // namespace v8::internal::compiler |
OLD | NEW |