| Index: src/compiler/graph-visualizer.cc
|
| diff --git a/src/compiler/graph-visualizer.cc b/src/compiler/graph-visualizer.cc
|
| index 10d6698a2cbeacde0be30471d1db346c30ea8c16..304787552f65ef177a797e932b9fbed336a7fa1b 100644
|
| --- a/src/compiler/graph-visualizer.cc
|
| +++ b/src/compiler/graph-visualizer.cc
|
| @@ -22,6 +22,141 @@ 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]";
|
| + }
|
| + os_ << ",\"opcode\":\"" << IrOpcode::Mnemonic(node->opcode()) << "\"";
|
| + os_ << ",\"control\":" << (NodeProperties::IsControl(node) ? "true"
|
| + : "false");
|
| + 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_ << ",";
|
| + }
|
| + const char* edge_type = NULL;
|
| + if (index < NodeProperties::FirstValueIndex(from)) {
|
| + edge_type = "unknown";
|
| + } else if (index < NodeProperties::FirstContextIndex(from)) {
|
| + edge_type = "value";
|
| + } else if (index < NodeProperties::FirstFrameStateIndex(from)) {
|
| + edge_type = "context";
|
| + } else if (index < NodeProperties::FirstEffectIndex(from)) {
|
| + edge_type = "frame-state";
|
| + } else if (index < NodeProperties::FirstControlIndex(from)) {
|
| + edge_type = "effect";
|
| + } else {
|
| + edge_type = "control";
|
| + }
|
| + os_ << "{\"source\":" << to->id() << ",\"target\":" << from->id()
|
| + << ",\"index\":" << index << ",\"type\":\"" << edge_type << "\"}";
|
| + 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 +222,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) {
|
|
|