| 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> | 7 #include <sstream> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
| 11 #include "src/compiler/generic-algorithm.h" | |
| 12 #include "src/compiler/generic-node.h" | 11 #include "src/compiler/generic-node.h" |
| 13 #include "src/compiler/generic-node-inl.h" | 12 #include "src/compiler/generic-node-inl.h" |
| 14 #include "src/compiler/graph.h" | 13 #include "src/compiler/graph.h" |
| 15 #include "src/compiler/graph-inl.h" | 14 #include "src/compiler/graph-inl.h" |
| 16 #include "src/compiler/node.h" | 15 #include "src/compiler/node.h" |
| 17 #include "src/compiler/node-properties.h" | 16 #include "src/compiler/node-properties.h" |
| 18 #include "src/compiler/node-properties-inl.h" | 17 #include "src/compiler/node-properties-inl.h" |
| 19 #include "src/compiler/opcodes.h" | 18 #include "src/compiler/opcodes.h" |
| 20 #include "src/compiler/operator.h" | 19 #include "src/compiler/operator.h" |
| 21 #include "src/compiler/register-allocator.h" | 20 #include "src/compiler/register-allocator.h" |
| 22 #include "src/compiler/schedule.h" | 21 #include "src/compiler/schedule.h" |
| 23 #include "src/compiler/scheduler.h" | 22 #include "src/compiler/scheduler.h" |
| 24 #include "src/ostreams.h" | 23 #include "src/ostreams.h" |
| 25 | 24 |
| 26 namespace v8 { | 25 namespace v8 { |
| 27 namespace internal { | 26 namespace internal { |
| 28 namespace compiler { | 27 namespace compiler { |
| 29 | 28 |
| 29 static int SafeId(Node* node) { return node == NULL ? -1 : node->id(); } |
| 30 |
| 30 #define DEAD_COLOR "#999999" | 31 #define DEAD_COLOR "#999999" |
| 31 | 32 |
| 33 class AllNodes { |
| 34 public: |
| 35 enum State { kDead, kGray, kLive }; |
| 36 |
| 37 AllNodes(Zone* local_zone, const Graph* graph) |
| 38 : state(graph->NodeCount(), kDead, local_zone), |
| 39 live(local_zone), |
| 40 gray(local_zone) { |
| 41 Node* end = graph->end(); |
| 42 state[end->id()] = kLive; |
| 43 live.push_back(end); |
| 44 // Find all live nodes reachable from end. |
| 45 for (size_t i = 0; i < live.size(); i++) { |
| 46 for (Node* const input : live[i]->inputs()) { |
| 47 if (input == NULL) { |
| 48 // TODO(titzer): print a warning. |
| 49 continue; |
| 50 } |
| 51 if (input->id() >= graph->NodeCount()) { |
| 52 // TODO(titzer): print a warning. |
| 53 continue; |
| 54 } |
| 55 if (state[input->id()] != kLive) { |
| 56 live.push_back(input); |
| 57 state[input->id()] = kLive; |
| 58 } |
| 59 } |
| 60 } |
| 61 |
| 62 // Find all nodes that are not reachable from end that use live nodes. |
| 63 for (size_t i = 0; i < live.size(); i++) { |
| 64 for (Node* const use : live[i]->uses()) { |
| 65 if (state[use->id()] == kDead) { |
| 66 gray.push_back(use); |
| 67 state[use->id()] = kGray; |
| 68 } |
| 69 } |
| 70 } |
| 71 } |
| 72 |
| 73 bool IsLive(Node* node) { |
| 74 return node != NULL && node->id() < static_cast<int>(state.size()) && |
| 75 state[node->id()] == kLive; |
| 76 } |
| 77 |
| 78 ZoneVector<State> state; |
| 79 NodeVector live; |
| 80 NodeVector gray; |
| 81 }; |
| 82 |
| 83 |
| 32 class Escaped { | 84 class Escaped { |
| 33 public: | 85 public: |
| 34 explicit Escaped(const std::ostringstream& os, | 86 explicit Escaped(const std::ostringstream& os, |
| 35 const char* escaped_chars = "<>|{}") | 87 const char* escaped_chars = "<>|{}") |
| 36 : str_(os.str()), escaped_chars_(escaped_chars) {} | 88 : str_(os.str()), escaped_chars_(escaped_chars) {} |
| 37 | 89 |
| 38 friend std::ostream& operator<<(std::ostream& os, const Escaped& e) { | 90 friend std::ostream& operator<<(std::ostream& os, const Escaped& e) { |
| 39 for (std::string::const_iterator i = e.str_.begin(); i != e.str_.end(); | 91 for (std::string::const_iterator i = e.str_.begin(); i != e.str_.end(); |
| 40 ++i) { | 92 ++i) { |
| 41 if (e.needs_escape(*i)) os << "\\"; | 93 if (e.needs_escape(*i)) os << "\\"; |
| 42 os << *i; | 94 os << *i; |
| 43 } | 95 } |
| 44 return os; | 96 return os; |
| 45 } | 97 } |
| 46 | 98 |
| 47 private: | 99 private: |
| 48 bool needs_escape(char ch) const { | 100 bool needs_escape(char ch) const { |
| 49 for (size_t i = 0; i < strlen(escaped_chars_); ++i) { | 101 for (size_t i = 0; i < strlen(escaped_chars_); ++i) { |
| 50 if (ch == escaped_chars_[i]) return true; | 102 if (ch == escaped_chars_[i]) return true; |
| 51 } | 103 } |
| 52 return false; | 104 return false; |
| 53 } | 105 } |
| 54 | 106 |
| 55 const std::string str_; | 107 const std::string str_; |
| 56 const char* const escaped_chars_; | 108 const char* const escaped_chars_; |
| 57 }; | 109 }; |
| 58 | 110 |
| 59 class JSONGraphNodeWriter : public NullNodeVisitor { | 111 class JSONGraphNodeWriter { |
| 60 public: | 112 public: |
| 61 JSONGraphNodeWriter(std::ostream& os, Zone* zone, | 113 JSONGraphNodeWriter(std::ostream& os, Zone* zone, const Graph* graph) |
| 62 const Graph* graph) // NOLINT | 114 : os_(os), all_(zone, graph), first_node_(true) {} |
| 63 : os_(os), | |
| 64 graph_(graph), | |
| 65 first_node_(true) {} | |
| 66 | 115 |
| 67 void Print() { const_cast<Graph*>(graph_)->VisitNodeInputsFromEnd(this); } | 116 void Print() { |
| 117 for (Node* const node : all_.live) PrintNode(node); |
| 118 } |
| 68 | 119 |
| 69 void Pre(Node* node); | 120 void PrintNode(Node* node) { |
| 121 if (first_node_) { |
| 122 first_node_ = false; |
| 123 } else { |
| 124 os_ << ","; |
| 125 } |
| 126 std::ostringstream label; |
| 127 label << *node->op(); |
| 128 os_ << "{\"id\":" << SafeId(node) << ",\"label\":\"" << Escaped(label, "\"") |
| 129 << "\""; |
| 130 IrOpcode::Value opcode = node->opcode(); |
| 131 if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) { |
| 132 os_ << ",\"rankInputs\":[0," << NodeProperties::FirstControlIndex(node) |
| 133 << "]"; |
| 134 os_ << ",\"rankWithInput\":[" << NodeProperties::FirstControlIndex(node) |
| 135 << "]"; |
| 136 } else if (opcode == IrOpcode::kIfTrue || opcode == IrOpcode::kIfFalse || |
| 137 opcode == IrOpcode::kLoop) { |
| 138 os_ << ",\"rankInputs\":[" << NodeProperties::FirstControlIndex(node) |
| 139 << "]"; |
| 140 } |
| 141 if (opcode == IrOpcode::kBranch) { |
| 142 os_ << ",\"rankInputs\":[0]"; |
| 143 } |
| 144 os_ << ",\"opcode\":\"" << IrOpcode::Mnemonic(node->opcode()) << "\""; |
| 145 os_ << ",\"control\":" << (NodeProperties::IsControl(node) ? "true" |
| 146 : "false"); |
| 147 os_ << "}"; |
| 148 } |
| 70 | 149 |
| 71 private: | 150 private: |
| 72 std::ostream& os_; | 151 std::ostream& os_; |
| 73 const Graph* const graph_; | 152 AllNodes all_; |
| 74 bool first_node_; | 153 bool first_node_; |
| 75 | 154 |
| 76 DISALLOW_COPY_AND_ASSIGN(JSONGraphNodeWriter); | 155 DISALLOW_COPY_AND_ASSIGN(JSONGraphNodeWriter); |
| 77 }; | 156 }; |
| 78 | 157 |
| 79 | 158 |
| 80 void JSONGraphNodeWriter::Pre(Node* node) { | 159 class JSONGraphEdgeWriter { |
| 81 if (first_node_) { | 160 public: |
| 82 first_node_ = false; | 161 JSONGraphEdgeWriter(std::ostream& os, Zone* zone, const Graph* graph) |
| 83 } else { | 162 : os_(os), all_(zone, graph), first_edge_(true) {} |
| 84 os_ << ","; | 163 |
| 164 void Print() { |
| 165 for (Node* const node : all_.live) PrintEdges(node); |
| 85 } | 166 } |
| 86 std::ostringstream label; | 167 |
| 87 label << *node->op(); | 168 void PrintEdges(Node* node) { |
| 88 os_ << "{\"id\":" << node->id() << ",\"label\":\"" << Escaped(label, "\"") | 169 for (int i = 0; i < node->InputCount(); i++) { |
| 89 << "\""; | 170 Node* input = node->InputAt(i); |
| 90 IrOpcode::Value opcode = node->opcode(); | 171 if (input == NULL) continue; |
| 91 if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) { | 172 PrintEdge(node, i, input); |
| 92 os_ << ",\"rankInputs\":[0," << NodeProperties::FirstControlIndex(node) | 173 } |
| 93 << "]"; | |
| 94 os_ << ",\"rankWithInput\":[" << NodeProperties::FirstControlIndex(node) | |
| 95 << "]"; | |
| 96 } else if (opcode == IrOpcode::kIfTrue || opcode == IrOpcode::kIfFalse || | |
| 97 opcode == IrOpcode::kLoop) { | |
| 98 os_ << ",\"rankInputs\":[" << NodeProperties::FirstControlIndex(node) | |
| 99 << "]"; | |
| 100 } | 174 } |
| 101 if (opcode == IrOpcode::kBranch) { | 175 |
| 102 os_ << ",\"rankInputs\":[0]"; | 176 void PrintEdge(Node* from, int index, Node* to) { |
| 177 if (first_edge_) { |
| 178 first_edge_ = false; |
| 179 } else { |
| 180 os_ << ","; |
| 181 } |
| 182 const char* edge_type = NULL; |
| 183 if (index < NodeProperties::FirstValueIndex(from)) { |
| 184 edge_type = "unknown"; |
| 185 } else if (index < NodeProperties::FirstContextIndex(from)) { |
| 186 edge_type = "value"; |
| 187 } else if (index < NodeProperties::FirstFrameStateIndex(from)) { |
| 188 edge_type = "context"; |
| 189 } else if (index < NodeProperties::FirstEffectIndex(from)) { |
| 190 edge_type = "frame-state"; |
| 191 } else if (index < NodeProperties::FirstControlIndex(from)) { |
| 192 edge_type = "effect"; |
| 193 } else { |
| 194 edge_type = "control"; |
| 195 } |
| 196 os_ << "{\"source\":" << SafeId(to) << ",\"target\":" << SafeId(from) |
| 197 << ",\"index\":" << index << ",\"type\":\"" << edge_type << "\"}"; |
| 103 } | 198 } |
| 104 os_ << ",\"opcode\":\"" << IrOpcode::Mnemonic(node->opcode()) << "\""; | |
| 105 os_ << ",\"control\":" << (NodeProperties::IsControl(node) ? "true" | |
| 106 : "false"); | |
| 107 os_ << "}"; | |
| 108 } | |
| 109 | |
| 110 | |
| 111 class JSONGraphEdgeWriter : public NullNodeVisitor { | |
| 112 public: | |
| 113 JSONGraphEdgeWriter(std::ostream& os, Zone* zone, | |
| 114 const Graph* graph) // NOLINT | |
| 115 : os_(os), | |
| 116 graph_(graph), | |
| 117 first_edge_(true) {} | |
| 118 | |
| 119 void Print() { const_cast<Graph*>(graph_)->VisitNodeInputsFromEnd(this); } | |
| 120 | |
| 121 void PreEdge(Node* from, int index, Node* to); | |
| 122 | 199 |
| 123 private: | 200 private: |
| 124 std::ostream& os_; | 201 std::ostream& os_; |
| 125 const Graph* const graph_; | 202 AllNodes all_; |
| 126 bool first_edge_; | 203 bool first_edge_; |
| 127 | 204 |
| 128 DISALLOW_COPY_AND_ASSIGN(JSONGraphEdgeWriter); | 205 DISALLOW_COPY_AND_ASSIGN(JSONGraphEdgeWriter); |
| 129 }; | 206 }; |
| 130 | 207 |
| 131 | 208 |
| 132 void JSONGraphEdgeWriter::PreEdge(Node* from, int index, Node* to) { | |
| 133 if (first_edge_) { | |
| 134 first_edge_ = false; | |
| 135 } else { | |
| 136 os_ << ","; | |
| 137 } | |
| 138 const char* edge_type = NULL; | |
| 139 if (index < NodeProperties::FirstValueIndex(from)) { | |
| 140 edge_type = "unknown"; | |
| 141 } else if (index < NodeProperties::FirstContextIndex(from)) { | |
| 142 edge_type = "value"; | |
| 143 } else if (index < NodeProperties::FirstFrameStateIndex(from)) { | |
| 144 edge_type = "context"; | |
| 145 } else if (index < NodeProperties::FirstEffectIndex(from)) { | |
| 146 edge_type = "frame-state"; | |
| 147 } else if (index < NodeProperties::FirstControlIndex(from)) { | |
| 148 edge_type = "effect"; | |
| 149 } else { | |
| 150 edge_type = "control"; | |
| 151 } | |
| 152 os_ << "{\"source\":" << to->id() << ",\"target\":" << from->id() | |
| 153 << ",\"index\":" << index << ",\"type\":\"" << edge_type << "\"}"; | |
| 154 } | |
| 155 | |
| 156 | |
| 157 std::ostream& operator<<(std::ostream& os, const AsJSON& ad) { | 209 std::ostream& operator<<(std::ostream& os, const AsJSON& ad) { |
| 158 Zone tmp_zone(ad.graph.zone()->isolate()); | 210 Zone tmp_zone(ad.graph.zone()->isolate()); |
| 159 os << "{\"nodes\":["; | 211 os << "{\"nodes\":["; |
| 160 JSONGraphNodeWriter(os, &tmp_zone, &ad.graph).Print(); | 212 JSONGraphNodeWriter(os, &tmp_zone, &ad.graph).Print(); |
| 161 os << "],\"edges\":["; | 213 os << "],\"edges\":["; |
| 162 JSONGraphEdgeWriter(os, &tmp_zone, &ad.graph).Print(); | 214 JSONGraphEdgeWriter(os, &tmp_zone, &ad.graph).Print(); |
| 163 os << "]}"; | 215 os << "]}"; |
| 164 return os; | 216 return os; |
| 165 } | 217 } |
| 166 | 218 |
| 167 | 219 |
| 168 class GraphVisualizer : public NullNodeVisitor { | 220 class GraphVisualizer { |
| 169 public: | 221 public: |
| 170 GraphVisualizer(std::ostream& os, Zone* zone, const Graph* graph); // NOLINT | 222 GraphVisualizer(std::ostream& os, Zone* zone, const Graph* graph); // NOLINT |
| 171 | 223 |
| 172 void Print(); | 224 void Print(); |
| 173 | 225 |
| 174 void Pre(Node* node); | 226 void PrintNode(Node* node, bool gray); |
| 175 | 227 |
| 176 private: | 228 private: |
| 177 void AnnotateNode(Node* node); | |
| 178 void PrintEdge(Node::Edge edge); | 229 void PrintEdge(Node::Edge edge); |
| 179 | 230 |
| 180 Zone* zone_; | 231 Zone* zone_; |
| 181 NodeSet all_nodes_; | 232 AllNodes all_; |
| 182 NodeSet white_nodes_; | |
| 183 bool use_to_def_; | |
| 184 std::ostream& os_; | 233 std::ostream& os_; |
| 185 const Graph* const graph_; | 234 const Graph* const graph_; |
| 186 | 235 |
| 187 DISALLOW_COPY_AND_ASSIGN(GraphVisualizer); | 236 DISALLOW_COPY_AND_ASSIGN(GraphVisualizer); |
| 188 }; | 237 }; |
| 189 | 238 |
| 190 | 239 |
| 191 static Node* GetControlCluster(Node* node) { | 240 static Node* GetControlCluster(Node* node) { |
| 192 if (OperatorProperties::IsBasicBlockBegin(node->op())) { | 241 if (OperatorProperties::IsBasicBlockBegin(node->op())) { |
| 193 return node; | 242 return node; |
| 194 } else if (node->op()->ControlInputCount() == 1) { | 243 } else if (node->op()->ControlInputCount() == 1) { |
| 195 Node* control = NodeProperties::GetControlInput(node, 0); | 244 Node* control = NodeProperties::GetControlInput(node, 0); |
| 196 return OperatorProperties::IsBasicBlockBegin(control->op()) ? control | 245 return control != NULL && |
| 197 : NULL; | 246 OperatorProperties::IsBasicBlockBegin(control->op()) |
| 247 ? control |
| 248 : NULL; |
| 198 } else { | 249 } else { |
| 199 return NULL; | 250 return NULL; |
| 200 } | 251 } |
| 201 } | 252 } |
| 202 | 253 |
| 203 | 254 |
| 204 void GraphVisualizer::Pre(Node* node) { | 255 void GraphVisualizer::PrintNode(Node* node, bool gray) { |
| 205 if (all_nodes_.count(node) == 0) { | 256 Node* control_cluster = GetControlCluster(node); |
| 206 Node* control_cluster = GetControlCluster(node); | 257 if (control_cluster != NULL) { |
| 207 if (control_cluster != NULL) { | 258 os_ << " subgraph cluster_BasicBlock" << control_cluster->id() << " {\n"; |
| 208 os_ << " subgraph cluster_BasicBlock" << control_cluster->id() << " {\n"; | |
| 209 } | |
| 210 os_ << " ID" << node->id() << " [\n"; | |
| 211 AnnotateNode(node); | |
| 212 os_ << " ]\n"; | |
| 213 if (control_cluster != NULL) os_ << " }\n"; | |
| 214 all_nodes_.insert(node); | |
| 215 if (use_to_def_) white_nodes_.insert(node); | |
| 216 } | 259 } |
| 217 } | 260 os_ << " ID" << SafeId(node) << " [\n"; |
| 218 | |
| 219 | |
| 220 static bool IsLikelyBackEdge(Node* from, int index, Node* to) { | |
| 221 if (from->opcode() == IrOpcode::kPhi || | |
| 222 from->opcode() == IrOpcode::kEffectPhi) { | |
| 223 Node* control = NodeProperties::GetControlInput(from, 0); | |
| 224 return control->opcode() != IrOpcode::kMerge && control != to && index != 0; | |
| 225 } else if (from->opcode() == IrOpcode::kLoop) { | |
| 226 return index != 0; | |
| 227 } else { | |
| 228 return false; | |
| 229 } | |
| 230 } | |
| 231 | |
| 232 | |
| 233 void GraphVisualizer::AnnotateNode(Node* node) { | |
| 234 if (!use_to_def_) { | |
| 235 os_ << " style=\"filled\"\n" | |
| 236 << " fillcolor=\"" DEAD_COLOR "\"\n"; | |
| 237 } | |
| 238 | 261 |
| 239 os_ << " shape=\"record\"\n"; | 262 os_ << " shape=\"record\"\n"; |
| 240 switch (node->opcode()) { | 263 switch (node->opcode()) { |
| 241 case IrOpcode::kEnd: | 264 case IrOpcode::kEnd: |
| 242 case IrOpcode::kDead: | 265 case IrOpcode::kDead: |
| 243 case IrOpcode::kStart: | 266 case IrOpcode::kStart: |
| 244 os_ << " style=\"diagonals\"\n"; | 267 os_ << " style=\"diagonals\"\n"; |
| 245 break; | 268 break; |
| 246 case IrOpcode::kMerge: | 269 case IrOpcode::kMerge: |
| 247 case IrOpcode::kIfTrue: | 270 case IrOpcode::kIfTrue: |
| 248 case IrOpcode::kIfFalse: | 271 case IrOpcode::kIfFalse: |
| 249 case IrOpcode::kLoop: | 272 case IrOpcode::kLoop: |
| 250 os_ << " style=\"rounded\"\n"; | 273 os_ << " style=\"rounded\"\n"; |
| 251 break; | 274 break; |
| 252 default: | 275 default: |
| 253 break; | 276 break; |
| 254 } | 277 } |
| 255 | 278 |
| 279 if (gray) { |
| 280 os_ << " style=\"filled\"\n" |
| 281 << " fillcolor=\"" DEAD_COLOR "\"\n"; |
| 282 } |
| 283 |
| 256 std::ostringstream label; | 284 std::ostringstream label; |
| 257 label << *node->op(); | 285 label << *node->op(); |
| 258 os_ << " label=\"{{#" << node->id() << ":" << Escaped(label); | 286 os_ << " label=\"{{#" << SafeId(node) << ":" << Escaped(label); |
| 259 | 287 |
| 260 InputIter i = node->inputs().begin(); | 288 InputIter i = node->inputs().begin(); |
| 261 for (int j = node->op()->ValueInputCount(); j > 0; ++i, j--) { | 289 for (int j = node->op()->ValueInputCount(); j > 0; ++i, j--) { |
| 262 os_ << "|<I" << i.index() << ">#" << (*i)->id(); | 290 os_ << "|<I" << i.index() << ">#" << SafeId(*i); |
| 263 } | 291 } |
| 264 for (int j = OperatorProperties::GetContextInputCount(node->op()); j > 0; | 292 for (int j = OperatorProperties::GetContextInputCount(node->op()); j > 0; |
| 265 ++i, j--) { | 293 ++i, j--) { |
| 266 os_ << "|<I" << i.index() << ">X #" << (*i)->id(); | 294 os_ << "|<I" << i.index() << ">X #" << SafeId(*i); |
| 267 } | 295 } |
| 268 for (int j = OperatorProperties::GetFrameStateInputCount(node->op()); j > 0; | 296 for (int j = OperatorProperties::GetFrameStateInputCount(node->op()); j > 0; |
| 269 ++i, j--) { | 297 ++i, j--) { |
| 270 os_ << "|<I" << i.index() << ">F #" << (*i)->id(); | 298 os_ << "|<I" << i.index() << ">F #" << SafeId(*i); |
| 271 } | 299 } |
| 272 for (int j = node->op()->EffectInputCount(); j > 0; ++i, j--) { | 300 for (int j = node->op()->EffectInputCount(); j > 0; ++i, j--) { |
| 273 os_ << "|<I" << i.index() << ">E #" << (*i)->id(); | 301 os_ << "|<I" << i.index() << ">E #" << SafeId(*i); |
| 274 } | 302 } |
| 275 | 303 |
| 276 if (!use_to_def_ || OperatorProperties::IsBasicBlockBegin(node->op()) || | 304 if (OperatorProperties::IsBasicBlockBegin(node->op()) || |
| 277 GetControlCluster(node) == NULL) { | 305 GetControlCluster(node) == NULL) { |
| 278 for (int j = node->op()->ControlInputCount(); j > 0; ++i, j--) { | 306 for (int j = node->op()->ControlInputCount(); j > 0; ++i, j--) { |
| 279 os_ << "|<I" << i.index() << ">C #" << (*i)->id(); | 307 os_ << "|<I" << i.index() << ">C #" << SafeId(*i); |
| 280 } | 308 } |
| 281 } | 309 } |
| 282 os_ << "}"; | 310 os_ << "}"; |
| 283 | 311 |
| 284 if (FLAG_trace_turbo_types && NodeProperties::IsTyped(node)) { | 312 if (FLAG_trace_turbo_types && NodeProperties::IsTyped(node)) { |
| 285 Bounds bounds = NodeProperties::GetBounds(node); | 313 Bounds bounds = NodeProperties::GetBounds(node); |
| 286 std::ostringstream upper; | 314 std::ostringstream upper; |
| 287 bounds.upper->PrintTo(upper); | 315 bounds.upper->PrintTo(upper); |
| 288 std::ostringstream lower; | 316 std::ostringstream lower; |
| 289 bounds.lower->PrintTo(lower); | 317 bounds.lower->PrintTo(lower); |
| 290 os_ << "|" << Escaped(upper) << "|" << Escaped(lower); | 318 os_ << "|" << Escaped(upper) << "|" << Escaped(lower); |
| 291 } | 319 } |
| 292 os_ << "}\"\n"; | 320 os_ << "}\"\n"; |
| 321 |
| 322 os_ << " ]\n"; |
| 323 if (control_cluster != NULL) os_ << " }\n"; |
| 293 } | 324 } |
| 294 | 325 |
| 295 | 326 |
| 327 static bool IsLikelyBackEdge(Node* from, int index, Node* to) { |
| 328 if (from->opcode() == IrOpcode::kPhi || |
| 329 from->opcode() == IrOpcode::kEffectPhi) { |
| 330 Node* control = NodeProperties::GetControlInput(from, 0); |
| 331 return control != NULL && control->opcode() != IrOpcode::kMerge && |
| 332 control != to && index != 0; |
| 333 } else if (from->opcode() == IrOpcode::kLoop) { |
| 334 return index != 0; |
| 335 } else { |
| 336 return false; |
| 337 } |
| 338 } |
| 339 |
| 340 |
| 296 void GraphVisualizer::PrintEdge(Node::Edge edge) { | 341 void GraphVisualizer::PrintEdge(Node::Edge edge) { |
| 297 Node* from = edge.from(); | 342 Node* from = edge.from(); |
| 298 int index = edge.index(); | 343 int index = edge.index(); |
| 299 Node* to = edge.to(); | 344 Node* to = edge.to(); |
| 345 |
| 346 if (!all_.IsLive(to)) return; // skip inputs that point to dead or NULL. |
| 347 |
| 300 bool unconstrained = IsLikelyBackEdge(from, index, to); | 348 bool unconstrained = IsLikelyBackEdge(from, index, to); |
| 301 os_ << " ID" << from->id(); | 349 os_ << " ID" << SafeId(from); |
| 302 if (all_nodes_.count(to) == 0) { | 350 |
| 303 os_ << ":I" << index << ":n -> DEAD_INPUT"; | 351 if (OperatorProperties::IsBasicBlockBegin(from->op()) || |
| 304 } else if (OperatorProperties::IsBasicBlockBegin(from->op()) || | 352 GetControlCluster(from) == NULL || |
| 305 GetControlCluster(from) == NULL || | 353 (from->op()->ControlInputCount() > 0 && |
| 306 (from->op()->ControlInputCount() > 0 && | 354 NodeProperties::GetControlInput(from) != to)) { |
| 307 NodeProperties::GetControlInput(from) != to)) { | 355 os_ << ":I" << index << ":n -> ID" << SafeId(to) << ":s" |
| 308 os_ << ":I" << index << ":n -> ID" << to->id() << ":s" | |
| 309 << "[" << (unconstrained ? "constraint=false, " : "") | 356 << "[" << (unconstrained ? "constraint=false, " : "") |
| 310 << (NodeProperties::IsControlEdge(edge) ? "style=bold, " : "") | 357 << (NodeProperties::IsControlEdge(edge) ? "style=bold, " : "") |
| 311 << (NodeProperties::IsEffectEdge(edge) ? "style=dotted, " : "") | 358 << (NodeProperties::IsEffectEdge(edge) ? "style=dotted, " : "") |
| 312 << (NodeProperties::IsContextEdge(edge) ? "style=dashed, " : "") << "]"; | 359 << (NodeProperties::IsContextEdge(edge) ? "style=dashed, " : "") << "]"; |
| 313 } else { | 360 } else { |
| 314 os_ << " -> ID" << to->id() << ":s [color=transparent, " | 361 os_ << " -> ID" << SafeId(to) << ":s [color=transparent, " |
| 315 << (unconstrained ? "constraint=false, " : "") | 362 << (unconstrained ? "constraint=false, " : "") |
| 316 << (NodeProperties::IsControlEdge(edge) ? "style=dashed, " : "") << "]"; | 363 << (NodeProperties::IsControlEdge(edge) ? "style=dashed, " : "") << "]"; |
| 317 } | 364 } |
| 318 os_ << "\n"; | 365 os_ << "\n"; |
| 319 } | 366 } |
| 320 | 367 |
| 321 | 368 |
| 322 void GraphVisualizer::Print() { | 369 void GraphVisualizer::Print() { |
| 323 os_ << "digraph D {\n" | 370 os_ << "digraph D {\n" |
| 324 << " node [fontsize=8,height=0.25]\n" | 371 << " node [fontsize=8,height=0.25]\n" |
| 325 << " rankdir=\"BT\"\n" | 372 << " rankdir=\"BT\"\n" |
| 326 << " ranksep=\"1.2 equally\"\n" | 373 << " ranksep=\"1.2 equally\"\n" |
| 327 << " overlap=\"false\"\n" | 374 << " overlap=\"false\"\n" |
| 328 << " splines=\"true\"\n" | 375 << " splines=\"true\"\n" |
| 329 << " concentrate=\"true\"\n" | 376 << " concentrate=\"true\"\n" |
| 330 << " \n"; | 377 << " \n"; |
| 331 | 378 |
| 332 // Make sure all nodes have been output before writing out the edges. | 379 // Make sure all nodes have been output before writing out the edges. |
| 333 use_to_def_ = true; | 380 for (Node* const node : all_.live) PrintNode(node, false); |
| 334 // TODO(svenpanne) Remove the need for the const_casts. | 381 for (Node* const node : all_.gray) PrintNode(node, true); |
| 335 const_cast<Graph*>(graph_)->VisitNodeInputsFromEnd(this); | |
| 336 white_nodes_.insert(const_cast<Graph*>(graph_)->start()); | |
| 337 | |
| 338 // Visit all uses of white nodes. | |
| 339 use_to_def_ = false; | |
| 340 GenericGraphVisit::Visit<GraphVisualizer, NodeUseIterationTraits<Node> >( | |
| 341 const_cast<Graph*>(graph_), zone_, white_nodes_.begin(), | |
| 342 white_nodes_.end(), this); | |
| 343 | |
| 344 os_ << " DEAD_INPUT [\n" | |
| 345 << " style=\"filled\" \n" | |
| 346 << " fillcolor=\"" DEAD_COLOR "\"\n" | |
| 347 << " ]\n" | |
| 348 << "\n"; | |
| 349 | 382 |
| 350 // With all the nodes written, add the edges. | 383 // With all the nodes written, add the edges. |
| 351 for (NodeSetIter i = all_nodes_.begin(); i != all_nodes_.end(); ++i) { | 384 for (Node* const node : all_.live) { |
| 352 Node::Inputs inputs = (*i)->inputs(); | 385 for (UseIter i = node->uses().begin(); i != node->uses().end(); ++i) { |
| 353 for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end(); | 386 PrintEdge(i.edge()); |
| 354 ++iter) { | |
| 355 PrintEdge(iter.edge()); | |
| 356 } | 387 } |
| 357 } | 388 } |
| 358 os_ << "}\n"; | 389 os_ << "}\n"; |
| 359 } | 390 } |
| 360 | 391 |
| 361 | 392 |
| 362 GraphVisualizer::GraphVisualizer(std::ostream& os, Zone* zone, | 393 GraphVisualizer::GraphVisualizer(std::ostream& os, Zone* zone, |
| 363 const Graph* graph) // NOLINT | 394 const Graph* graph) // NOLINT |
| 364 : zone_(zone), | 395 : zone_(zone), |
| 365 all_nodes_(NodeSet::key_compare(), NodeSet::allocator_type(zone)), | 396 all_(zone, graph), |
| 366 white_nodes_(NodeSet::key_compare(), NodeSet::allocator_type(zone)), | |
| 367 use_to_def_(true), | |
| 368 os_(os), | 397 os_(os), |
| 369 graph_(graph) {} | 398 graph_(graph) {} |
| 370 | 399 |
| 371 | 400 |
| 372 std::ostream& operator<<(std::ostream& os, const AsDOT& ad) { | 401 std::ostream& operator<<(std::ostream& os, const AsDOT& ad) { |
| 373 Zone tmp_zone(ad.graph.zone()->isolate()); | 402 Zone tmp_zone(ad.graph.zone()->isolate()); |
| 374 GraphVisualizer(os, &tmp_zone, &ad.graph).Print(); | 403 GraphVisualizer(os, &tmp_zone, &ad.graph).Print(); |
| 375 return os; | 404 return os; |
| 376 } | 405 } |
| 377 | 406 |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 478 } else { | 507 } else { |
| 479 CodeStub::Major major_key = info->code_stub()->MajorKey(); | 508 CodeStub::Major major_key = info->code_stub()->MajorKey(); |
| 480 PrintStringProperty("name", CodeStub::MajorName(major_key, false)); | 509 PrintStringProperty("name", CodeStub::MajorName(major_key, false)); |
| 481 PrintStringProperty("method", "stub"); | 510 PrintStringProperty("method", "stub"); |
| 482 } | 511 } |
| 483 PrintLongProperty("date", | 512 PrintLongProperty("date", |
| 484 static_cast<int64_t>(base::OS::TimeCurrentMillis())); | 513 static_cast<int64_t>(base::OS::TimeCurrentMillis())); |
| 485 } | 514 } |
| 486 | 515 |
| 487 | 516 |
| 488 void GraphC1Visualizer::PrintNodeId(Node* n) { os_ << "n" << n->id(); } | 517 void GraphC1Visualizer::PrintNodeId(Node* n) { os_ << "n" << SafeId(n); } |
| 489 | 518 |
| 490 | 519 |
| 491 void GraphC1Visualizer::PrintNode(Node* n) { | 520 void GraphC1Visualizer::PrintNode(Node* n) { |
| 492 PrintNodeId(n); | 521 PrintNodeId(n); |
| 493 os_ << " " << *n->op() << " "; | 522 os_ << " " << *n->op() << " "; |
| 494 PrintInputs(n); | 523 PrintInputs(n); |
| 495 } | 524 } |
| 496 | 525 |
| 497 | 526 |
| 498 void GraphC1Visualizer::PrintInputs(InputIter* i, int count, | 527 void GraphC1Visualizer::PrintInputs(InputIter* i, int count, |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 759 | 788 |
| 760 | 789 |
| 761 std::ostream& operator<<(std::ostream& os, const AsC1VAllocator& ac) { | 790 std::ostream& operator<<(std::ostream& os, const AsC1VAllocator& ac) { |
| 762 Zone tmp_zone(ac.allocator_->code()->zone()->isolate()); | 791 Zone tmp_zone(ac.allocator_->code()->zone()->isolate()); |
| 763 GraphC1Visualizer(os, &tmp_zone).PrintAllocator(ac.phase_, ac.allocator_); | 792 GraphC1Visualizer(os, &tmp_zone).PrintAllocator(ac.phase_, ac.allocator_); |
| 764 return os; | 793 return os; |
| 765 } | 794 } |
| 766 } | 795 } |
| 767 } | 796 } |
| 768 } // namespace v8::internal::compiler | 797 } // namespace v8::internal::compiler |
| OLD | NEW |