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 "src/compiler/generic-algorithm.h" | 7 #include "src/compiler/generic-algorithm.h" |
8 #include "src/compiler/generic-node.h" | 8 #include "src/compiler/generic-node.h" |
9 #include "src/compiler/generic-node-inl.h" | 9 #include "src/compiler/generic-node-inl.h" |
10 #include "src/compiler/graph.h" | 10 #include "src/compiler/graph.h" |
11 #include "src/compiler/graph-inl.h" | 11 #include "src/compiler/graph-inl.h" |
12 #include "src/compiler/node.h" | 12 #include "src/compiler/node.h" |
13 #include "src/compiler/node-properties.h" | 13 #include "src/compiler/node-properties.h" |
14 #include "src/compiler/node-properties-inl.h" | 14 #include "src/compiler/node-properties-inl.h" |
15 #include "src/compiler/opcodes.h" | 15 #include "src/compiler/opcodes.h" |
16 #include "src/compiler/operator.h" | 16 #include "src/compiler/operator.h" |
17 #include "src/ostreams.h" | 17 #include "src/ostreams.h" |
18 | 18 |
19 namespace v8 { | 19 namespace v8 { |
20 namespace internal { | 20 namespace internal { |
21 namespace compiler { | 21 namespace compiler { |
22 | 22 |
23 #define DEAD_COLOR "#999999" | 23 #define DEAD_COLOR "#999999" |
24 | 24 |
25 class Escaped { | |
26 public: | |
27 explicit Escaped(const OStringStream& os, const char* escaped_chars = "<>|{}") | |
28 : str_(os.c_str()), escaped_chars_(escaped_chars) {} | |
29 | |
30 friend OStream& operator<<(OStream& os, const Escaped& e) { | |
31 for (const char* s = e.str_; *s != '\0'; ++s) { | |
32 if (e.needs_escape(*s)) os << "\\"; | |
33 os << *s; | |
34 } | |
35 return os; | |
36 } | |
37 | |
38 private: | |
39 bool needs_escape(char ch) const { | |
40 for (size_t i = 0; i < strlen(escaped_chars_); ++i) { | |
41 if (ch == escaped_chars_[i]) return true; | |
42 } | |
43 return false; | |
44 } | |
45 | |
46 const char* const str_; | |
47 const char* const escaped_chars_; | |
48 }; | |
49 | |
50 class JSONGraphNodeWriter : public NullNodeVisitor { | |
51 public: | |
52 JSONGraphNodeWriter(OStream& os, Zone* zone, const Graph* graph) // NOLINT | |
53 : os_(os), | |
54 graph_(graph), | |
55 first_node_(true) {} | |
56 | |
57 void Print() { const_cast<Graph*>(graph_)->VisitNodeInputsFromEnd(this); } | |
58 | |
59 GenericGraphVisit::Control Pre(Node* node); | |
60 | |
61 private: | |
62 OStream& os_; | |
63 const Graph* const graph_; | |
64 bool first_node_; | |
65 | |
66 DISALLOW_COPY_AND_ASSIGN(JSONGraphNodeWriter); | |
67 }; | |
68 | |
69 | |
70 GenericGraphVisit::Control JSONGraphNodeWriter::Pre(Node* node) { | |
71 if (first_node_) { | |
72 first_node_ = false; | |
73 } else { | |
74 os_ << ","; | |
75 } | |
76 OStringStream label; | |
77 label << *node->op(); | |
78 os_ << "{\"id\":" << node->id() << ",\"label\":\"" << Escaped(label, "\"") | |
79 << "\""; | |
80 IrOpcode::Value opcode = node->opcode(); | |
81 if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) { | |
82 os_ << ",\"rankInputs\":[0," << NodeProperties::FirstControlIndex(node) | |
83 << "]"; | |
84 os_ << ",\"rankWithInput\":[" << NodeProperties::FirstControlIndex(node) | |
85 << "]"; | |
86 } else if (opcode == IrOpcode::kIfTrue || opcode == IrOpcode::kIfFalse || | |
87 opcode == IrOpcode::kLoop) { | |
88 os_ << ",\"rankInputs\":[" << NodeProperties::FirstControlIndex(node) | |
89 << "]"; | |
90 } | |
91 if (opcode == IrOpcode::kBranch) { | |
92 os_ << ",\"rankInputs\":[0]"; | |
93 } | |
94 if (NodeProperties::IsControl(node)) { | |
95 os_ << ",\"control\":true"; | |
96 } | |
97 os_ << ",\"visible\":true"; | |
98 os_ << "}"; | |
99 return GenericGraphVisit::CONTINUE; | |
100 } | |
101 | |
102 | |
103 class JSONGraphEdgeWriter : public NullNodeVisitor { | |
104 public: | |
105 JSONGraphEdgeWriter(OStream& os, Zone* zone, const Graph* graph) // NOLINT | |
106 : os_(os), | |
107 graph_(graph), | |
108 first_edge_(true) {} | |
109 | |
110 void Print() { const_cast<Graph*>(graph_)->VisitNodeInputsFromEnd(this); } | |
111 | |
112 GenericGraphVisit::Control PreEdge(Node* from, int index, Node* to); | |
113 | |
114 private: | |
115 OStream& os_; | |
116 const Graph* const graph_; | |
117 bool first_edge_; | |
118 | |
119 DISALLOW_COPY_AND_ASSIGN(JSONGraphEdgeWriter); | |
120 }; | |
121 | |
122 | |
123 GenericGraphVisit::Control JSONGraphEdgeWriter::PreEdge(Node* from, int index, | |
124 Node* to) { | |
125 if (first_edge_) { | |
126 first_edge_ = false; | |
127 } else { | |
128 os_ << ","; | |
129 } | |
130 IrOpcode::Value opcode = from->opcode(); | |
131 bool visible = (NodeProperties::IsControl(from) || opcode == IrOpcode::kPhi || | |
Michael Starzinger
2014/09/25 08:40:06
suggestion: In the long run we could try to encode
| |
132 opcode == IrOpcode::kEffectPhi || | |
133 index < NodeProperties::FirstControlIndex(from)) && | |
134 to->UseCount() < 16; | |
135 os_ << "{\"source\":" << to->id() << ",\"target\":" << from->id() | |
136 << ",\"index\":" << index | |
137 << ",\"visible\":" << (visible ? "true" : "false") << "}"; | |
138 return GenericGraphVisit::CONTINUE; | |
139 } | |
140 | |
141 | |
142 OStream& operator<<(OStream& os, const AsJSON& ad) { | |
143 Zone tmp_zone(ad.graph.zone()->isolate()); | |
144 os << "{\"nodes\":["; | |
145 JSONGraphNodeWriter(os, &tmp_zone, &ad.graph).Print(); | |
146 os << "],\"edges\":["; | |
147 JSONGraphEdgeWriter(os, &tmp_zone, &ad.graph).Print(); | |
148 os << "]}"; | |
149 return os; | |
150 } | |
151 | |
152 | |
25 class GraphVisualizer : public NullNodeVisitor { | 153 class GraphVisualizer : public NullNodeVisitor { |
26 public: | 154 public: |
27 GraphVisualizer(OStream& os, Zone* zone, const Graph* graph); // NOLINT | 155 GraphVisualizer(OStream& os, Zone* zone, const Graph* graph); // NOLINT |
28 | 156 |
29 void Print(); | 157 void Print(); |
30 | 158 |
31 GenericGraphVisit::Control Pre(Node* node); | 159 GenericGraphVisit::Control Pre(Node* node); |
32 GenericGraphVisit::Control PreEdge(Node* from, int index, Node* to); | 160 GenericGraphVisit::Control PreEdge(Node* from, int index, Node* to); |
33 | 161 |
34 private: | 162 private: |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
80 Node* to) { | 208 Node* to) { |
81 if (use_to_def_) return GenericGraphVisit::CONTINUE; | 209 if (use_to_def_) return GenericGraphVisit::CONTINUE; |
82 // When going from def to use, only consider white -> other edges, which are | 210 // When going from def to use, only consider white -> other edges, which are |
83 // the dead nodes that use live nodes. We're probably not interested in | 211 // the dead nodes that use live nodes. We're probably not interested in |
84 // dead nodes that only use other dead nodes. | 212 // dead nodes that only use other dead nodes. |
85 if (white_nodes_.count(from) > 0) return GenericGraphVisit::CONTINUE; | 213 if (white_nodes_.count(from) > 0) return GenericGraphVisit::CONTINUE; |
86 return GenericGraphVisit::SKIP; | 214 return GenericGraphVisit::SKIP; |
87 } | 215 } |
88 | 216 |
89 | 217 |
90 class Escaped { | |
91 public: | |
92 explicit Escaped(const OStringStream& os) : str_(os.c_str()) {} | |
93 | |
94 friend OStream& operator<<(OStream& os, const Escaped& e) { | |
95 for (const char* s = e.str_; *s != '\0'; ++s) { | |
96 if (needs_escape(*s)) os << "\\"; | |
97 os << *s; | |
98 } | |
99 return os; | |
100 } | |
101 | |
102 private: | |
103 static bool needs_escape(char ch) { | |
104 switch (ch) { | |
105 case '>': | |
106 case '<': | |
107 case '|': | |
108 case '}': | |
109 case '{': | |
110 return true; | |
111 default: | |
112 return false; | |
113 } | |
114 } | |
115 | |
116 const char* const str_; | |
117 }; | |
118 | |
119 | |
120 static bool IsLikelyBackEdge(Node* from, int index, Node* to) { | 218 static bool IsLikelyBackEdge(Node* from, int index, Node* to) { |
121 if (from->opcode() == IrOpcode::kPhi || | 219 if (from->opcode() == IrOpcode::kPhi || |
122 from->opcode() == IrOpcode::kEffectPhi) { | 220 from->opcode() == IrOpcode::kEffectPhi) { |
123 Node* control = NodeProperties::GetControlInput(from, 0); | 221 Node* control = NodeProperties::GetControlInput(from, 0); |
124 return control->opcode() != IrOpcode::kMerge && control != to && index != 0; | 222 return control->opcode() != IrOpcode::kMerge && control != to && index != 0; |
125 } else if (from->opcode() == IrOpcode::kLoop) { | 223 } else if (from->opcode() == IrOpcode::kLoop) { |
126 return index != 0; | 224 return index != 0; |
127 } else { | 225 } else { |
128 return false; | 226 return false; |
129 } | 227 } |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
273 | 371 |
274 | 372 |
275 OStream& operator<<(OStream& os, const AsDOT& ad) { | 373 OStream& operator<<(OStream& os, const AsDOT& ad) { |
276 Zone tmp_zone(ad.graph.zone()->isolate()); | 374 Zone tmp_zone(ad.graph.zone()->isolate()); |
277 GraphVisualizer(os, &tmp_zone, &ad.graph).Print(); | 375 GraphVisualizer(os, &tmp_zone, &ad.graph).Print(); |
278 return os; | 376 return os; |
279 } | 377 } |
280 } | 378 } |
281 } | 379 } |
282 } // namespace v8::internal::compiler | 380 } // namespace v8::internal::compiler |
OLD | NEW |