| 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> |
| 8 #include <string> |
| 9 |
| 7 #include "src/compiler/generic-algorithm.h" | 10 #include "src/compiler/generic-algorithm.h" |
| 8 #include "src/compiler/generic-node.h" | 11 #include "src/compiler/generic-node.h" |
| 9 #include "src/compiler/generic-node-inl.h" | 12 #include "src/compiler/generic-node-inl.h" |
| 10 #include "src/compiler/graph.h" | 13 #include "src/compiler/graph.h" |
| 11 #include "src/compiler/graph-inl.h" | 14 #include "src/compiler/graph-inl.h" |
| 12 #include "src/compiler/node.h" | 15 #include "src/compiler/node.h" |
| 13 #include "src/compiler/node-properties.h" | 16 #include "src/compiler/node-properties.h" |
| 14 #include "src/compiler/node-properties-inl.h" | 17 #include "src/compiler/node-properties-inl.h" |
| 15 #include "src/compiler/opcodes.h" | 18 #include "src/compiler/opcodes.h" |
| 16 #include "src/compiler/operator.h" | 19 #include "src/compiler/operator.h" |
| 17 #include "src/ostreams.h" | 20 #include "src/ostreams.h" |
| 18 | 21 |
| 19 namespace v8 { | 22 namespace v8 { |
| 20 namespace internal { | 23 namespace internal { |
| 21 namespace compiler { | 24 namespace compiler { |
| 22 | 25 |
| 23 #define DEAD_COLOR "#999999" | 26 #define DEAD_COLOR "#999999" |
| 24 | 27 |
| 25 class Escaped { | 28 class Escaped { |
| 26 public: | 29 public: |
| 27 explicit Escaped(const OStringStream& os, const char* escaped_chars = "<>|{}") | 30 explicit Escaped(const std::ostringstream& os, |
| 28 : str_(os.c_str()), escaped_chars_(escaped_chars) {} | 31 const char* escaped_chars = "<>|{}") |
| 32 : str_(os.str()), escaped_chars_(escaped_chars) {} |
| 29 | 33 |
| 30 friend OStream& operator<<(OStream& os, const Escaped& e) { | 34 friend std::ostream& operator<<(std::ostream& os, const Escaped& e) { |
| 31 for (const char* s = e.str_; *s != '\0'; ++s) { | 35 for (std::string::const_iterator i = e.str_.begin(); i != e.str_.end(); |
| 32 if (e.needs_escape(*s)) os << "\\"; | 36 ++i) { |
| 33 os << *s; | 37 if (e.needs_escape(*i)) os << "\\"; |
| 38 os << *i; |
| 34 } | 39 } |
| 35 return os; | 40 return os; |
| 36 } | 41 } |
| 37 | 42 |
| 38 private: | 43 private: |
| 39 bool needs_escape(char ch) const { | 44 bool needs_escape(char ch) const { |
| 40 for (size_t i = 0; i < strlen(escaped_chars_); ++i) { | 45 for (size_t i = 0; i < strlen(escaped_chars_); ++i) { |
| 41 if (ch == escaped_chars_[i]) return true; | 46 if (ch == escaped_chars_[i]) return true; |
| 42 } | 47 } |
| 43 return false; | 48 return false; |
| 44 } | 49 } |
| 45 | 50 |
| 46 const char* const str_; | 51 const std::string str_; |
| 47 const char* const escaped_chars_; | 52 const char* const escaped_chars_; |
| 48 }; | 53 }; |
| 49 | 54 |
| 50 class JSONGraphNodeWriter : public NullNodeVisitor { | 55 class JSONGraphNodeWriter : public NullNodeVisitor { |
| 51 public: | 56 public: |
| 52 JSONGraphNodeWriter(OStream& os, Zone* zone, const Graph* graph) // NOLINT | 57 JSONGraphNodeWriter(std::ostream& os, Zone* zone, |
| 58 const Graph* graph) // NOLINT |
| 53 : os_(os), | 59 : os_(os), |
| 54 graph_(graph), | 60 graph_(graph), |
| 55 first_node_(true) {} | 61 first_node_(true) {} |
| 56 | 62 |
| 57 void Print() { const_cast<Graph*>(graph_)->VisitNodeInputsFromEnd(this); } | 63 void Print() { const_cast<Graph*>(graph_)->VisitNodeInputsFromEnd(this); } |
| 58 | 64 |
| 59 GenericGraphVisit::Control Pre(Node* node); | 65 GenericGraphVisit::Control Pre(Node* node); |
| 60 | 66 |
| 61 private: | 67 private: |
| 62 OStream& os_; | 68 std::ostream& os_; |
| 63 const Graph* const graph_; | 69 const Graph* const graph_; |
| 64 bool first_node_; | 70 bool first_node_; |
| 65 | 71 |
| 66 DISALLOW_COPY_AND_ASSIGN(JSONGraphNodeWriter); | 72 DISALLOW_COPY_AND_ASSIGN(JSONGraphNodeWriter); |
| 67 }; | 73 }; |
| 68 | 74 |
| 69 | 75 |
| 70 GenericGraphVisit::Control JSONGraphNodeWriter::Pre(Node* node) { | 76 GenericGraphVisit::Control JSONGraphNodeWriter::Pre(Node* node) { |
| 71 if (first_node_) { | 77 if (first_node_) { |
| 72 first_node_ = false; | 78 first_node_ = false; |
| 73 } else { | 79 } else { |
| 74 os_ << ","; | 80 os_ << ","; |
| 75 } | 81 } |
| 76 OStringStream label; | 82 std::ostringstream label; |
| 77 label << *node->op(); | 83 label << *node->op(); |
| 78 os_ << "{\"id\":" << node->id() << ",\"label\":\"" << Escaped(label, "\"") | 84 os_ << "{\"id\":" << node->id() << ",\"label\":\"" << Escaped(label, "\"") |
| 79 << "\""; | 85 << "\""; |
| 80 IrOpcode::Value opcode = node->opcode(); | 86 IrOpcode::Value opcode = node->opcode(); |
| 81 if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) { | 87 if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) { |
| 82 os_ << ",\"rankInputs\":[0," << NodeProperties::FirstControlIndex(node) | 88 os_ << ",\"rankInputs\":[0," << NodeProperties::FirstControlIndex(node) |
| 83 << "]"; | 89 << "]"; |
| 84 os_ << ",\"rankWithInput\":[" << NodeProperties::FirstControlIndex(node) | 90 os_ << ",\"rankWithInput\":[" << NodeProperties::FirstControlIndex(node) |
| 85 << "]"; | 91 << "]"; |
| 86 } else if (opcode == IrOpcode::kIfTrue || opcode == IrOpcode::kIfFalse || | 92 } else if (opcode == IrOpcode::kIfTrue || opcode == IrOpcode::kIfFalse || |
| 87 opcode == IrOpcode::kLoop) { | 93 opcode == IrOpcode::kLoop) { |
| 88 os_ << ",\"rankInputs\":[" << NodeProperties::FirstControlIndex(node) | 94 os_ << ",\"rankInputs\":[" << NodeProperties::FirstControlIndex(node) |
| 89 << "]"; | 95 << "]"; |
| 90 } | 96 } |
| 91 if (opcode == IrOpcode::kBranch) { | 97 if (opcode == IrOpcode::kBranch) { |
| 92 os_ << ",\"rankInputs\":[0]"; | 98 os_ << ",\"rankInputs\":[0]"; |
| 93 } | 99 } |
| 94 os_ << ",\"opcode\":\"" << IrOpcode::Mnemonic(node->opcode()) << "\""; | 100 os_ << ",\"opcode\":\"" << IrOpcode::Mnemonic(node->opcode()) << "\""; |
| 95 os_ << ",\"control\":" << (NodeProperties::IsControl(node) ? "true" | 101 os_ << ",\"control\":" << (NodeProperties::IsControl(node) ? "true" |
| 96 : "false"); | 102 : "false"); |
| 97 os_ << "}"; | 103 os_ << "}"; |
| 98 return GenericGraphVisit::CONTINUE; | 104 return GenericGraphVisit::CONTINUE; |
| 99 } | 105 } |
| 100 | 106 |
| 101 | 107 |
| 102 class JSONGraphEdgeWriter : public NullNodeVisitor { | 108 class JSONGraphEdgeWriter : public NullNodeVisitor { |
| 103 public: | 109 public: |
| 104 JSONGraphEdgeWriter(OStream& os, Zone* zone, const Graph* graph) // NOLINT | 110 JSONGraphEdgeWriter(std::ostream& os, Zone* zone, |
| 111 const Graph* graph) // NOLINT |
| 105 : os_(os), | 112 : os_(os), |
| 106 graph_(graph), | 113 graph_(graph), |
| 107 first_edge_(true) {} | 114 first_edge_(true) {} |
| 108 | 115 |
| 109 void Print() { const_cast<Graph*>(graph_)->VisitNodeInputsFromEnd(this); } | 116 void Print() { const_cast<Graph*>(graph_)->VisitNodeInputsFromEnd(this); } |
| 110 | 117 |
| 111 GenericGraphVisit::Control PreEdge(Node* from, int index, Node* to); | 118 GenericGraphVisit::Control PreEdge(Node* from, int index, Node* to); |
| 112 | 119 |
| 113 private: | 120 private: |
| 114 OStream& os_; | 121 std::ostream& os_; |
| 115 const Graph* const graph_; | 122 const Graph* const graph_; |
| 116 bool first_edge_; | 123 bool first_edge_; |
| 117 | 124 |
| 118 DISALLOW_COPY_AND_ASSIGN(JSONGraphEdgeWriter); | 125 DISALLOW_COPY_AND_ASSIGN(JSONGraphEdgeWriter); |
| 119 }; | 126 }; |
| 120 | 127 |
| 121 | 128 |
| 122 GenericGraphVisit::Control JSONGraphEdgeWriter::PreEdge(Node* from, int index, | 129 GenericGraphVisit::Control JSONGraphEdgeWriter::PreEdge(Node* from, int index, |
| 123 Node* to) { | 130 Node* to) { |
| 124 if (first_edge_) { | 131 if (first_edge_) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 139 edge_type = "effect"; | 146 edge_type = "effect"; |
| 140 } else { | 147 } else { |
| 141 edge_type = "control"; | 148 edge_type = "control"; |
| 142 } | 149 } |
| 143 os_ << "{\"source\":" << to->id() << ",\"target\":" << from->id() | 150 os_ << "{\"source\":" << to->id() << ",\"target\":" << from->id() |
| 144 << ",\"index\":" << index << ",\"type\":\"" << edge_type << "\"}"; | 151 << ",\"index\":" << index << ",\"type\":\"" << edge_type << "\"}"; |
| 145 return GenericGraphVisit::CONTINUE; | 152 return GenericGraphVisit::CONTINUE; |
| 146 } | 153 } |
| 147 | 154 |
| 148 | 155 |
| 149 OStream& operator<<(OStream& os, const AsJSON& ad) { | 156 std::ostream& operator<<(std::ostream& os, const AsJSON& ad) { |
| 150 Zone tmp_zone(ad.graph.zone()->isolate()); | 157 Zone tmp_zone(ad.graph.zone()->isolate()); |
| 151 os << "{\"nodes\":["; | 158 os << "{\"nodes\":["; |
| 152 JSONGraphNodeWriter(os, &tmp_zone, &ad.graph).Print(); | 159 JSONGraphNodeWriter(os, &tmp_zone, &ad.graph).Print(); |
| 153 os << "],\"edges\":["; | 160 os << "],\"edges\":["; |
| 154 JSONGraphEdgeWriter(os, &tmp_zone, &ad.graph).Print(); | 161 JSONGraphEdgeWriter(os, &tmp_zone, &ad.graph).Print(); |
| 155 os << "]}"; | 162 os << "]}"; |
| 156 return os; | 163 return os; |
| 157 } | 164 } |
| 158 | 165 |
| 159 | 166 |
| 160 class GraphVisualizer : public NullNodeVisitor { | 167 class GraphVisualizer : public NullNodeVisitor { |
| 161 public: | 168 public: |
| 162 GraphVisualizer(OStream& os, Zone* zone, const Graph* graph); // NOLINT | 169 GraphVisualizer(std::ostream& os, Zone* zone, const Graph* graph); // NOLINT |
| 163 | 170 |
| 164 void Print(); | 171 void Print(); |
| 165 | 172 |
| 166 GenericGraphVisit::Control Pre(Node* node); | 173 GenericGraphVisit::Control Pre(Node* node); |
| 167 GenericGraphVisit::Control PreEdge(Node* from, int index, Node* to); | 174 GenericGraphVisit::Control PreEdge(Node* from, int index, Node* to); |
| 168 | 175 |
| 169 private: | 176 private: |
| 170 void AnnotateNode(Node* node); | 177 void AnnotateNode(Node* node); |
| 171 void PrintEdge(Node::Edge edge); | 178 void PrintEdge(Node::Edge edge); |
| 172 | 179 |
| 173 Zone* zone_; | 180 Zone* zone_; |
| 174 NodeSet all_nodes_; | 181 NodeSet all_nodes_; |
| 175 NodeSet white_nodes_; | 182 NodeSet white_nodes_; |
| 176 bool use_to_def_; | 183 bool use_to_def_; |
| 177 OStream& os_; | 184 std::ostream& os_; |
| 178 const Graph* const graph_; | 185 const Graph* const graph_; |
| 179 | 186 |
| 180 DISALLOW_COPY_AND_ASSIGN(GraphVisualizer); | 187 DISALLOW_COPY_AND_ASSIGN(GraphVisualizer); |
| 181 }; | 188 }; |
| 182 | 189 |
| 183 | 190 |
| 184 static Node* GetControlCluster(Node* node) { | 191 static Node* GetControlCluster(Node* node) { |
| 185 if (OperatorProperties::IsBasicBlockBegin(node->op())) { | 192 if (OperatorProperties::IsBasicBlockBegin(node->op())) { |
| 186 return node; | 193 return node; |
| 187 } else if (OperatorProperties::GetControlInputCount(node->op()) == 1) { | 194 } else if (OperatorProperties::GetControlInputCount(node->op()) == 1) { |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 251 case IrOpcode::kMerge: | 258 case IrOpcode::kMerge: |
| 252 case IrOpcode::kIfTrue: | 259 case IrOpcode::kIfTrue: |
| 253 case IrOpcode::kIfFalse: | 260 case IrOpcode::kIfFalse: |
| 254 case IrOpcode::kLoop: | 261 case IrOpcode::kLoop: |
| 255 os_ << " style=\"rounded\"\n"; | 262 os_ << " style=\"rounded\"\n"; |
| 256 break; | 263 break; |
| 257 default: | 264 default: |
| 258 break; | 265 break; |
| 259 } | 266 } |
| 260 | 267 |
| 261 OStringStream label; | 268 std::ostringstream label; |
| 262 label << *node->op(); | 269 label << *node->op(); |
| 263 os_ << " label=\"{{#" << node->id() << ":" << Escaped(label); | 270 os_ << " label=\"{{#" << node->id() << ":" << Escaped(label); |
| 264 | 271 |
| 265 InputIter i = node->inputs().begin(); | 272 InputIter i = node->inputs().begin(); |
| 266 for (int j = OperatorProperties::GetValueInputCount(node->op()); j > 0; | 273 for (int j = OperatorProperties::GetValueInputCount(node->op()); j > 0; |
| 267 ++i, j--) { | 274 ++i, j--) { |
| 268 os_ << "|<I" << i.index() << ">#" << (*i)->id(); | 275 os_ << "|<I" << i.index() << ">#" << (*i)->id(); |
| 269 } | 276 } |
| 270 for (int j = OperatorProperties::GetContextInputCount(node->op()); j > 0; | 277 for (int j = OperatorProperties::GetContextInputCount(node->op()); j > 0; |
| 271 ++i, j--) { | 278 ++i, j--) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 284 GetControlCluster(node) == NULL) { | 291 GetControlCluster(node) == NULL) { |
| 285 for (int j = OperatorProperties::GetControlInputCount(node->op()); j > 0; | 292 for (int j = OperatorProperties::GetControlInputCount(node->op()); j > 0; |
| 286 ++i, j--) { | 293 ++i, j--) { |
| 287 os_ << "|<I" << i.index() << ">C #" << (*i)->id(); | 294 os_ << "|<I" << i.index() << ">C #" << (*i)->id(); |
| 288 } | 295 } |
| 289 } | 296 } |
| 290 os_ << "}"; | 297 os_ << "}"; |
| 291 | 298 |
| 292 if (FLAG_trace_turbo_types && !NodeProperties::IsControl(node)) { | 299 if (FLAG_trace_turbo_types && !NodeProperties::IsControl(node)) { |
| 293 Bounds bounds = NodeProperties::GetBounds(node); | 300 Bounds bounds = NodeProperties::GetBounds(node); |
| 294 OStringStream upper; | 301 std::ostringstream upper; |
| 295 bounds.upper->PrintTo(upper); | 302 bounds.upper->PrintTo(upper); |
| 296 OStringStream lower; | 303 std::ostringstream lower; |
| 297 bounds.lower->PrintTo(lower); | 304 bounds.lower->PrintTo(lower); |
| 298 os_ << "|" << Escaped(upper) << "|" << Escaped(lower); | 305 os_ << "|" << Escaped(upper) << "|" << Escaped(lower); |
| 299 } | 306 } |
| 300 os_ << "}\"\n"; | 307 os_ << "}\"\n"; |
| 301 } | 308 } |
| 302 | 309 |
| 303 | 310 |
| 304 void GraphVisualizer::PrintEdge(Node::Edge edge) { | 311 void GraphVisualizer::PrintEdge(Node::Edge edge) { |
| 305 Node* from = edge.from(); | 312 Node* from = edge.from(); |
| 306 int index = edge.index(); | 313 int index = edge.index(); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 360 Node::Inputs inputs = (*i)->inputs(); | 367 Node::Inputs inputs = (*i)->inputs(); |
| 361 for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end(); | 368 for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end(); |
| 362 ++iter) { | 369 ++iter) { |
| 363 PrintEdge(iter.edge()); | 370 PrintEdge(iter.edge()); |
| 364 } | 371 } |
| 365 } | 372 } |
| 366 os_ << "}\n"; | 373 os_ << "}\n"; |
| 367 } | 374 } |
| 368 | 375 |
| 369 | 376 |
| 370 GraphVisualizer::GraphVisualizer(OStream& os, Zone* zone, | 377 GraphVisualizer::GraphVisualizer(std::ostream& os, Zone* zone, |
| 371 const Graph* graph) // NOLINT | 378 const Graph* graph) // NOLINT |
| 372 : zone_(zone), | 379 : zone_(zone), |
| 373 all_nodes_(NodeSet::key_compare(), NodeSet::allocator_type(zone)), | 380 all_nodes_(NodeSet::key_compare(), NodeSet::allocator_type(zone)), |
| 374 white_nodes_(NodeSet::key_compare(), NodeSet::allocator_type(zone)), | 381 white_nodes_(NodeSet::key_compare(), NodeSet::allocator_type(zone)), |
| 375 use_to_def_(true), | 382 use_to_def_(true), |
| 376 os_(os), | 383 os_(os), |
| 377 graph_(graph) {} | 384 graph_(graph) {} |
| 378 | 385 |
| 379 | 386 |
| 380 OStream& operator<<(OStream& os, const AsDOT& ad) { | 387 std::ostream& operator<<(std::ostream& os, const AsDOT& ad) { |
| 381 Zone tmp_zone(ad.graph.zone()->isolate()); | 388 Zone tmp_zone(ad.graph.zone()->isolate()); |
| 382 GraphVisualizer(os, &tmp_zone, &ad.graph).Print(); | 389 GraphVisualizer(os, &tmp_zone, &ad.graph).Print(); |
| 383 return os; | 390 return os; |
| 384 } | 391 } |
| 385 } | 392 } |
| 386 } | 393 } |
| 387 } // namespace v8::internal::compiler | 394 } // namespace v8::internal::compiler |
| OLD | NEW |