• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <memory>
8 #include <sstream>
9 #include <string>
10 
11 #include "src/code-stubs.h"
12 #include "src/compilation-info.h"
13 #include "src/compiler/all-nodes.h"
14 #include "src/compiler/compiler-source-position-table.h"
15 #include "src/compiler/graph.h"
16 #include "src/compiler/node-properties.h"
17 #include "src/compiler/node.h"
18 #include "src/compiler/opcodes.h"
19 #include "src/compiler/operator-properties.h"
20 #include "src/compiler/operator.h"
21 #include "src/compiler/register-allocator.h"
22 #include "src/compiler/schedule.h"
23 #include "src/compiler/scheduler.h"
24 #include "src/interpreter/bytecodes.h"
25 #include "src/objects-inl.h"
26 #include "src/ostreams.h"
27 
28 namespace v8 {
29 namespace internal {
30 namespace compiler {
31 
GetVisualizerLogFileName(CompilationInfo * info,const char * phase,const char * suffix)32 std::unique_ptr<char[]> GetVisualizerLogFileName(CompilationInfo* info,
33                                                  const char* phase,
34                                                  const char* suffix) {
35   EmbeddedVector<char, 256> filename(0);
36   std::unique_ptr<char[]> debug_name = info->GetDebugName();
37   if (strlen(debug_name.get()) > 0) {
38     if (info->has_shared_info()) {
39       int attempt = info->shared_info()->opt_count();
40       SNPrintF(filename, "turbo-%s-%i", debug_name.get(), attempt);
41     } else {
42       SNPrintF(filename, "turbo-%s", debug_name.get());
43     }
44   } else if (info->has_shared_info()) {
45     int attempt = info->shared_info()->opt_count();
46     SNPrintF(filename, "turbo-%p-%i", static_cast<void*>(info), attempt);
47   } else {
48     SNPrintF(filename, "turbo-none-%s", phase);
49   }
50   EmbeddedVector<char, 256> source_file(0);
51   bool source_available = false;
52   if (FLAG_trace_file_names && info->parse_info()) {
53     Object* source_name = info->script()->name();
54     if (source_name->IsString()) {
55       String* str = String::cast(source_name);
56       if (str->length() > 0) {
57         SNPrintF(source_file, "%s", str->ToCString().get());
58         std::replace(source_file.start(),
59                      source_file.start() + source_file.length(), '/', '_');
60         source_available = true;
61       }
62     }
63   }
64   std::replace(filename.start(), filename.start() + filename.length(), ' ',
65                '_');
66 
67   EmbeddedVector<char, 256> full_filename;
68   if (phase == nullptr && !source_available) {
69     SNPrintF(full_filename, "%s.%s", filename.start(), suffix);
70   } else if (phase != nullptr && !source_available) {
71     SNPrintF(full_filename, "%s-%s.%s", filename.start(), phase, suffix);
72   } else if (phase == nullptr && source_available) {
73     SNPrintF(full_filename, "%s_%s.%s", filename.start(), source_file.start(),
74              suffix);
75   } else {
76     SNPrintF(full_filename, "%s_%s-%s.%s", filename.start(),
77              source_file.start(), phase, suffix);
78   }
79 
80   char* buffer = new char[full_filename.length() + 1];
81   memcpy(buffer, full_filename.start(), full_filename.length());
82   buffer[full_filename.length()] = '\0';
83   return std::unique_ptr<char[]>(buffer);
84 }
85 
86 
SafeId(Node * node)87 static int SafeId(Node* node) { return node == nullptr ? -1 : node->id(); }
SafeMnemonic(Node * node)88 static const char* SafeMnemonic(Node* node) {
89   return node == nullptr ? "null" : node->op()->mnemonic();
90 }
91 
92 class JSONEscaped {
93  public:
JSONEscaped(const std::ostringstream & os)94   explicit JSONEscaped(const std::ostringstream& os) : str_(os.str()) {}
95 
operator <<(std::ostream & os,const JSONEscaped & e)96   friend std::ostream& operator<<(std::ostream& os, const JSONEscaped& e) {
97     for (char c : e.str_) PipeCharacter(os, c);
98     return os;
99   }
100 
101  private:
PipeCharacter(std::ostream & os,char c)102   static std::ostream& PipeCharacter(std::ostream& os, char c) {
103     if (c == '"') return os << "\\\"";
104     if (c == '\\') return os << "\\\\";
105     if (c == '\b') return os << "\\b";
106     if (c == '\f') return os << "\\f";
107     if (c == '\n') return os << "\\n";
108     if (c == '\r') return os << "\\r";
109     if (c == '\t') return os << "\\t";
110     return os << c;
111   }
112 
113   const std::string str_;
114 };
115 
116 class JSONGraphNodeWriter {
117  public:
JSONGraphNodeWriter(std::ostream & os,Zone * zone,const Graph * graph,const SourcePositionTable * positions)118   JSONGraphNodeWriter(std::ostream& os, Zone* zone, const Graph* graph,
119                       const SourcePositionTable* positions)
120       : os_(os),
121         all_(zone, graph, false),
122         live_(zone, graph, true),
123         positions_(positions),
124         first_node_(true) {}
125 
Print()126   void Print() {
127     for (Node* const node : all_.reachable) PrintNode(node);
128     os_ << "\n";
129   }
130 
PrintNode(Node * node)131   void PrintNode(Node* node) {
132     if (first_node_) {
133       first_node_ = false;
134     } else {
135       os_ << ",\n";
136     }
137     std::ostringstream label, title, properties;
138     node->op()->PrintTo(label, Operator::PrintVerbosity::kSilent);
139     node->op()->PrintTo(title, Operator::PrintVerbosity::kVerbose);
140     node->op()->PrintPropsTo(properties);
141     os_ << "{\"id\":" << SafeId(node) << ",\"label\":\"" << JSONEscaped(label)
142         << "\""
143         << ",\"title\":\"" << JSONEscaped(title) << "\""
144         << ",\"live\": " << (live_.IsLive(node) ? "true" : "false")
145         << ",\"properties\":\"" << JSONEscaped(properties) << "\"";
146     IrOpcode::Value opcode = node->opcode();
147     if (IrOpcode::IsPhiOpcode(opcode)) {
148       os_ << ",\"rankInputs\":[0," << NodeProperties::FirstControlIndex(node)
149           << "]";
150       os_ << ",\"rankWithInput\":[" << NodeProperties::FirstControlIndex(node)
151           << "]";
152     } else if (opcode == IrOpcode::kIfTrue || opcode == IrOpcode::kIfFalse ||
153                opcode == IrOpcode::kLoop) {
154       os_ << ",\"rankInputs\":[" << NodeProperties::FirstControlIndex(node)
155           << "]";
156     }
157     if (opcode == IrOpcode::kBranch) {
158       os_ << ",\"rankInputs\":[0]";
159     }
160     SourcePosition position = positions_->GetSourcePosition(node);
161     if (position.IsKnown()) {
162       os_ << ",\"pos\":" << position.ScriptOffset();
163     }
164     os_ << ",\"opcode\":\"" << IrOpcode::Mnemonic(node->opcode()) << "\"";
165     os_ << ",\"control\":" << (NodeProperties::IsControl(node) ? "true"
166                                                                : "false");
167     os_ << ",\"opinfo\":\"" << node->op()->ValueInputCount() << " v "
168         << node->op()->EffectInputCount() << " eff "
169         << node->op()->ControlInputCount() << " ctrl in, "
170         << node->op()->ValueOutputCount() << " v "
171         << node->op()->EffectOutputCount() << " eff "
172         << node->op()->ControlOutputCount() << " ctrl out\"";
173     if (NodeProperties::IsTyped(node)) {
174       Type* type = NodeProperties::GetType(node);
175       std::ostringstream type_out;
176       type->PrintTo(type_out);
177       os_ << ",\"type\":\"" << JSONEscaped(type_out) << "\"";
178     }
179     os_ << "}";
180   }
181 
182  private:
183   std::ostream& os_;
184   AllNodes all_;
185   AllNodes live_;
186   const SourcePositionTable* positions_;
187   bool first_node_;
188 
189   DISALLOW_COPY_AND_ASSIGN(JSONGraphNodeWriter);
190 };
191 
192 
193 class JSONGraphEdgeWriter {
194  public:
JSONGraphEdgeWriter(std::ostream & os,Zone * zone,const Graph * graph)195   JSONGraphEdgeWriter(std::ostream& os, Zone* zone, const Graph* graph)
196       : os_(os), all_(zone, graph, false), first_edge_(true) {}
197 
Print()198   void Print() {
199     for (Node* const node : all_.reachable) PrintEdges(node);
200     os_ << "\n";
201   }
202 
PrintEdges(Node * node)203   void PrintEdges(Node* node) {
204     for (int i = 0; i < node->InputCount(); i++) {
205       Node* input = node->InputAt(i);
206       if (input == nullptr) continue;
207       PrintEdge(node, i, input);
208     }
209   }
210 
PrintEdge(Node * from,int index,Node * to)211   void PrintEdge(Node* from, int index, Node* to) {
212     if (first_edge_) {
213       first_edge_ = false;
214     } else {
215       os_ << ",\n";
216     }
217     const char* edge_type = nullptr;
218     if (index < NodeProperties::FirstValueIndex(from)) {
219       edge_type = "unknown";
220     } else if (index < NodeProperties::FirstContextIndex(from)) {
221       edge_type = "value";
222     } else if (index < NodeProperties::FirstFrameStateIndex(from)) {
223       edge_type = "context";
224     } else if (index < NodeProperties::FirstEffectIndex(from)) {
225       edge_type = "frame-state";
226     } else if (index < NodeProperties::FirstControlIndex(from)) {
227       edge_type = "effect";
228     } else {
229       edge_type = "control";
230     }
231     os_ << "{\"source\":" << SafeId(to) << ",\"target\":" << SafeId(from)
232         << ",\"index\":" << index << ",\"type\":\"" << edge_type << "\"}";
233   }
234 
235  private:
236   std::ostream& os_;
237   AllNodes all_;
238   bool first_edge_;
239 
240   DISALLOW_COPY_AND_ASSIGN(JSONGraphEdgeWriter);
241 };
242 
243 
operator <<(std::ostream & os,const AsJSON & ad)244 std::ostream& operator<<(std::ostream& os, const AsJSON& ad) {
245   AccountingAllocator allocator;
246   Zone tmp_zone(&allocator, ZONE_NAME);
247   os << "{\n\"nodes\":[";
248   JSONGraphNodeWriter(os, &tmp_zone, &ad.graph, ad.positions).Print();
249   os << "],\n\"edges\":[";
250   JSONGraphEdgeWriter(os, &tmp_zone, &ad.graph).Print();
251   os << "]}";
252   return os;
253 }
254 
255 
256 class GraphC1Visualizer {
257  public:
258   GraphC1Visualizer(std::ostream& os, Zone* zone);  // NOLINT
259 
260   void PrintCompilation(const CompilationInfo* info);
261   void PrintSchedule(const char* phase, const Schedule* schedule,
262                      const SourcePositionTable* positions,
263                      const InstructionSequence* instructions);
264   void PrintLiveRanges(const char* phase, const RegisterAllocationData* data);
zone() const265   Zone* zone() const { return zone_; }
266 
267  private:
268   void PrintIndent();
269   void PrintStringProperty(const char* name, const char* value);
270   void PrintLongProperty(const char* name, int64_t value);
271   void PrintIntProperty(const char* name, int value);
272   void PrintBlockProperty(const char* name, int rpo_number);
273   void PrintNodeId(Node* n);
274   void PrintNode(Node* n);
275   void PrintInputs(Node* n);
276   template <typename InputIterator>
277   void PrintInputs(InputIterator* i, int count, const char* prefix);
278   void PrintType(Node* node);
279 
280   void PrintLiveRange(const LiveRange* range, const char* type, int vreg);
281   void PrintLiveRangeChain(const TopLevelLiveRange* range, const char* type);
282 
283   class Tag final BASE_EMBEDDED {
284    public:
Tag(GraphC1Visualizer * visualizer,const char * name)285     Tag(GraphC1Visualizer* visualizer, const char* name) {
286       name_ = name;
287       visualizer_ = visualizer;
288       visualizer->PrintIndent();
289       visualizer_->os_ << "begin_" << name << "\n";
290       visualizer->indent_++;
291     }
292 
~Tag()293     ~Tag() {
294       visualizer_->indent_--;
295       visualizer_->PrintIndent();
296       visualizer_->os_ << "end_" << name_ << "\n";
297       DCHECK(visualizer_->indent_ >= 0);
298     }
299 
300    private:
301     GraphC1Visualizer* visualizer_;
302     const char* name_;
303   };
304 
305   std::ostream& os_;
306   int indent_;
307   Zone* zone_;
308 
309   DISALLOW_COPY_AND_ASSIGN(GraphC1Visualizer);
310 };
311 
312 
PrintIndent()313 void GraphC1Visualizer::PrintIndent() {
314   for (int i = 0; i < indent_; i++) {
315     os_ << "  ";
316   }
317 }
318 
319 
GraphC1Visualizer(std::ostream & os,Zone * zone)320 GraphC1Visualizer::GraphC1Visualizer(std::ostream& os, Zone* zone)
321     : os_(os), indent_(0), zone_(zone) {}
322 
323 
PrintStringProperty(const char * name,const char * value)324 void GraphC1Visualizer::PrintStringProperty(const char* name,
325                                             const char* value) {
326   PrintIndent();
327   os_ << name << " \"" << value << "\"\n";
328 }
329 
330 
PrintLongProperty(const char * name,int64_t value)331 void GraphC1Visualizer::PrintLongProperty(const char* name, int64_t value) {
332   PrintIndent();
333   os_ << name << " " << static_cast<int>(value / 1000) << "\n";
334 }
335 
336 
PrintBlockProperty(const char * name,int rpo_number)337 void GraphC1Visualizer::PrintBlockProperty(const char* name, int rpo_number) {
338   PrintIndent();
339   os_ << name << " \"B" << rpo_number << "\"\n";
340 }
341 
342 
PrintIntProperty(const char * name,int value)343 void GraphC1Visualizer::PrintIntProperty(const char* name, int value) {
344   PrintIndent();
345   os_ << name << " " << value << "\n";
346 }
347 
348 
PrintCompilation(const CompilationInfo * info)349 void GraphC1Visualizer::PrintCompilation(const CompilationInfo* info) {
350   Tag tag(this, "compilation");
351   std::unique_ptr<char[]> name = info->GetDebugName();
352   if (info->IsOptimizing()) {
353     PrintStringProperty("name", name.get());
354     PrintIndent();
355     os_ << "method \"" << name.get() << ":" << info->optimization_id()
356         << "\"\n";
357   } else {
358     PrintStringProperty("name", name.get());
359     PrintStringProperty("method", "stub");
360   }
361   PrintLongProperty("date",
362                     static_cast<int64_t>(base::OS::TimeCurrentMillis()));
363 }
364 
365 
PrintNodeId(Node * n)366 void GraphC1Visualizer::PrintNodeId(Node* n) { os_ << "n" << SafeId(n); }
367 
368 
PrintNode(Node * n)369 void GraphC1Visualizer::PrintNode(Node* n) {
370   PrintNodeId(n);
371   os_ << " " << *n->op() << " ";
372   PrintInputs(n);
373 }
374 
375 
376 template <typename InputIterator>
PrintInputs(InputIterator * i,int count,const char * prefix)377 void GraphC1Visualizer::PrintInputs(InputIterator* i, int count,
378                                     const char* prefix) {
379   if (count > 0) {
380     os_ << prefix;
381   }
382   while (count > 0) {
383     os_ << " ";
384     PrintNodeId(**i);
385     ++(*i);
386     count--;
387   }
388 }
389 
390 
PrintInputs(Node * node)391 void GraphC1Visualizer::PrintInputs(Node* node) {
392   auto i = node->inputs().begin();
393   PrintInputs(&i, node->op()->ValueInputCount(), " ");
394   PrintInputs(&i, OperatorProperties::GetContextInputCount(node->op()),
395               " Ctx:");
396   PrintInputs(&i, OperatorProperties::GetFrameStateInputCount(node->op()),
397               " FS:");
398   PrintInputs(&i, node->op()->EffectInputCount(), " Eff:");
399   PrintInputs(&i, node->op()->ControlInputCount(), " Ctrl:");
400 }
401 
402 
PrintType(Node * node)403 void GraphC1Visualizer::PrintType(Node* node) {
404   if (NodeProperties::IsTyped(node)) {
405     Type* type = NodeProperties::GetType(node);
406     os_ << " type:";
407     type->PrintTo(os_);
408   }
409 }
410 
411 
PrintSchedule(const char * phase,const Schedule * schedule,const SourcePositionTable * positions,const InstructionSequence * instructions)412 void GraphC1Visualizer::PrintSchedule(const char* phase,
413                                       const Schedule* schedule,
414                                       const SourcePositionTable* positions,
415                                       const InstructionSequence* instructions) {
416   Tag tag(this, "cfg");
417   PrintStringProperty("name", phase);
418   const BasicBlockVector* rpo = schedule->rpo_order();
419   for (size_t i = 0; i < rpo->size(); i++) {
420     BasicBlock* current = (*rpo)[i];
421     Tag block_tag(this, "block");
422     PrintBlockProperty("name", current->rpo_number());
423     PrintIntProperty("from_bci", -1);
424     PrintIntProperty("to_bci", -1);
425 
426     PrintIndent();
427     os_ << "predecessors";
428     for (BasicBlock* predecessor : current->predecessors()) {
429       os_ << " \"B" << predecessor->rpo_number() << "\"";
430     }
431     os_ << "\n";
432 
433     PrintIndent();
434     os_ << "successors";
435     for (BasicBlock* successor : current->successors()) {
436       os_ << " \"B" << successor->rpo_number() << "\"";
437     }
438     os_ << "\n";
439 
440     PrintIndent();
441     os_ << "xhandlers\n";
442 
443     PrintIndent();
444     os_ << "flags\n";
445 
446     if (current->dominator() != nullptr) {
447       PrintBlockProperty("dominator", current->dominator()->rpo_number());
448     }
449 
450     PrintIntProperty("loop_depth", current->loop_depth());
451 
452     const InstructionBlock* instruction_block =
453         instructions->InstructionBlockAt(
454             RpoNumber::FromInt(current->rpo_number()));
455     if (instruction_block->code_start() >= 0) {
456       int first_index = instruction_block->first_instruction_index();
457       int last_index = instruction_block->last_instruction_index();
458       PrintIntProperty(
459           "first_lir_id",
460           LifetimePosition::GapFromInstructionIndex(first_index).value());
461       PrintIntProperty("last_lir_id",
462                        LifetimePosition::InstructionFromInstructionIndex(
463                            last_index).value());
464     }
465 
466     {
467       Tag states_tag(this, "states");
468       Tag locals_tag(this, "locals");
469       int total = 0;
470       for (BasicBlock::const_iterator i = current->begin(); i != current->end();
471            ++i) {
472         if ((*i)->opcode() == IrOpcode::kPhi) total++;
473       }
474       PrintIntProperty("size", total);
475       PrintStringProperty("method", "None");
476       int index = 0;
477       for (BasicBlock::const_iterator i = current->begin(); i != current->end();
478            ++i) {
479         if ((*i)->opcode() != IrOpcode::kPhi) continue;
480         PrintIndent();
481         os_ << index << " ";
482         PrintNodeId(*i);
483         os_ << " [";
484         PrintInputs(*i);
485         os_ << "]\n";
486         index++;
487       }
488     }
489 
490     {
491       Tag HIR_tag(this, "HIR");
492       for (BasicBlock::const_iterator i = current->begin(); i != current->end();
493            ++i) {
494         Node* node = *i;
495         if (node->opcode() == IrOpcode::kPhi) continue;
496         int uses = node->UseCount();
497         PrintIndent();
498         os_ << "0 " << uses << " ";
499         PrintNode(node);
500         if (FLAG_trace_turbo_types) {
501           os_ << " ";
502           PrintType(node);
503         }
504         if (positions != nullptr) {
505           SourcePosition position = positions->GetSourcePosition(node);
506           if (position.IsKnown()) {
507             os_ << " pos:";
508             if (position.isInlined()) {
509               os_ << "inlining(" << position.InliningId() << "),";
510             }
511             os_ << position.ScriptOffset();
512           }
513         }
514         os_ << " <|@\n";
515       }
516 
517       BasicBlock::Control control = current->control();
518       if (control != BasicBlock::kNone) {
519         PrintIndent();
520         os_ << "0 0 ";
521         if (current->control_input() != nullptr) {
522           PrintNode(current->control_input());
523         } else {
524           os_ << -1 - current->rpo_number() << " Goto";
525         }
526         os_ << " ->";
527         for (BasicBlock* successor : current->successors()) {
528           os_ << " B" << successor->rpo_number();
529         }
530         if (FLAG_trace_turbo_types && current->control_input() != nullptr) {
531           os_ << " ";
532           PrintType(current->control_input());
533         }
534         os_ << " <|@\n";
535       }
536     }
537 
538     if (instructions != nullptr) {
539       Tag LIR_tag(this, "LIR");
540       for (int j = instruction_block->first_instruction_index();
541            j <= instruction_block->last_instruction_index(); j++) {
542         PrintIndent();
543         PrintableInstruction printable = {RegisterConfiguration::Turbofan(),
544                                           instructions->InstructionAt(j)};
545         os_ << j << " " << printable << " <|@\n";
546       }
547     }
548   }
549 }
550 
551 
PrintLiveRanges(const char * phase,const RegisterAllocationData * data)552 void GraphC1Visualizer::PrintLiveRanges(const char* phase,
553                                         const RegisterAllocationData* data) {
554   Tag tag(this, "intervals");
555   PrintStringProperty("name", phase);
556 
557   for (const TopLevelLiveRange* range : data->fixed_double_live_ranges()) {
558     PrintLiveRangeChain(range, "fixed");
559   }
560 
561   for (const TopLevelLiveRange* range : data->fixed_live_ranges()) {
562     PrintLiveRangeChain(range, "fixed");
563   }
564 
565   for (const TopLevelLiveRange* range : data->live_ranges()) {
566     PrintLiveRangeChain(range, "object");
567   }
568 }
569 
PrintLiveRangeChain(const TopLevelLiveRange * range,const char * type)570 void GraphC1Visualizer::PrintLiveRangeChain(const TopLevelLiveRange* range,
571                                             const char* type) {
572   if (range == nullptr || range->IsEmpty()) return;
573   int vreg = range->vreg();
574   for (const LiveRange* child = range; child != nullptr;
575        child = child->next()) {
576     PrintLiveRange(child, type, vreg);
577   }
578 }
579 
PrintLiveRange(const LiveRange * range,const char * type,int vreg)580 void GraphC1Visualizer::PrintLiveRange(const LiveRange* range, const char* type,
581                                        int vreg) {
582   if (range != nullptr && !range->IsEmpty()) {
583     PrintIndent();
584     os_ << vreg << ":" << range->relative_id() << " " << type;
585     if (range->HasRegisterAssigned()) {
586       AllocatedOperand op = AllocatedOperand::cast(range->GetAssignedOperand());
587       const auto config = RegisterConfiguration::Turbofan();
588       if (op.IsRegister()) {
589         os_ << " \"" << config->GetGeneralRegisterName(op.register_code())
590             << "\"";
591       } else if (op.IsDoubleRegister()) {
592         os_ << " \"" << config->GetDoubleRegisterName(op.register_code())
593             << "\"";
594       } else {
595         DCHECK(op.IsFloatRegister());
596         os_ << " \"" << config->GetFloatRegisterName(op.register_code())
597             << "\"";
598       }
599     } else if (range->spilled()) {
600       const TopLevelLiveRange* top = range->TopLevel();
601       int index = -1;
602       if (top->HasSpillRange()) {
603         index = kMaxInt;  // This hasn't been set yet.
604       } else if (top->GetSpillOperand()->IsConstant()) {
605         os_ << " \"const(nostack):"
606             << ConstantOperand::cast(top->GetSpillOperand())->virtual_register()
607             << "\"";
608       } else {
609         index = AllocatedOperand::cast(top->GetSpillOperand())->index();
610         if (IsFloatingPoint(top->representation())) {
611           os_ << " \"fp_stack:" << index << "\"";
612         } else {
613           os_ << " \"stack:" << index << "\"";
614         }
615       }
616     }
617 
618     os_ << " " << vreg;
619     for (const UseInterval* interval = range->first_interval();
620          interval != nullptr; interval = interval->next()) {
621       os_ << " [" << interval->start().value() << ", "
622           << interval->end().value() << "[";
623     }
624 
625     UsePosition* current_pos = range->first_pos();
626     while (current_pos != nullptr) {
627       if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) {
628         os_ << " " << current_pos->pos().value() << " M";
629       }
630       current_pos = current_pos->next();
631     }
632 
633     os_ << " \"\"\n";
634   }
635 }
636 
637 
operator <<(std::ostream & os,const AsC1VCompilation & ac)638 std::ostream& operator<<(std::ostream& os, const AsC1VCompilation& ac) {
639   AccountingAllocator allocator;
640   Zone tmp_zone(&allocator, ZONE_NAME);
641   GraphC1Visualizer(os, &tmp_zone).PrintCompilation(ac.info_);
642   return os;
643 }
644 
645 
operator <<(std::ostream & os,const AsC1V & ac)646 std::ostream& operator<<(std::ostream& os, const AsC1V& ac) {
647   AccountingAllocator allocator;
648   Zone tmp_zone(&allocator, ZONE_NAME);
649   GraphC1Visualizer(os, &tmp_zone)
650       .PrintSchedule(ac.phase_, ac.schedule_, ac.positions_, ac.instructions_);
651   return os;
652 }
653 
654 
operator <<(std::ostream & os,const AsC1VRegisterAllocationData & ac)655 std::ostream& operator<<(std::ostream& os,
656                          const AsC1VRegisterAllocationData& ac) {
657   AccountingAllocator allocator;
658   Zone tmp_zone(&allocator, ZONE_NAME);
659   GraphC1Visualizer(os, &tmp_zone).PrintLiveRanges(ac.phase_, ac.data_);
660   return os;
661 }
662 
663 const int kUnvisited = 0;
664 const int kOnStack = 1;
665 const int kVisited = 2;
666 
operator <<(std::ostream & os,const AsRPO & ar)667 std::ostream& operator<<(std::ostream& os, const AsRPO& ar) {
668   AccountingAllocator allocator;
669   Zone local_zone(&allocator, ZONE_NAME);
670 
671   // Do a post-order depth-first search on the RPO graph. For every node,
672   // print:
673   //
674   //   - the node id
675   //   - the operator mnemonic
676   //   - in square brackets its parameter (if present)
677   //   - in parentheses the list of argument ids and their mnemonics
678   //   - the node type (if it is typed)
679 
680   // Post-order guarantees that all inputs of a node will be printed before
681   // the node itself, if there are no cycles. Any cycles are broken
682   // arbitrarily.
683 
684   ZoneVector<byte> state(ar.graph.NodeCount(), kUnvisited, &local_zone);
685   ZoneStack<Node*> stack(&local_zone);
686 
687   stack.push(ar.graph.end());
688   state[ar.graph.end()->id()] = kOnStack;
689   while (!stack.empty()) {
690     Node* n = stack.top();
691     bool pop = true;
692     for (Node* const i : n->inputs()) {
693       if (state[i->id()] == kUnvisited) {
694         state[i->id()] = kOnStack;
695         stack.push(i);
696         pop = false;
697         break;
698       }
699     }
700     if (pop) {
701       state[n->id()] = kVisited;
702       stack.pop();
703       os << "#" << n->id() << ":" << *n->op() << "(";
704       // Print the inputs.
705       int j = 0;
706       for (Node* const i : n->inputs()) {
707         if (j++ > 0) os << ", ";
708         os << "#" << SafeId(i) << ":" << SafeMnemonic(i);
709       }
710       os << ")";
711       // Print the node type, if any.
712       if (NodeProperties::IsTyped(n)) {
713         os << "  [Type: ";
714         NodeProperties::GetType(n)->PrintTo(os);
715         os << "]";
716       }
717       os << std::endl;
718     }
719   }
720   return os;
721 }
722 }  // namespace compiler
723 }  // namespace internal
724 }  // namespace v8
725