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) { |