deps: update v8 to 4.3.61.21
[platform/upstream/nodejs.git] / deps / 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/all-nodes.h"
12 #include "src/compiler/graph.h"
13 #include "src/compiler/node.h"
14 #include "src/compiler/node-properties.h"
15 #include "src/compiler/opcodes.h"
16 #include "src/compiler/operator.h"
17 #include "src/compiler/operator-properties.h"
18 #include "src/compiler/register-allocator.h"
19 #include "src/compiler/schedule.h"
20 #include "src/compiler/scheduler.h"
21 #include "src/ostreams.h"
22
23 namespace v8 {
24 namespace internal {
25 namespace compiler {
26
27
28 FILE* OpenVisualizerLogFile(CompilationInfo* info, const char* phase,
29                             const char* suffix, const char* mode) {
30   EmbeddedVector<char, 256> filename(0);
31   SmartArrayPointer<char> function_name;
32   if (info->has_shared_info()) {
33     function_name = info->shared_info()->DebugName()->ToCString();
34     if (strlen(function_name.get()) > 0) {
35       SNPrintF(filename, "turbo-%s", function_name.get());
36     } else {
37       SNPrintF(filename, "turbo-%p", static_cast<void*>(info));
38     }
39   } else {
40     SNPrintF(filename, "turbo-none-%s", phase);
41   }
42   std::replace(filename.start(), filename.start() + filename.length(), ' ',
43                '_');
44
45   EmbeddedVector<char, 256> full_filename;
46   if (phase == NULL) {
47     SNPrintF(full_filename, "%s.%s", filename.start(), suffix);
48   } else {
49     SNPrintF(full_filename, "%s-%s.%s", filename.start(), phase, suffix);
50   }
51   return base::OS::FOpen(full_filename.start(), mode);
52 }
53
54
55 static int SafeId(Node* node) { return node == NULL ? -1 : node->id(); }
56 static const char* SafeMnemonic(Node* node) {
57   return node == NULL ? "null" : node->op()->mnemonic();
58 }
59
60 #define DEAD_COLOR "#999999"
61
62 class Escaped {
63  public:
64   explicit Escaped(const std::ostringstream& os,
65                    const char* escaped_chars = "<>|{}")
66       : str_(os.str()), escaped_chars_(escaped_chars) {}
67
68   friend std::ostream& operator<<(std::ostream& os, const Escaped& e) {
69     for (std::string::const_iterator i = e.str_.begin(); i != e.str_.end();
70          ++i) {
71       if (e.needs_escape(*i)) os << "\\";
72       os << *i;
73     }
74     return os;
75   }
76
77  private:
78   bool needs_escape(char ch) const {
79     for (size_t i = 0; i < strlen(escaped_chars_); ++i) {
80       if (ch == escaped_chars_[i]) return true;
81     }
82     return false;
83   }
84
85   const std::string str_;
86   const char* const escaped_chars_;
87 };
88
89 class JSONGraphNodeWriter {
90  public:
91   JSONGraphNodeWriter(std::ostream& os, Zone* zone, const Graph* graph,
92                       const SourcePositionTable* positions)
93       : os_(os), all_(zone, graph), positions_(positions), first_node_(true) {}
94
95   void Print() {
96     for (Node* const node : all_.live) PrintNode(node);
97     os_ << "\n";
98   }
99
100   void PrintNode(Node* node) {
101     if (first_node_) {
102       first_node_ = false;
103     } else {
104       os_ << ",\n";
105     }
106     std::ostringstream label;
107     label << *node->op();
108     os_ << "{\"id\":" << SafeId(node) << ",\"label\":\"" << Escaped(label, "\"")
109         << "\"";
110     IrOpcode::Value opcode = node->opcode();
111     if (IrOpcode::IsPhiOpcode(opcode)) {
112       os_ << ",\"rankInputs\":[0," << NodeProperties::FirstControlIndex(node)
113           << "]";
114       os_ << ",\"rankWithInput\":[" << NodeProperties::FirstControlIndex(node)
115           << "]";
116     } else if (opcode == IrOpcode::kIfTrue || opcode == IrOpcode::kIfFalse ||
117                opcode == IrOpcode::kLoop) {
118       os_ << ",\"rankInputs\":[" << NodeProperties::FirstControlIndex(node)
119           << "]";
120     }
121     if (opcode == IrOpcode::kBranch) {
122       os_ << ",\"rankInputs\":[0]";
123     }
124     SourcePosition position = positions_->GetSourcePosition(node);
125     if (!position.IsUnknown()) {
126       DCHECK(!position.IsInvalid());
127       os_ << ",\"pos\":" << position.raw();
128     }
129     os_ << ",\"opcode\":\"" << IrOpcode::Mnemonic(node->opcode()) << "\"";
130     os_ << ",\"control\":" << (NodeProperties::IsControl(node) ? "true"
131                                                                : "false");
132     os_ << "}";
133   }
134
135  private:
136   std::ostream& os_;
137   AllNodes all_;
138   const SourcePositionTable* positions_;
139   bool first_node_;
140
141   DISALLOW_COPY_AND_ASSIGN(JSONGraphNodeWriter);
142 };
143
144
145 class JSONGraphEdgeWriter {
146  public:
147   JSONGraphEdgeWriter(std::ostream& os, Zone* zone, const Graph* graph)
148       : os_(os), all_(zone, graph), first_edge_(true) {}
149
150   void Print() {
151     for (Node* const node : all_.live) PrintEdges(node);
152     os_ << "\n";
153   }
154
155   void PrintEdges(Node* node) {
156     for (int i = 0; i < node->InputCount(); i++) {
157       Node* input = node->InputAt(i);
158       if (input == NULL) continue;
159       PrintEdge(node, i, input);
160     }
161   }
162
163   void PrintEdge(Node* from, int index, Node* to) {
164     if (first_edge_) {
165       first_edge_ = false;
166     } else {
167       os_ << ",\n";
168     }
169     const char* edge_type = NULL;
170     if (index < NodeProperties::FirstValueIndex(from)) {
171       edge_type = "unknown";
172     } else if (index < NodeProperties::FirstContextIndex(from)) {
173       edge_type = "value";
174     } else if (index < NodeProperties::FirstFrameStateIndex(from)) {
175       edge_type = "context";
176     } else if (index < NodeProperties::FirstEffectIndex(from)) {
177       edge_type = "frame-state";
178     } else if (index < NodeProperties::FirstControlIndex(from)) {
179       edge_type = "effect";
180     } else {
181       edge_type = "control";
182     }
183     os_ << "{\"source\":" << SafeId(to) << ",\"target\":" << SafeId(from)
184         << ",\"index\":" << index << ",\"type\":\"" << edge_type << "\"}";
185   }
186
187  private:
188   std::ostream& os_;
189   AllNodes all_;
190   bool first_edge_;
191
192   DISALLOW_COPY_AND_ASSIGN(JSONGraphEdgeWriter);
193 };
194
195
196 std::ostream& operator<<(std::ostream& os, const AsJSON& ad) {
197   Zone tmp_zone;
198   os << "{\n\"nodes\":[";
199   JSONGraphNodeWriter(os, &tmp_zone, &ad.graph, ad.positions).Print();
200   os << "],\n\"edges\":[";
201   JSONGraphEdgeWriter(os, &tmp_zone, &ad.graph).Print();
202   os << "]}";
203   return os;
204 }
205
206
207 class GraphVisualizer {
208  public:
209   GraphVisualizer(std::ostream& os, Zone* zone, const Graph* graph)
210       : all_(zone, graph), os_(os) {}
211
212   void Print();
213
214   void PrintNode(Node* node, bool gray);
215
216  private:
217   void PrintEdge(Edge edge);
218
219   AllNodes all_;
220   std::ostream& os_;
221
222   DISALLOW_COPY_AND_ASSIGN(GraphVisualizer);
223 };
224
225
226 static Node* GetControlCluster(Node* node) {
227   if (OperatorProperties::IsBasicBlockBegin(node->op())) {
228     return node;
229   } else if (node->op()->ControlInputCount() == 1) {
230     Node* control = NodeProperties::GetControlInput(node, 0);
231     return control != NULL &&
232                    OperatorProperties::IsBasicBlockBegin(control->op())
233                ? control
234                : NULL;
235   } else {
236     return NULL;
237   }
238 }
239
240
241 void GraphVisualizer::PrintNode(Node* node, bool gray) {
242   Node* control_cluster = GetControlCluster(node);
243   if (control_cluster != NULL) {
244     os_ << "  subgraph cluster_BasicBlock" << control_cluster->id() << " {\n";
245   }
246   os_ << "  ID" << SafeId(node) << " [\n";
247
248   os_ << "    shape=\"record\"\n";
249   switch (node->opcode()) {
250     case IrOpcode::kEnd:
251     case IrOpcode::kDead:
252     case IrOpcode::kStart:
253       os_ << "    style=\"diagonals\"\n";
254       break;
255     case IrOpcode::kMerge:
256     case IrOpcode::kIfTrue:
257     case IrOpcode::kIfFalse:
258     case IrOpcode::kLoop:
259       os_ << "    style=\"rounded\"\n";
260       break;
261     default:
262       break;
263   }
264
265   if (gray) {
266     os_ << "    style=\"filled\"\n"
267         << "    fillcolor=\"" DEAD_COLOR "\"\n";
268   }
269
270   std::ostringstream label;
271   label << *node->op();
272   os_ << "    label=\"{{#" << SafeId(node) << ":" << Escaped(label);
273
274   auto i = node->input_edges().begin();
275   for (int j = node->op()->ValueInputCount(); j > 0; ++i, j--) {
276     os_ << "|<I" << (*i).index() << ">#" << SafeId((*i).to());
277   }
278   for (int j = OperatorProperties::GetContextInputCount(node->op()); j > 0;
279        ++i, j--) {
280     os_ << "|<I" << (*i).index() << ">X #" << SafeId((*i).to());
281   }
282   for (int j = OperatorProperties::GetFrameStateInputCount(node->op()); j > 0;
283        ++i, j--) {
284     os_ << "|<I" << (*i).index() << ">F #" << SafeId((*i).to());
285   }
286   for (int j = node->op()->EffectInputCount(); j > 0; ++i, j--) {
287     os_ << "|<I" << (*i).index() << ">E #" << SafeId((*i).to());
288   }
289
290   if (OperatorProperties::IsBasicBlockBegin(node->op()) ||
291       GetControlCluster(node) == NULL) {
292     for (int j = node->op()->ControlInputCount(); j > 0; ++i, j--) {
293       os_ << "|<I" << (*i).index() << ">C #" << SafeId((*i).to());
294     }
295   }
296   os_ << "}";
297
298   if (FLAG_trace_turbo_types && NodeProperties::IsTyped(node)) {
299     Bounds bounds = NodeProperties::GetBounds(node);
300     std::ostringstream upper;
301     bounds.upper->PrintTo(upper);
302     std::ostringstream lower;
303     bounds.lower->PrintTo(lower);
304     os_ << "|" << Escaped(upper) << "|" << Escaped(lower);
305   }
306   os_ << "}\"\n";
307
308   os_ << "  ]\n";
309   if (control_cluster != NULL) os_ << "  }\n";
310 }
311
312
313 static bool IsLikelyBackEdge(Node* from, int index, Node* to) {
314   if (NodeProperties::IsPhi(from)) {
315     Node* control = NodeProperties::GetControlInput(from, 0);
316     return control != NULL && control->opcode() != IrOpcode::kMerge &&
317            control != to && index != 0;
318   } else if (from->opcode() == IrOpcode::kLoop) {
319     return index != 0;
320   } else {
321     return false;
322   }
323 }
324
325
326 void GraphVisualizer::PrintEdge(Edge edge) {
327   Node* from = edge.from();
328   int index = edge.index();
329   Node* to = edge.to();
330
331   if (!all_.IsLive(to)) return;  // skip inputs that point to dead or NULL.
332
333   bool unconstrained = IsLikelyBackEdge(from, index, to);
334   os_ << "  ID" << SafeId(from);
335
336   if (OperatorProperties::IsBasicBlockBegin(from->op()) ||
337       GetControlCluster(from) == NULL ||
338       (from->op()->ControlInputCount() > 0 &&
339        NodeProperties::GetControlInput(from) != to)) {
340     os_ << ":I" << index << ":n -> ID" << SafeId(to) << ":s"
341         << "[" << (unconstrained ? "constraint=false, " : "")
342         << (NodeProperties::IsControlEdge(edge) ? "style=bold, " : "")
343         << (NodeProperties::IsEffectEdge(edge) ? "style=dotted, " : "")
344         << (NodeProperties::IsContextEdge(edge) ? "style=dashed, " : "") << "]";
345   } else {
346     os_ << " -> ID" << SafeId(to) << ":s [color=transparent, "
347         << (unconstrained ? "constraint=false, " : "")
348         << (NodeProperties::IsControlEdge(edge) ? "style=dashed, " : "") << "]";
349   }
350   os_ << "\n";
351 }
352
353
354 void GraphVisualizer::Print() {
355   os_ << "digraph D {\n"
356       << "  node [fontsize=8,height=0.25]\n"
357       << "  rankdir=\"BT\"\n"
358       << "  ranksep=\"1.2 equally\"\n"
359       << "  overlap=\"false\"\n"
360       << "  splines=\"true\"\n"
361       << "  concentrate=\"true\"\n"
362       << "  \n";
363
364   // Find all nodes that are not reachable from end that use live nodes.
365   std::set<Node*> gray;
366   for (Node* const node : all_.live) {
367     for (Node* const use : node->uses()) {
368       if (!all_.IsLive(use)) gray.insert(use);
369     }
370   }
371
372   // Make sure all nodes have been output before writing out the edges.
373   for (Node* const node : all_.live) PrintNode(node, false);
374   for (Node* const node : gray) PrintNode(node, true);
375
376   // With all the nodes written, add the edges.
377   for (Node* const node : all_.live) {
378     for (Edge edge : node->use_edges()) {
379       PrintEdge(edge);
380     }
381   }
382   os_ << "}\n";
383 }
384
385
386 std::ostream& operator<<(std::ostream& os, const AsDOT& ad) {
387   Zone tmp_zone;
388   GraphVisualizer(os, &tmp_zone, &ad.graph).Print();
389   return os;
390 }
391
392
393 class GraphC1Visualizer {
394  public:
395   GraphC1Visualizer(std::ostream& os, Zone* zone);  // NOLINT
396
397   void PrintCompilation(const CompilationInfo* info);
398   void PrintSchedule(const char* phase, const Schedule* schedule,
399                      const SourcePositionTable* positions,
400                      const InstructionSequence* instructions);
401   void PrintAllocator(const char* phase, const RegisterAllocator* allocator);
402   Zone* zone() const { return zone_; }
403
404  private:
405   void PrintIndent();
406   void PrintStringProperty(const char* name, const char* value);
407   void PrintLongProperty(const char* name, int64_t value);
408   void PrintIntProperty(const char* name, int value);
409   void PrintBlockProperty(const char* name, int rpo_number);
410   void PrintNodeId(Node* n);
411   void PrintNode(Node* n);
412   void PrintInputs(Node* n);
413   template <typename InputIterator>
414   void PrintInputs(InputIterator* i, int count, const char* prefix);
415   void PrintType(Node* node);
416
417   void PrintLiveRange(LiveRange* range, const char* type);
418   class Tag FINAL BASE_EMBEDDED {
419    public:
420     Tag(GraphC1Visualizer* visualizer, const char* name) {
421       name_ = name;
422       visualizer_ = visualizer;
423       visualizer->PrintIndent();
424       visualizer_->os_ << "begin_" << name << "\n";
425       visualizer->indent_++;
426     }
427
428     ~Tag() {
429       visualizer_->indent_--;
430       visualizer_->PrintIndent();
431       visualizer_->os_ << "end_" << name_ << "\n";
432       DCHECK(visualizer_->indent_ >= 0);
433     }
434
435    private:
436     GraphC1Visualizer* visualizer_;
437     const char* name_;
438   };
439
440   std::ostream& os_;
441   int indent_;
442   Zone* zone_;
443
444   DISALLOW_COPY_AND_ASSIGN(GraphC1Visualizer);
445 };
446
447
448 void GraphC1Visualizer::PrintIndent() {
449   for (int i = 0; i < indent_; i++) {
450     os_ << "  ";
451   }
452 }
453
454
455 GraphC1Visualizer::GraphC1Visualizer(std::ostream& os, Zone* zone)
456     : os_(os), indent_(0), zone_(zone) {}
457
458
459 void GraphC1Visualizer::PrintStringProperty(const char* name,
460                                             const char* value) {
461   PrintIndent();
462   os_ << name << " \"" << value << "\"\n";
463 }
464
465
466 void GraphC1Visualizer::PrintLongProperty(const char* name, int64_t value) {
467   PrintIndent();
468   os_ << name << " " << static_cast<int>(value / 1000) << "\n";
469 }
470
471
472 void GraphC1Visualizer::PrintBlockProperty(const char* name, int rpo_number) {
473   PrintIndent();
474   os_ << name << " \"B" << rpo_number << "\"\n";
475 }
476
477
478 void GraphC1Visualizer::PrintIntProperty(const char* name, int value) {
479   PrintIndent();
480   os_ << name << " " << value << "\n";
481 }
482
483
484 void GraphC1Visualizer::PrintCompilation(const CompilationInfo* info) {
485   Tag tag(this, "compilation");
486   if (info->IsOptimizing()) {
487     Handle<String> name = info->function()->debug_name();
488     PrintStringProperty("name", name->ToCString().get());
489     PrintIndent();
490     os_ << "method \"" << name->ToCString().get() << ":"
491         << info->optimization_id() << "\"\n";
492   } else {
493     CodeStub::Major major_key = info->code_stub()->MajorKey();
494     PrintStringProperty("name", CodeStub::MajorName(major_key, false));
495     PrintStringProperty("method", "stub");
496   }
497   PrintLongProperty("date",
498                     static_cast<int64_t>(base::OS::TimeCurrentMillis()));
499 }
500
501
502 void GraphC1Visualizer::PrintNodeId(Node* n) { os_ << "n" << SafeId(n); }
503
504
505 void GraphC1Visualizer::PrintNode(Node* n) {
506   PrintNodeId(n);
507   os_ << " " << *n->op() << " ";
508   PrintInputs(n);
509 }
510
511
512 template <typename InputIterator>
513 void GraphC1Visualizer::PrintInputs(InputIterator* i, int count,
514                                     const char* prefix) {
515   if (count > 0) {
516     os_ << prefix;
517   }
518   while (count > 0) {
519     os_ << " ";
520     PrintNodeId(**i);
521     ++(*i);
522     count--;
523   }
524 }
525
526
527 void GraphC1Visualizer::PrintInputs(Node* node) {
528   auto i = node->inputs().begin();
529   PrintInputs(&i, node->op()->ValueInputCount(), " ");
530   PrintInputs(&i, OperatorProperties::GetContextInputCount(node->op()),
531               " Ctx:");
532   PrintInputs(&i, OperatorProperties::GetFrameStateInputCount(node->op()),
533               " FS:");
534   PrintInputs(&i, node->op()->EffectInputCount(), " Eff:");
535   PrintInputs(&i, node->op()->ControlInputCount(), " Ctrl:");
536 }
537
538
539 void GraphC1Visualizer::PrintType(Node* node) {
540   if (NodeProperties::IsTyped(node)) {
541     Bounds bounds = NodeProperties::GetBounds(node);
542     os_ << " type:";
543     bounds.upper->PrintTo(os_);
544     os_ << "..";
545     bounds.lower->PrintTo(os_);
546   }
547 }
548
549
550 void GraphC1Visualizer::PrintSchedule(const char* phase,
551                                       const Schedule* schedule,
552                                       const SourcePositionTable* positions,
553                                       const InstructionSequence* instructions) {
554   Tag tag(this, "cfg");
555   PrintStringProperty("name", phase);
556   const BasicBlockVector* rpo = schedule->rpo_order();
557   for (size_t i = 0; i < rpo->size(); i++) {
558     BasicBlock* current = (*rpo)[i];
559     Tag block_tag(this, "block");
560     PrintBlockProperty("name", current->rpo_number());
561     PrintIntProperty("from_bci", -1);
562     PrintIntProperty("to_bci", -1);
563
564     PrintIndent();
565     os_ << "predecessors";
566     for (BasicBlock* predecessor : current->predecessors()) {
567       os_ << " \"B" << predecessor->rpo_number() << "\"";
568     }
569     os_ << "\n";
570
571     PrintIndent();
572     os_ << "successors";
573     for (BasicBlock* successor : current->successors()) {
574       os_ << " \"B" << successor->rpo_number() << "\"";
575     }
576     os_ << "\n";
577
578     PrintIndent();
579     os_ << "xhandlers\n";
580
581     PrintIndent();
582     os_ << "flags\n";
583
584     if (current->dominator() != NULL) {
585       PrintBlockProperty("dominator", current->dominator()->rpo_number());
586     }
587
588     PrintIntProperty("loop_depth", current->loop_depth());
589
590     const InstructionBlock* instruction_block =
591         instructions->InstructionBlockAt(
592             RpoNumber::FromInt(current->rpo_number()));
593     if (instruction_block->code_start() >= 0) {
594       int first_index = instruction_block->first_instruction_index();
595       int last_index = instruction_block->last_instruction_index();
596       PrintIntProperty("first_lir_id", LifetimePosition::FromInstructionIndex(
597                                            first_index).Value());
598       PrintIntProperty("last_lir_id", LifetimePosition::FromInstructionIndex(
599                                           last_index).Value());
600     }
601
602     {
603       Tag states_tag(this, "states");
604       Tag locals_tag(this, "locals");
605       int total = 0;
606       for (BasicBlock::const_iterator i = current->begin(); i != current->end();
607            ++i) {
608         if ((*i)->opcode() == IrOpcode::kPhi) total++;
609       }
610       PrintIntProperty("size", total);
611       PrintStringProperty("method", "None");
612       int index = 0;
613       for (BasicBlock::const_iterator i = current->begin(); i != current->end();
614            ++i) {
615         if ((*i)->opcode() != IrOpcode::kPhi) continue;
616         PrintIndent();
617         os_ << index << " ";
618         PrintNodeId(*i);
619         os_ << " [";
620         PrintInputs(*i);
621         os_ << "]\n";
622         index++;
623       }
624     }
625
626     {
627       Tag HIR_tag(this, "HIR");
628       for (BasicBlock::const_iterator i = current->begin(); i != current->end();
629            ++i) {
630         Node* node = *i;
631         if (node->opcode() == IrOpcode::kPhi) continue;
632         int uses = node->UseCount();
633         PrintIndent();
634         os_ << "0 " << uses << " ";
635         PrintNode(node);
636         if (FLAG_trace_turbo_types) {
637           os_ << " ";
638           PrintType(node);
639         }
640         if (positions != NULL) {
641           SourcePosition position = positions->GetSourcePosition(node);
642           if (!position.IsUnknown()) {
643             DCHECK(!position.IsInvalid());
644             os_ << " pos:" << position.raw();
645           }
646         }
647         os_ << " <|@\n";
648       }
649
650       BasicBlock::Control control = current->control();
651       if (control != BasicBlock::kNone) {
652         PrintIndent();
653         os_ << "0 0 ";
654         if (current->control_input() != NULL) {
655           PrintNode(current->control_input());
656         } else {
657           os_ << -1 - current->rpo_number() << " Goto";
658         }
659         os_ << " ->";
660         for (BasicBlock* successor : current->successors()) {
661           os_ << " B" << successor->rpo_number();
662         }
663         if (FLAG_trace_turbo_types && current->control_input() != NULL) {
664           os_ << " ";
665           PrintType(current->control_input());
666         }
667         os_ << " <|@\n";
668       }
669     }
670
671     if (instructions != NULL) {
672       Tag LIR_tag(this, "LIR");
673       for (int j = instruction_block->first_instruction_index();
674            j <= instruction_block->last_instruction_index(); j++) {
675         PrintIndent();
676         PrintableInstruction printable = {RegisterConfiguration::ArchDefault(),
677                                           instructions->InstructionAt(j)};
678         os_ << j << " " << printable << " <|@\n";
679       }
680     }
681   }
682 }
683
684
685 void GraphC1Visualizer::PrintAllocator(const char* phase,
686                                        const RegisterAllocator* allocator) {
687   Tag tag(this, "intervals");
688   PrintStringProperty("name", phase);
689
690   for (auto range : allocator->fixed_double_live_ranges()) {
691     PrintLiveRange(range, "fixed");
692   }
693
694   for (auto range : allocator->fixed_live_ranges()) {
695     PrintLiveRange(range, "fixed");
696   }
697
698   for (auto range : allocator->live_ranges()) {
699     PrintLiveRange(range, "object");
700   }
701 }
702
703
704 void GraphC1Visualizer::PrintLiveRange(LiveRange* range, const char* type) {
705   if (range != NULL && !range->IsEmpty()) {
706     PrintIndent();
707     os_ << range->id() << " " << type;
708     if (range->HasRegisterAssigned()) {
709       InstructionOperand op = range->GetAssignedOperand();
710       int assigned_reg = op.index();
711       if (op.IsDoubleRegister()) {
712         os_ << " \"" << DoubleRegister::AllocationIndexToString(assigned_reg)
713             << "\"";
714       } else {
715         DCHECK(op.IsRegister());
716         os_ << " \"" << Register::AllocationIndexToString(assigned_reg) << "\"";
717       }
718     } else if (range->IsSpilled()) {
719       int index = -1;
720       if (range->TopLevel()->HasSpillRange()) {
721         index = kMaxInt;  // This hasn't been set yet.
722       } else {
723         index = range->TopLevel()->GetSpillOperand()->index();
724       }
725       if (range->TopLevel()->Kind() == DOUBLE_REGISTERS) {
726         os_ << " \"double_stack:" << index << "\"";
727       } else if (range->TopLevel()->Kind() == GENERAL_REGISTERS) {
728         os_ << " \"stack:" << index << "\"";
729       } else {
730         os_ << " \"const(nostack):" << index << "\"";
731       }
732     }
733     int parent_index = -1;
734     if (range->IsChild()) {
735       parent_index = range->parent()->id();
736     } else {
737       parent_index = range->id();
738     }
739     InstructionOperand* op = range->FirstHint();
740     int hint_index = -1;
741     if (op != NULL && op->IsUnallocated()) {
742       hint_index = UnallocatedOperand::cast(op)->virtual_register();
743     }
744     os_ << " " << parent_index << " " << hint_index;
745     UseInterval* cur_interval = range->first_interval();
746     while (cur_interval != NULL && range->Covers(cur_interval->start())) {
747       os_ << " [" << cur_interval->start().Value() << ", "
748           << cur_interval->end().Value() << "[";
749       cur_interval = cur_interval->next();
750     }
751
752     UsePosition* current_pos = range->first_pos();
753     while (current_pos != NULL) {
754       if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) {
755         os_ << " " << current_pos->pos().Value() << " M";
756       }
757       current_pos = current_pos->next();
758     }
759
760     os_ << " \"\"\n";
761   }
762 }
763
764
765 std::ostream& operator<<(std::ostream& os, const AsC1VCompilation& ac) {
766   Zone tmp_zone;
767   GraphC1Visualizer(os, &tmp_zone).PrintCompilation(ac.info_);
768   return os;
769 }
770
771
772 std::ostream& operator<<(std::ostream& os, const AsC1V& ac) {
773   Zone tmp_zone;
774   GraphC1Visualizer(os, &tmp_zone)
775       .PrintSchedule(ac.phase_, ac.schedule_, ac.positions_, ac.instructions_);
776   return os;
777 }
778
779
780 std::ostream& operator<<(std::ostream& os, const AsC1VAllocator& ac) {
781   Zone tmp_zone;
782   GraphC1Visualizer(os, &tmp_zone).PrintAllocator(ac.phase_, ac.allocator_);
783   return os;
784 }
785
786 const int kUnvisited = 0;
787 const int kOnStack = 1;
788 const int kVisited = 2;
789
790 std::ostream& operator<<(std::ostream& os, const AsRPO& ar) {
791   Zone local_zone;
792   ZoneVector<byte> state(ar.graph.NodeCount(), kUnvisited, &local_zone);
793   ZoneStack<Node*> stack(&local_zone);
794
795   stack.push(ar.graph.end());
796   state[ar.graph.end()->id()] = kOnStack;
797   while (!stack.empty()) {
798     Node* n = stack.top();
799     bool pop = true;
800     for (Node* const i : n->inputs()) {
801       if (state[i->id()] == kUnvisited) {
802         state[i->id()] = kOnStack;
803         stack.push(i);
804         pop = false;
805         break;
806       }
807     }
808     if (pop) {
809       state[n->id()] = kVisited;
810       stack.pop();
811       os << "#" << n->id() << ":" << *n->op() << "(";
812       int j = 0;
813       for (Node* const i : n->inputs()) {
814         if (j++ > 0) os << ", ";
815         os << "#" << SafeId(i) << ":" << SafeMnemonic(i);
816       }
817       os << ")" << std::endl;
818     }
819   }
820   return os;
821 }
822 }
823 }
824 }  // namespace v8::internal::compiler