Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / v8 / src / compiler / graph-visualizer.cc
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
3 // found in the LICENSE file.
4
5 #include "src/compiler/graph-visualizer.h"
6
7 #include <sstream>
8 #include <string>
9
10 #include "src/code-stubs.h"
11 #include "src/compiler/generic-node.h"
12 #include "src/compiler/generic-node-inl.h"
13 #include "src/compiler/graph.h"
14 #include "src/compiler/graph-inl.h"
15 #include "src/compiler/node.h"
16 #include "src/compiler/node-properties.h"
17 #include "src/compiler/node-properties-inl.h"
18 #include "src/compiler/opcodes.h"
19 #include "src/compiler/operator.h"
20 #include "src/compiler/register-allocator.h"
21 #include "src/compiler/schedule.h"
22 #include "src/compiler/scheduler.h"
23 #include "src/ostreams.h"
24
25 namespace v8 {
26 namespace internal {
27 namespace compiler {
28
29 static int SafeId(Node* node) { return node == NULL ? -1 : node->id(); }
30
31 #define DEAD_COLOR "#999999"
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
84 class Escaped {
85  public:
86   explicit Escaped(const std::ostringstream& os,
87                    const char* escaped_chars = "<>|{}")
88       : str_(os.str()), escaped_chars_(escaped_chars) {}
89
90   friend std::ostream& operator<<(std::ostream& os, const Escaped& e) {
91     for (std::string::const_iterator i = e.str_.begin(); i != e.str_.end();
92          ++i) {
93       if (e.needs_escape(*i)) os << "\\";
94       os << *i;
95     }
96     return os;
97   }
98
99  private:
100   bool needs_escape(char ch) const {
101     for (size_t i = 0; i < strlen(escaped_chars_); ++i) {
102       if (ch == escaped_chars_[i]) return true;
103     }
104     return false;
105   }
106
107   const std::string str_;
108   const char* const escaped_chars_;
109 };
110
111 class JSONGraphNodeWriter {
112  public:
113   JSONGraphNodeWriter(std::ostream& os, Zone* zone, const Graph* graph)
114       : os_(os), all_(zone, graph), first_node_(true) {}
115
116   void Print() {
117     for (Node* const node : all_.live) PrintNode(node);
118   }
119
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   }
149
150  private:
151   std::ostream& os_;
152   AllNodes all_;
153   bool first_node_;
154
155   DISALLOW_COPY_AND_ASSIGN(JSONGraphNodeWriter);
156 };
157
158
159 class JSONGraphEdgeWriter {
160  public:
161   JSONGraphEdgeWriter(std::ostream& os, Zone* zone, const Graph* graph)
162       : os_(os), all_(zone, graph), first_edge_(true) {}
163
164   void Print() {
165     for (Node* const node : all_.live) PrintEdges(node);
166   }
167
168   void PrintEdges(Node* node) {
169     for (int i = 0; i < node->InputCount(); i++) {
170       Node* input = node->InputAt(i);
171       if (input == NULL) continue;
172       PrintEdge(node, i, input);
173     }
174   }
175
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 << "\"}";
198   }
199
200  private:
201   std::ostream& os_;
202   AllNodes all_;
203   bool first_edge_;
204
205   DISALLOW_COPY_AND_ASSIGN(JSONGraphEdgeWriter);
206 };
207
208
209 std::ostream& operator<<(std::ostream& os, const AsJSON& ad) {
210   Zone tmp_zone(ad.graph.zone()->isolate());
211   os << "{\"nodes\":[";
212   JSONGraphNodeWriter(os, &tmp_zone, &ad.graph).Print();
213   os << "],\"edges\":[";
214   JSONGraphEdgeWriter(os, &tmp_zone, &ad.graph).Print();
215   os << "]}";
216   return os;
217 }
218
219
220 class GraphVisualizer {
221  public:
222   GraphVisualizer(std::ostream& os, Zone* zone, const Graph* graph)
223       : all_(zone, graph), os_(os) {}
224
225   void Print();
226
227   void PrintNode(Node* node, bool gray);
228
229  private:
230   void PrintEdge(Node::Edge edge);
231
232   AllNodes all_;
233   std::ostream& os_;
234
235   DISALLOW_COPY_AND_ASSIGN(GraphVisualizer);
236 };
237
238
239 static Node* GetControlCluster(Node* node) {
240   if (OperatorProperties::IsBasicBlockBegin(node->op())) {
241     return node;
242   } else if (node->op()->ControlInputCount() == 1) {
243     Node* control = NodeProperties::GetControlInput(node, 0);
244     return control != NULL &&
245                    OperatorProperties::IsBasicBlockBegin(control->op())
246                ? control
247                : NULL;
248   } else {
249     return NULL;
250   }
251 }
252
253
254 void GraphVisualizer::PrintNode(Node* node, bool gray) {
255   Node* control_cluster = GetControlCluster(node);
256   if (control_cluster != NULL) {
257     os_ << "  subgraph cluster_BasicBlock" << control_cluster->id() << " {\n";
258   }
259   os_ << "  ID" << SafeId(node) << " [\n";
260
261   os_ << "    shape=\"record\"\n";
262   switch (node->opcode()) {
263     case IrOpcode::kEnd:
264     case IrOpcode::kDead:
265     case IrOpcode::kStart:
266       os_ << "    style=\"diagonals\"\n";
267       break;
268     case IrOpcode::kMerge:
269     case IrOpcode::kIfTrue:
270     case IrOpcode::kIfFalse:
271     case IrOpcode::kLoop:
272       os_ << "    style=\"rounded\"\n";
273       break;
274     default:
275       break;
276   }
277
278   if (gray) {
279     os_ << "    style=\"filled\"\n"
280         << "    fillcolor=\"" DEAD_COLOR "\"\n";
281   }
282
283   std::ostringstream label;
284   label << *node->op();
285   os_ << "    label=\"{{#" << SafeId(node) << ":" << Escaped(label);
286
287   InputIter i = node->inputs().begin();
288   for (int j = node->op()->ValueInputCount(); j > 0; ++i, j--) {
289     os_ << "|<I" << i.index() << ">#" << SafeId(*i);
290   }
291   for (int j = OperatorProperties::GetContextInputCount(node->op()); j > 0;
292        ++i, j--) {
293     os_ << "|<I" << i.index() << ">X #" << SafeId(*i);
294   }
295   for (int j = OperatorProperties::GetFrameStateInputCount(node->op()); j > 0;
296        ++i, j--) {
297     os_ << "|<I" << i.index() << ">F #" << SafeId(*i);
298   }
299   for (int j = node->op()->EffectInputCount(); j > 0; ++i, j--) {
300     os_ << "|<I" << i.index() << ">E #" << SafeId(*i);
301   }
302
303   if (OperatorProperties::IsBasicBlockBegin(node->op()) ||
304       GetControlCluster(node) == NULL) {
305     for (int j = node->op()->ControlInputCount(); j > 0; ++i, j--) {
306       os_ << "|<I" << i.index() << ">C #" << SafeId(*i);
307     }
308   }
309   os_ << "}";
310
311   if (FLAG_trace_turbo_types && NodeProperties::IsTyped(node)) {
312     Bounds bounds = NodeProperties::GetBounds(node);
313     std::ostringstream upper;
314     bounds.upper->PrintTo(upper);
315     std::ostringstream lower;
316     bounds.lower->PrintTo(lower);
317     os_ << "|" << Escaped(upper) << "|" << Escaped(lower);
318   }
319   os_ << "}\"\n";
320
321   os_ << "  ]\n";
322   if (control_cluster != NULL) os_ << "  }\n";
323 }
324
325
326 static bool IsLikelyBackEdge(Node* from, int index, Node* to) {
327   if (from->opcode() == IrOpcode::kPhi ||
328       from->opcode() == IrOpcode::kEffectPhi) {
329     Node* control = NodeProperties::GetControlInput(from, 0);
330     return control != NULL && control->opcode() != IrOpcode::kMerge &&
331            control != to && index != 0;
332   } else if (from->opcode() == IrOpcode::kLoop) {
333     return index != 0;
334   } else {
335     return false;
336   }
337 }
338
339
340 void GraphVisualizer::PrintEdge(Node::Edge edge) {
341   Node* from = edge.from();
342   int index = edge.index();
343   Node* to = edge.to();
344
345   if (!all_.IsLive(to)) return;  // skip inputs that point to dead or NULL.
346
347   bool unconstrained = IsLikelyBackEdge(from, index, to);
348   os_ << "  ID" << SafeId(from);
349
350   if (OperatorProperties::IsBasicBlockBegin(from->op()) ||
351       GetControlCluster(from) == NULL ||
352       (from->op()->ControlInputCount() > 0 &&
353        NodeProperties::GetControlInput(from) != to)) {
354     os_ << ":I" << index << ":n -> ID" << SafeId(to) << ":s"
355         << "[" << (unconstrained ? "constraint=false, " : "")
356         << (NodeProperties::IsControlEdge(edge) ? "style=bold, " : "")
357         << (NodeProperties::IsEffectEdge(edge) ? "style=dotted, " : "")
358         << (NodeProperties::IsContextEdge(edge) ? "style=dashed, " : "") << "]";
359   } else {
360     os_ << " -> ID" << SafeId(to) << ":s [color=transparent, "
361         << (unconstrained ? "constraint=false, " : "")
362         << (NodeProperties::IsControlEdge(edge) ? "style=dashed, " : "") << "]";
363   }
364   os_ << "\n";
365 }
366
367
368 void GraphVisualizer::Print() {
369   os_ << "digraph D {\n"
370       << "  node [fontsize=8,height=0.25]\n"
371       << "  rankdir=\"BT\"\n"
372       << "  ranksep=\"1.2 equally\"\n"
373       << "  overlap=\"false\"\n"
374       << "  splines=\"true\"\n"
375       << "  concentrate=\"true\"\n"
376       << "  \n";
377
378   // Make sure all nodes have been output before writing out the edges.
379   for (Node* const node : all_.live) PrintNode(node, false);
380   for (Node* const node : all_.gray) PrintNode(node, true);
381
382   // With all the nodes written, add the edges.
383   for (Node* const node : all_.live) {
384     for (UseIter i = node->uses().begin(); i != node->uses().end(); ++i) {
385       PrintEdge(i.edge());
386     }
387   }
388   os_ << "}\n";
389 }
390
391
392 std::ostream& operator<<(std::ostream& os, const AsDOT& ad) {
393   Zone tmp_zone(ad.graph.zone()->isolate());
394   GraphVisualizer(os, &tmp_zone, &ad.graph).Print();
395   return os;
396 }
397
398
399 class GraphC1Visualizer {
400  public:
401   GraphC1Visualizer(std::ostream& os, Zone* zone);  // NOLINT
402
403   void PrintCompilation(const CompilationInfo* info);
404   void PrintSchedule(const char* phase, const Schedule* schedule,
405                      const SourcePositionTable* positions,
406                      const InstructionSequence* instructions);
407   void PrintAllocator(const char* phase, const RegisterAllocator* allocator);
408   Zone* zone() const { return zone_; }
409
410  private:
411   void PrintIndent();
412   void PrintStringProperty(const char* name, const char* value);
413   void PrintLongProperty(const char* name, int64_t value);
414   void PrintIntProperty(const char* name, int value);
415   void PrintBlockProperty(const char* name, BasicBlock::Id block_id);
416   void PrintNodeId(Node* n);
417   void PrintNode(Node* n);
418   void PrintInputs(Node* n);
419   void PrintInputs(InputIter* i, int count, const char* prefix);
420   void PrintType(Node* node);
421
422   void PrintLiveRange(LiveRange* range, const char* type);
423   class Tag FINAL BASE_EMBEDDED {
424    public:
425     Tag(GraphC1Visualizer* visualizer, const char* name) {
426       name_ = name;
427       visualizer_ = visualizer;
428       visualizer->PrintIndent();
429       visualizer_->os_ << "begin_" << name << "\n";
430       visualizer->indent_++;
431     }
432
433     ~Tag() {
434       visualizer_->indent_--;
435       visualizer_->PrintIndent();
436       visualizer_->os_ << "end_" << name_ << "\n";
437       DCHECK(visualizer_->indent_ >= 0);
438     }
439
440    private:
441     GraphC1Visualizer* visualizer_;
442     const char* name_;
443   };
444
445   std::ostream& os_;
446   int indent_;
447   Zone* zone_;
448
449   DISALLOW_COPY_AND_ASSIGN(GraphC1Visualizer);
450 };
451
452
453 void GraphC1Visualizer::PrintIndent() {
454   for (int i = 0; i < indent_; i++) {
455     os_ << "  ";
456   }
457 }
458
459
460 GraphC1Visualizer::GraphC1Visualizer(std::ostream& os, Zone* zone)
461     : os_(os), indent_(0), zone_(zone) {}
462
463
464 void GraphC1Visualizer::PrintStringProperty(const char* name,
465                                             const char* value) {
466   PrintIndent();
467   os_ << name << " \"" << value << "\"\n";
468 }
469
470
471 void GraphC1Visualizer::PrintLongProperty(const char* name, int64_t value) {
472   PrintIndent();
473   os_ << name << " " << static_cast<int>(value / 1000) << "\n";
474 }
475
476
477 void GraphC1Visualizer::PrintBlockProperty(const char* name,
478                                            BasicBlock::Id block_id) {
479   PrintIndent();
480   os_ << name << " \"B" << block_id << "\"\n";
481 }
482
483
484 void GraphC1Visualizer::PrintIntProperty(const char* name, int value) {
485   PrintIndent();
486   os_ << name << " " << value << "\n";
487 }
488
489
490 void GraphC1Visualizer::PrintCompilation(const CompilationInfo* info) {
491   Tag tag(this, "compilation");
492   if (info->IsOptimizing()) {
493     Handle<String> name = info->function()->debug_name();
494     PrintStringProperty("name", name->ToCString().get());
495     PrintIndent();
496     os_ << "method \"" << name->ToCString().get() << ":"
497         << info->optimization_id() << "\"\n";
498   } else {
499     CodeStub::Major major_key = info->code_stub()->MajorKey();
500     PrintStringProperty("name", CodeStub::MajorName(major_key, false));
501     PrintStringProperty("method", "stub");
502   }
503   PrintLongProperty("date",
504                     static_cast<int64_t>(base::OS::TimeCurrentMillis()));
505 }
506
507
508 void GraphC1Visualizer::PrintNodeId(Node* n) { os_ << "n" << SafeId(n); }
509
510
511 void GraphC1Visualizer::PrintNode(Node* n) {
512   PrintNodeId(n);
513   os_ << " " << *n->op() << " ";
514   PrintInputs(n);
515 }
516
517
518 void GraphC1Visualizer::PrintInputs(InputIter* i, int count,
519                                     const char* prefix) {
520   if (count > 0) {
521     os_ << prefix;
522   }
523   while (count > 0) {
524     os_ << " ";
525     PrintNodeId(**i);
526     ++(*i);
527     count--;
528   }
529 }
530
531
532 void GraphC1Visualizer::PrintInputs(Node* node) {
533   InputIter i = node->inputs().begin();
534   PrintInputs(&i, node->op()->ValueInputCount(), " ");
535   PrintInputs(&i, OperatorProperties::GetContextInputCount(node->op()),
536               " Ctx:");
537   PrintInputs(&i, OperatorProperties::GetFrameStateInputCount(node->op()),
538               " FS:");
539   PrintInputs(&i, node->op()->EffectInputCount(), " Eff:");
540   PrintInputs(&i, node->op()->ControlInputCount(), " Ctrl:");
541 }
542
543
544 void GraphC1Visualizer::PrintType(Node* node) {
545   if (NodeProperties::IsTyped(node)) {
546     Bounds bounds = NodeProperties::GetBounds(node);
547     os_ << " type:";
548     bounds.upper->PrintTo(os_);
549     os_ << "..";
550     bounds.lower->PrintTo(os_);
551   }
552 }
553
554
555 void GraphC1Visualizer::PrintSchedule(const char* phase,
556                                       const Schedule* schedule,
557                                       const SourcePositionTable* positions,
558                                       const InstructionSequence* instructions) {
559   Tag tag(this, "cfg");
560   PrintStringProperty("name", phase);
561   const BasicBlockVector* rpo = schedule->rpo_order();
562   for (size_t i = 0; i < rpo->size(); i++) {
563     BasicBlock* current = (*rpo)[i];
564     Tag block_tag(this, "block");
565     PrintBlockProperty("name", current->id());
566     PrintIntProperty("from_bci", -1);
567     PrintIntProperty("to_bci", -1);
568
569     PrintIndent();
570     os_ << "predecessors";
571     for (BasicBlock::Predecessors::iterator j = current->predecessors_begin();
572          j != current->predecessors_end(); ++j) {
573       os_ << " \"B" << (*j)->id() << "\"";
574     }
575     os_ << "\n";
576
577     PrintIndent();
578     os_ << "successors";
579     for (BasicBlock::Successors::iterator j = current->successors_begin();
580          j != current->successors_end(); ++j) {
581       os_ << " \"B" << (*j)->id() << "\"";
582     }
583     os_ << "\n";
584
585     PrintIndent();
586     os_ << "xhandlers\n";
587
588     PrintIndent();
589     os_ << "flags\n";
590
591     if (current->dominator() != NULL) {
592       PrintBlockProperty("dominator", current->dominator()->id());
593     }
594
595     PrintIntProperty("loop_depth", current->loop_depth());
596
597     const InstructionBlock* instruction_block =
598         instructions->InstructionBlockAt(current->GetRpoNumber());
599     if (instruction_block->code_start() >= 0) {
600       int first_index = instruction_block->first_instruction_index();
601       int last_index = instruction_block->last_instruction_index();
602       PrintIntProperty("first_lir_id", LifetimePosition::FromInstructionIndex(
603                                            first_index).Value());
604       PrintIntProperty("last_lir_id", LifetimePosition::FromInstructionIndex(
605                                           last_index).Value());
606     }
607
608     {
609       Tag states_tag(this, "states");
610       Tag locals_tag(this, "locals");
611       int total = 0;
612       for (BasicBlock::const_iterator i = current->begin(); i != current->end();
613            ++i) {
614         if ((*i)->opcode() == IrOpcode::kPhi) total++;
615       }
616       PrintIntProperty("size", total);
617       PrintStringProperty("method", "None");
618       int index = 0;
619       for (BasicBlock::const_iterator i = current->begin(); i != current->end();
620            ++i) {
621         if ((*i)->opcode() != IrOpcode::kPhi) continue;
622         PrintIndent();
623         os_ << index << " ";
624         PrintNodeId(*i);
625         os_ << " [";
626         PrintInputs(*i);
627         os_ << "]\n";
628         index++;
629       }
630     }
631
632     {
633       Tag HIR_tag(this, "HIR");
634       for (BasicBlock::const_iterator i = current->begin(); i != current->end();
635            ++i) {
636         Node* node = *i;
637         if (node->opcode() == IrOpcode::kPhi) continue;
638         int uses = node->UseCount();
639         PrintIndent();
640         os_ << "0 " << uses << " ";
641         PrintNode(node);
642         if (FLAG_trace_turbo_types) {
643           os_ << " ";
644           PrintType(node);
645         }
646         if (positions != NULL) {
647           SourcePosition position = positions->GetSourcePosition(node);
648           if (!position.IsUnknown()) {
649             DCHECK(!position.IsInvalid());
650             os_ << " pos:" << position.raw();
651           }
652         }
653         os_ << " <|@\n";
654       }
655
656       BasicBlock::Control control = current->control();
657       if (control != BasicBlock::kNone) {
658         PrintIndent();
659         os_ << "0 0 ";
660         if (current->control_input() != NULL) {
661           PrintNode(current->control_input());
662         } else {
663           os_ << -1 - current->id().ToInt() << " Goto";
664         }
665         os_ << " ->";
666         for (BasicBlock::Successors::iterator j = current->successors_begin();
667              j != current->successors_end(); ++j) {
668           os_ << " B" << (*j)->id();
669         }
670         if (FLAG_trace_turbo_types && current->control_input() != NULL) {
671           os_ << " ";
672           PrintType(current->control_input());
673         }
674         os_ << " <|@\n";
675       }
676     }
677
678     if (instructions != NULL) {
679       Tag LIR_tag(this, "LIR");
680       for (int j = instruction_block->first_instruction_index();
681            j <= instruction_block->last_instruction_index(); j++) {
682         PrintIndent();
683         PrintableInstruction printable = {RegisterConfiguration::ArchDefault(),
684                                           instructions->InstructionAt(j)};
685         os_ << j << " " << printable << " <|@\n";
686       }
687     }
688   }
689 }
690
691
692 void GraphC1Visualizer::PrintAllocator(const char* phase,
693                                        const RegisterAllocator* allocator) {
694   Tag tag(this, "intervals");
695   PrintStringProperty("name", phase);
696
697   for (auto range : allocator->fixed_double_live_ranges()) {
698     PrintLiveRange(range, "fixed");
699   }
700
701   for (auto range : allocator->fixed_live_ranges()) {
702     PrintLiveRange(range, "fixed");
703   }
704
705   for (auto range : allocator->live_ranges()) {
706     PrintLiveRange(range, "object");
707   }
708 }
709
710
711 void GraphC1Visualizer::PrintLiveRange(LiveRange* range, const char* type) {
712   if (range != NULL && !range->IsEmpty()) {
713     PrintIndent();
714     os_ << range->id() << " " << type;
715     if (range->HasRegisterAssigned()) {
716       InstructionOperand* op = range->CreateAssignedOperand(zone());
717       int assigned_reg = op->index();
718       if (op->IsDoubleRegister()) {
719         os_ << " \"" << DoubleRegister::AllocationIndexToString(assigned_reg)
720             << "\"";
721       } else {
722         DCHECK(op->IsRegister());
723         os_ << " \"" << Register::AllocationIndexToString(assigned_reg) << "\"";
724       }
725     } else if (range->IsSpilled()) {
726       InstructionOperand* op = range->TopLevel()->GetSpillOperand();
727       if (op->IsDoubleStackSlot()) {
728         os_ << " \"double_stack:" << op->index() << "\"";
729       } else if (op->IsStackSlot()) {
730         os_ << " \"stack:" << op->index() << "\"";
731       } else {
732         DCHECK(op->IsConstant());
733         os_ << " \"const(nostack):" << op->index() << "\"";
734       }
735     }
736     int parent_index = -1;
737     if (range->IsChild()) {
738       parent_index = range->parent()->id();
739     } else {
740       parent_index = range->id();
741     }
742     InstructionOperand* op = range->FirstHint();
743     int hint_index = -1;
744     if (op != NULL && op->IsUnallocated()) {
745       hint_index = UnallocatedOperand::cast(op)->virtual_register();
746     }
747     os_ << " " << parent_index << " " << hint_index;
748     UseInterval* cur_interval = range->first_interval();
749     while (cur_interval != NULL && range->Covers(cur_interval->start())) {
750       os_ << " [" << cur_interval->start().Value() << ", "
751           << cur_interval->end().Value() << "[";
752       cur_interval = cur_interval->next();
753     }
754
755     UsePosition* current_pos = range->first_pos();
756     while (current_pos != NULL) {
757       if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) {
758         os_ << " " << current_pos->pos().Value() << " M";
759       }
760       current_pos = current_pos->next();
761     }
762
763     os_ << " \"\"\n";
764   }
765 }
766
767
768 std::ostream& operator<<(std::ostream& os, const AsC1VCompilation& ac) {
769   Zone tmp_zone(ac.info_->isolate());
770   GraphC1Visualizer(os, &tmp_zone).PrintCompilation(ac.info_);
771   return os;
772 }
773
774
775 std::ostream& operator<<(std::ostream& os, const AsC1V& ac) {
776   Zone tmp_zone(ac.schedule_->zone()->isolate());
777   GraphC1Visualizer(os, &tmp_zone)
778       .PrintSchedule(ac.phase_, ac.schedule_, ac.positions_, ac.instructions_);
779   return os;
780 }
781
782
783 std::ostream& operator<<(std::ostream& os, const AsC1VAllocator& ac) {
784   Zone tmp_zone(ac.allocator_->code()->zone()->isolate());
785   GraphC1Visualizer(os, &tmp_zone).PrintAllocator(ac.phase_, ac.allocator_);
786   return os;
787 }
788 }
789 }
790 }  // namespace v8::internal::compiler