#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
}
-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) {
SmartArrayPointer<char> functionname =
info_->shared_info()->DebugName()->ToCString();
if (strlen(functionname.get()) > 0) {
- SNPrintF(filename, "turbo-%s-%s.dot", functionname.get(), phase);
+ SNPrintF(filename, "turbo-%s-%s", functionname.get(), phase);
} else {
- SNPrintF(filename, "turbo-%p-%s.dot", static_cast<void*>(info_), phase);
+ SNPrintF(filename, "turbo-%p-%s", static_cast<void*>(info_), phase);
}
} else {
- SNPrintF(filename, "turbo-none-%s.dot", phase);
+ SNPrintF(filename, "turbo-none-%s", phase);
}
std::replace(filename.start(), filename.start() + filename.length(), ' ',
'_');
- FILE* file = base::OS::FOpen(filename.start(), "w+");
- OFStream of(file);
- of << AsDOT(*graph);
- fclose(file);
+
+ char dot_buffer[256];
+ Vector<char> dot_filename(dot_buffer, sizeof(dot_buffer));
+ SNPrintF(dot_filename, "%s.dot", filename.start());
+ FILE* dot_file = base::OS::FOpen(dot_filename.start(), "w+");
+ OFStream dot_of(dot_file);
+ dot_of << AsDOT(*graph);
+ fclose(dot_file);
+
+ char json_buffer[256];
+ Vector<char> json_filename(json_buffer, sizeof(json_buffer));
+ SNPrintF(json_filename, "%s.json", filename.start());
+ FILE* json_file = base::OS::FOpen(json_filename.start(), "w+");
+ OFStream json_of(json_file);
+ json_of << AsJSON(*graph);
+ fclose(json_file);
OFStream os(stdout);
os << "-- " << phase << " graph printed to file " << filename.start()