Chromium Code Reviews| Index: src/compiler/graph-visualizer.cc |
| diff --git a/src/compiler/graph-visualizer.cc b/src/compiler/graph-visualizer.cc |
| index 10d6698a2cbeacde0be30471d1db346c30ea8c16..39c8e88cd59ee220f30a25a8fd364cef0061d099 100644 |
| --- a/src/compiler/graph-visualizer.cc |
| +++ b/src/compiler/graph-visualizer.cc |
| @@ -22,6 +22,134 @@ namespace compiler { |
| #define DEAD_COLOR "#999999" |
| +class Escaped { |
| + public: |
| + explicit Escaped(const OStringStream& os, const char* escaped_chars = "<>|{}") |
| + : str_(os.c_str()), escaped_chars_(escaped_chars) {} |
| + |
| + friend OStream& operator<<(OStream& os, const Escaped& e) { |
| + for (const char* s = e.str_; *s != '\0'; ++s) { |
| + if (e.needs_escape(*s)) os << "\\"; |
| + os << *s; |
| + } |
| + return os; |
| + } |
| + |
| + private: |
| + bool needs_escape(char ch) const { |
| + for (size_t i = 0; i < strlen(escaped_chars_); ++i) { |
| + if (ch == escaped_chars_[i]) return true; |
| + } |
| + return false; |
| + } |
| + |
| + const char* const str_; |
| + const char* const escaped_chars_; |
| +}; |
| + |
| +class JSONGraphNodeWriter : public NullNodeVisitor { |
| + public: |
| + JSONGraphNodeWriter(OStream& os, Zone* zone, const Graph* graph) // NOLINT |
| + : os_(os), |
| + graph_(graph), |
| + first_node_(true) {} |
| + |
| + void Print() { const_cast<Graph*>(graph_)->VisitNodeInputsFromEnd(this); } |
| + |
| + GenericGraphVisit::Control Pre(Node* node); |
| + |
| + private: |
| + OStream& os_; |
| + const Graph* const graph_; |
| + bool first_node_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(JSONGraphNodeWriter); |
| +}; |
| + |
| + |
| +GenericGraphVisit::Control JSONGraphNodeWriter::Pre(Node* node) { |
| + if (first_node_) { |
| + first_node_ = false; |
| + } else { |
| + os_ << ","; |
| + } |
| + OStringStream label; |
| + label << *node->op(); |
| + os_ << "{\"id\":" << node->id() << ",\"label\":\"" << Escaped(label, "\"") |
| + << "\""; |
| + IrOpcode::Value opcode = node->opcode(); |
| + if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) { |
| + os_ << ",\"rankInputs\":[0," << NodeProperties::FirstControlIndex(node) |
| + << "]"; |
| + os_ << ",\"rankWithInput\":[" << NodeProperties::FirstControlIndex(node) |
| + << "]"; |
| + } else if (opcode == IrOpcode::kIfTrue || opcode == IrOpcode::kIfFalse || |
| + opcode == IrOpcode::kLoop) { |
| + os_ << ",\"rankInputs\":[" << NodeProperties::FirstControlIndex(node) |
| + << "]"; |
| + } |
| + if (opcode == IrOpcode::kBranch) { |
| + os_ << ",\"rankInputs\":[0]"; |
| + } |
| + if (NodeProperties::IsControl(node)) { |
| + os_ << ",\"control\":true"; |
| + } |
| + os_ << ",\"visible\":true"; |
| + os_ << "}"; |
| + return GenericGraphVisit::CONTINUE; |
| +} |
| + |
| + |
| +class JSONGraphEdgeWriter : public NullNodeVisitor { |
| + public: |
| + JSONGraphEdgeWriter(OStream& os, Zone* zone, const Graph* graph) // NOLINT |
| + : os_(os), |
| + graph_(graph), |
| + first_edge_(true) {} |
| + |
| + void Print() { const_cast<Graph*>(graph_)->VisitNodeInputsFromEnd(this); } |
| + |
| + GenericGraphVisit::Control PreEdge(Node* from, int index, Node* to); |
| + |
| + private: |
| + OStream& os_; |
| + const Graph* const graph_; |
| + bool first_edge_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(JSONGraphEdgeWriter); |
| +}; |
| + |
| + |
| +GenericGraphVisit::Control JSONGraphEdgeWriter::PreEdge(Node* from, int index, |
| + Node* to) { |
| + if (first_edge_) { |
| + first_edge_ = false; |
| + } else { |
| + os_ << ","; |
| + } |
| + IrOpcode::Value opcode = from->opcode(); |
| + 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
|
| + opcode == IrOpcode::kEffectPhi || |
| + index < NodeProperties::FirstControlIndex(from)) && |
| + to->UseCount() < 16; |
| + os_ << "{\"source\":" << to->id() << ",\"target\":" << from->id() |
| + << ",\"index\":" << index |
| + << ",\"visible\":" << (visible ? "true" : "false") << "}"; |
| + return GenericGraphVisit::CONTINUE; |
| +} |
| + |
| + |
| +OStream& operator<<(OStream& os, const AsJSON& ad) { |
| + Zone tmp_zone(ad.graph.zone()->isolate()); |
| + os << "{\"nodes\":["; |
| + JSONGraphNodeWriter(os, &tmp_zone, &ad.graph).Print(); |
| + os << "],\"edges\":["; |
| + JSONGraphEdgeWriter(os, &tmp_zone, &ad.graph).Print(); |
| + os << "]}"; |
| + return os; |
| +} |
| + |
| + |
| class GraphVisualizer : public NullNodeVisitor { |
| public: |
| GraphVisualizer(OStream& os, Zone* zone, const Graph* graph); // NOLINT |
| @@ -87,36 +215,6 @@ GenericGraphVisit::Control GraphVisualizer::PreEdge(Node* from, int index, |
| } |
| -class Escaped { |
| - public: |
| - explicit Escaped(const OStringStream& os) : str_(os.c_str()) {} |
| - |
| - friend OStream& operator<<(OStream& os, const Escaped& e) { |
| - for (const char* s = e.str_; *s != '\0'; ++s) { |
| - if (needs_escape(*s)) os << "\\"; |
| - os << *s; |
| - } |
| - return os; |
| - } |
| - |
| - private: |
| - static bool needs_escape(char ch) { |
| - switch (ch) { |
| - case '>': |
| - case '<': |
| - case '|': |
| - case '}': |
| - case '{': |
| - return true; |
| - default: |
| - return false; |
| - } |
| - } |
| - |
| - const char* const str_; |
| -}; |
| - |
| - |
| static bool IsLikelyBackEdge(Node* from, int index, Node* to) { |
| if (from->opcode() == IrOpcode::kPhi || |
| from->opcode() == IrOpcode::kEffectPhi) { |