LCOV - code coverage report
Current view: top level - src/compiler - graph-visualizer.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 542 647 83.8 %
Date: 2019-03-21 Functions: 42 57 73.7 %

          Line data    Source code
       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/compiler/all-nodes.h"
      12             : #include "src/compiler/backend/register-allocator.h"
      13             : #include "src/compiler/compiler-source-position-table.h"
      14             : #include "src/compiler/graph.h"
      15             : #include "src/compiler/node-origin-table.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/schedule.h"
      22             : #include "src/compiler/scheduler.h"
      23             : #include "src/interpreter/bytecodes.h"
      24             : #include "src/objects/script-inl.h"
      25             : #include "src/objects/shared-function-info.h"
      26             : #include "src/optimized-compilation-info.h"
      27             : #include "src/ostreams.h"
      28             : #include "src/source-position.h"
      29             : #include "src/vector.h"
      30             : 
      31             : namespace v8 {
      32             : namespace internal {
      33             : namespace compiler {
      34             : 
      35          25 : const char* get_cached_trace_turbo_filename(OptimizedCompilationInfo* info) {
      36          25 :   if (!info->trace_turbo_filename()) {
      37             :     info->set_trace_turbo_filename(
      38           2 :         GetVisualizerLogFileName(info, FLAG_trace_turbo_path, nullptr, "json"));
      39             :   }
      40          25 :   return info->trace_turbo_filename();
      41             : }
      42             : 
      43          25 : TurboJsonFile::TurboJsonFile(OptimizedCompilationInfo* info,
      44             :                              std::ios_base::openmode mode)
      45          25 :     : std::ofstream(get_cached_trace_turbo_filename(info), mode) {}
      46             : 
      47          50 : TurboJsonFile::~TurboJsonFile() { flush(); }
      48             : 
      49           5 : TurboCfgFile::TurboCfgFile(Isolate* isolate)
      50          10 :     : std::ofstream(Isolate::GetTurboCfgFileName(isolate).c_str(),
      51          10 :                     std::ios_base::app) {}
      52             : 
      53          10 : TurboCfgFile::~TurboCfgFile() { flush(); }
      54             : 
      55           0 : std::ostream& operator<<(std::ostream& out,
      56             :                          const SourcePositionAsJSON& asJSON) {
      57         567 :   asJSON.sp.PrintJson(out);
      58           0 :   return out;
      59             : }
      60             : 
      61           0 : std::ostream& operator<<(std::ostream& out, const NodeOriginAsJSON& asJSON) {
      62         324 :   asJSON.no.PrintJson(out);
      63           0 :   return out;
      64             : }
      65             : 
      66        2375 : class JSONEscaped {
      67             :  public:
      68             :   explicit JSONEscaped(const std::ostringstream& os) : str_(os.str()) {}
      69             : 
      70             :   friend std::ostream& operator<<(std::ostream& os, const JSONEscaped& e) {
      71       65799 :     for (char c : e.str_) PipeCharacter(os, c);
      72             :     return os;
      73             :   }
      74             : 
      75             :  private:
      76       63424 :   static std::ostream& PipeCharacter(std::ostream& os, char c) {
      77       63424 :     if (c == '"') return os << "\\\"";
      78       63424 :     if (c == '\\') return os << "\\\\";
      79       63424 :     if (c == '\b') return os << "\\b";
      80       63424 :     if (c == '\f') return os << "\\f";
      81       63424 :     if (c == '\n') return os << "\\n";
      82       63424 :     if (c == '\r') return os << "\\r";
      83       63424 :     if (c == '\t') return os << "\\t";
      84       63424 :     return os << c;
      85             :   }
      86             : 
      87             :   const std::string str_;
      88             : };
      89             : 
      90           2 : void JsonPrintFunctionSource(std::ostream& os, int source_id,
      91             :                              std::unique_ptr<char[]> function_name,
      92             :                              Handle<Script> script, Isolate* isolate,
      93             :                              Handle<SharedFunctionInfo> shared, bool with_key) {
      94           3 :   if (with_key) os << "\"" << source_id << "\" : ";
      95             : 
      96           2 :   os << "{ ";
      97           2 :   os << "\"sourceId\": " << source_id;
      98           2 :   os << ", \"functionName\": \"" << function_name.get() << "\" ";
      99             : 
     100             :   int start = 0;
     101             :   int end = 0;
     102           6 :   if (!script.is_null() && !script->IsUndefined(isolate) && !shared.is_null()) {
     103             :     Object source_name = script->name();
     104           2 :     os << ", \"sourceName\": \"";
     105           2 :     if (source_name->IsString()) {
     106           4 :       std::ostringstream escaped_name;
     107           6 :       escaped_name << String::cast(source_name)->ToCString().get();
     108           2 :       os << JSONEscaped(escaped_name);
     109             :     }
     110           2 :     os << "\"";
     111             :     {
     112             :       DisallowHeapAllocation no_allocation;
     113           2 :       start = shared->StartPosition();
     114           2 :       end = shared->EndPosition();
     115           2 :       os << ", \"sourceText\": \"";
     116           2 :       int len = shared->EndPosition() - start;
     117             :       SubStringRange source(String::cast(script->source()), no_allocation,
     118             :                             start, len);
     119          62 :       for (const auto& c : source) {
     120          60 :         os << AsEscapedUC16ForJSON(c);
     121             :       }
     122           2 :       os << "\"";
     123             :     }
     124             :   } else {
     125           0 :     os << ", \"sourceName\": \"\"";
     126           0 :     os << ", \"sourceText\": \"\"";
     127             :   }
     128           2 :   os << ", \"startPosition\": " << start;
     129           2 :   os << ", \"endPosition\": " << end;
     130           2 :   os << "}";
     131           2 : }
     132             : 
     133          10 : int SourceIdAssigner::GetIdFor(Handle<SharedFunctionInfo> shared) {
     134          20 :   for (unsigned i = 0; i < printed_.size(); i++) {
     135           5 :     if (printed_.at(i).is_identical_to(shared)) {
     136          10 :       source_ids_.push_back(i);
     137           5 :       return i;
     138             :     }
     139             :   }
     140           5 :   const int source_id = static_cast<int>(printed_.size());
     141           5 :   printed_.push_back(shared);
     142           5 :   source_ids_.push_back(source_id);
     143           5 :   return source_id;
     144             : }
     145             : 
     146             : namespace {
     147             : 
     148           0 : void JsonPrintInlinedFunctionInfo(
     149             :     std::ostream& os, int source_id, int inlining_id,
     150             :     const OptimizedCompilationInfo::InlinedFunctionHolder& h) {
     151           0 :   os << "\"" << inlining_id << "\" : ";
     152           0 :   os << "{ \"inliningId\" : " << inlining_id;
     153           0 :   os << ", \"sourceId\" : " << source_id;
     154           0 :   const SourcePosition position = h.position.position;
     155           0 :   if (position.IsKnown()) {
     156             :     os << ", \"inliningPosition\" : " << AsJSON(position);
     157             :   }
     158           0 :   os << "}";
     159           0 : }
     160             : 
     161             : }  // namespace
     162             : 
     163           1 : void JsonPrintAllSourceWithPositions(std::ostream& os,
     164             :                                      OptimizedCompilationInfo* info,
     165             :                                      Isolate* isolate) {
     166             :   AllowDeferredHandleDereference allow_deference_for_print_code;
     167           1 :   os << "\"sources\" : {";
     168             :   Handle<Script> script =
     169           1 :       (info->shared_info().is_null() ||
     170           2 :        info->shared_info()->script() == Object())
     171             :           ? Handle<Script>()
     172           3 :           : handle(Script::cast(info->shared_info()->script()), isolate);
     173           3 :   JsonPrintFunctionSource(os, -1,
     174             :                           info->shared_info().is_null()
     175           0 :                               ? std::unique_ptr<char[]>(new char[1]{0})
     176           2 :                               : info->shared_info()->DebugName()->ToCString(),
     177           1 :                           script, isolate, info->shared_info(), true);
     178             :   const auto& inlined = info->inlined_functions();
     179           2 :   SourceIdAssigner id_assigner(info->inlined_functions().size());
     180           2 :   for (unsigned id = 0; id < inlined.size(); id++) {
     181           0 :     os << ", ";
     182           0 :     Handle<SharedFunctionInfo> shared = inlined[id].shared_info;
     183           0 :     const int source_id = id_assigner.GetIdFor(shared);
     184           0 :     JsonPrintFunctionSource(os, source_id, shared->DebugName()->ToCString(),
     185             :                             handle(Script::cast(shared->script()), isolate),
     186           0 :                             isolate, shared, true);
     187             :   }
     188           1 :   os << "}, ";
     189           1 :   os << "\"inlinings\" : {";
     190             :   bool need_comma = false;
     191           2 :   for (unsigned id = 0; id < inlined.size(); id++) {
     192           0 :     if (need_comma) os << ", ";
     193             :     const int source_id = id_assigner.GetIdAt(id);
     194           0 :     JsonPrintInlinedFunctionInfo(os, source_id, id, inlined[id]);
     195             :     need_comma = true;
     196             :   }
     197           1 :   os << "}";
     198           1 : }
     199             : 
     200           1 : std::unique_ptr<char[]> GetVisualizerLogFileName(OptimizedCompilationInfo* info,
     201             :                                                  const char* optional_base_dir,
     202             :                                                  const char* phase,
     203             :                                                  const char* suffix) {
     204             :   EmbeddedVector<char, 256> filename(0);
     205           1 :   std::unique_ptr<char[]> debug_name = info->GetDebugName();
     206           1 :   int optimization_id = info->IsOptimizing() ? info->optimization_id() : 0;
     207           1 :   if (strlen(debug_name.get()) > 0) {
     208           1 :     SNPrintF(filename, "turbo-%s-%i", debug_name.get(), optimization_id);
     209           0 :   } else if (info->has_shared_info()) {
     210           0 :     SNPrintF(filename, "turbo-%p-%i",
     211             :              reinterpret_cast<void*>(info->shared_info()->address()),
     212           0 :              optimization_id);
     213             :   } else {
     214           0 :     SNPrintF(filename, "turbo-none-%i", optimization_id);
     215             :   }
     216             :   EmbeddedVector<char, 256> source_file(0);
     217             :   bool source_available = false;
     218           2 :   if (FLAG_trace_file_names && info->has_shared_info() &&
     219           1 :       info->shared_info()->script()->IsScript()) {
     220           0 :     Object source_name = Script::cast(info->shared_info()->script())->name();
     221           0 :     if (source_name->IsString()) {
     222           0 :       String str = String::cast(source_name);
     223           0 :       if (str->length() > 0) {
     224           0 :         SNPrintF(source_file, "%s", str->ToCString().get());
     225           0 :         std::replace(source_file.start(),
     226             :                      source_file.start() + source_file.length(), '/', '_');
     227             :         source_available = true;
     228             :       }
     229             :     }
     230             :   }
     231           1 :   std::replace(filename.start(), filename.start() + filename.length(), ' ',
     232             :                '_');
     233             : 
     234             :   EmbeddedVector<char, 256> base_dir;
     235           1 :   if (optional_base_dir != nullptr) {
     236           1 :     SNPrintF(base_dir, "%s%c", optional_base_dir,
     237           2 :              base::OS::DirectorySeparator());
     238             :   } else {
     239           0 :     base_dir[0] = '\0';
     240             :   }
     241             : 
     242             :   EmbeddedVector<char, 256> full_filename;
     243           1 :   if (phase == nullptr && !source_available) {
     244             :     SNPrintF(full_filename, "%s%s.%s", base_dir.start(), filename.start(),
     245           1 :              suffix);
     246           0 :   } else if (phase != nullptr && !source_available) {
     247             :     SNPrintF(full_filename, "%s%s-%s.%s", base_dir.start(), filename.start(),
     248           0 :              phase, suffix);
     249           0 :   } else if (phase == nullptr && source_available) {
     250             :     SNPrintF(full_filename, "%s%s_%s.%s", base_dir.start(), filename.start(),
     251           0 :              source_file.start(), suffix);
     252             :   } else {
     253             :     SNPrintF(full_filename, "%s%s_%s-%s.%s", base_dir.start(), filename.start(),
     254           0 :              source_file.start(), phase, suffix);
     255             :   }
     256             : 
     257           1 :   char* buffer = new char[full_filename.length() + 1];
     258           1 :   memcpy(buffer, full_filename.start(), full_filename.length());
     259           1 :   buffer[full_filename.length()] = '\0';
     260           1 :   return std::unique_ptr<char[]>(buffer);
     261             : }
     262             : 
     263             : 
     264        8049 : static int SafeId(Node* node) { return node == nullptr ? -1 : node->id(); }
     265             : static const char* SafeMnemonic(Node* node) {
     266        1157 :   return node == nullptr ? "null" : node->op()->mnemonic();
     267             : }
     268             : 
     269          42 : class JSONGraphNodeWriter {
     270             :  public:
     271          42 :   JSONGraphNodeWriter(std::ostream& os, Zone* zone, const Graph* graph,
     272             :                       const SourcePositionTable* positions,
     273             :                       const NodeOriginTable* origins)
     274             :       : os_(os),
     275             :         all_(zone, graph, false),
     276             :         live_(zone, graph, true),
     277             :         positions_(positions),
     278             :         origins_(origins),
     279          42 :         first_node_(true) {}
     280             : 
     281          42 :   void Print() {
     282         779 :     for (Node* const node : all_.reachable) PrintNode(node);
     283          42 :     os_ << "\n";
     284          42 :   }
     285             : 
     286         737 :   void PrintNode(Node* node) {
     287         737 :     if (first_node_) {
     288          42 :       first_node_ = false;
     289             :     } else {
     290         695 :       os_ << ",\n";
     291             :     }
     292        1474 :     std::ostringstream label, title, properties;
     293             :     node->op()->PrintTo(label, Operator::PrintVerbosity::kSilent);
     294             :     node->op()->PrintTo(title, Operator::PrintVerbosity::kVerbose);
     295         737 :     node->op()->PrintPropsTo(properties);
     296        2211 :     os_ << "{\"id\":" << SafeId(node) << ",\"label\":\"" << JSONEscaped(label)
     297             :         << "\""
     298         737 :         << ",\"title\":\"" << JSONEscaped(title) << "\""
     299        1474 :         << ",\"live\": " << (live_.IsLive(node) ? "true" : "false")
     300        1474 :         << ",\"properties\":\"" << JSONEscaped(properties) << "\"";
     301             :     IrOpcode::Value opcode = node->opcode();
     302         737 :     if (IrOpcode::IsPhiOpcode(opcode)) {
     303          58 :       os_ << ",\"rankInputs\":[0," << NodeProperties::FirstControlIndex(node)
     304          29 :           << "]";
     305          58 :       os_ << ",\"rankWithInput\":[" << NodeProperties::FirstControlIndex(node)
     306          29 :           << "]";
     307        1416 :     } else if (opcode == IrOpcode::kIfTrue || opcode == IrOpcode::kIfFalse ||
     308         708 :                opcode == IrOpcode::kLoop) {
     309          68 :       os_ << ",\"rankInputs\":[" << NodeProperties::FirstControlIndex(node)
     310          34 :           << "]";
     311             :     }
     312         737 :     if (opcode == IrOpcode::kBranch) {
     313          17 :       os_ << ",\"rankInputs\":[0]";
     314             :     }
     315         737 :     if (positions_ != nullptr) {
     316         737 :       SourcePosition position = positions_->GetSourcePosition(node);
     317         737 :       if (position.IsKnown()) {
     318         567 :         os_ << ", \"sourcePosition\" : " << AsJSON(position);
     319             :       }
     320             :     }
     321         737 :     if (origins_) {
     322         737 :       NodeOrigin origin = origins_->GetNodeOrigin(node);
     323         737 :       if (origin.IsKnown()) {
     324         324 :         os_ << ", \"origin\" : " << AsJSON(origin);
     325             :       }
     326             :     }
     327        1474 :     os_ << ",\"opcode\":\"" << IrOpcode::Mnemonic(node->opcode()) << "\"";
     328         737 :     os_ << ",\"control\":" << (NodeProperties::IsControl(node) ? "true"
     329        1474 :                                                                : "false");
     330        1474 :     os_ << ",\"opinfo\":\"" << node->op()->ValueInputCount() << " v "
     331         737 :         << node->op()->EffectInputCount() << " eff "
     332         737 :         << node->op()->ControlInputCount() << " ctrl in, "
     333         737 :         << node->op()->ValueOutputCount() << " v "
     334         737 :         << node->op()->EffectOutputCount() << " eff "
     335         737 :         << node->op()->ControlOutputCount() << " ctrl out\"";
     336         737 :     if (NodeProperties::IsTyped(node)) {
     337         162 :       Type type = NodeProperties::GetType(node);
     338         324 :       std::ostringstream type_out;
     339         162 :       type.PrintTo(type_out);
     340         486 :       os_ << ",\"type\":\"" << JSONEscaped(type_out) << "\"";
     341             :     }
     342         737 :     os_ << "}";
     343         737 :   }
     344             : 
     345             :  private:
     346             :   std::ostream& os_;
     347             :   AllNodes all_;
     348             :   AllNodes live_;
     349             :   const SourcePositionTable* positions_;
     350             :   const NodeOriginTable* origins_;
     351             :   bool first_node_;
     352             : 
     353             :   DISALLOW_COPY_AND_ASSIGN(JSONGraphNodeWriter);
     354             : };
     355             : 
     356             : 
     357          42 : class JSONGraphEdgeWriter {
     358             :  public:
     359             :   JSONGraphEdgeWriter(std::ostream& os, Zone* zone, const Graph* graph)
     360          42 :       : os_(os), all_(zone, graph, false), first_edge_(true) {}
     361             : 
     362          42 :   void Print() {
     363         779 :     for (Node* const node : all_.reachable) PrintEdges(node);
     364          42 :     os_ << "\n";
     365          42 :   }
     366             : 
     367         737 :   void PrintEdges(Node* node) {
     368        3319 :     for (int i = 0; i < node->InputCount(); i++) {
     369             :       Node* input = node->InputAt(i);
     370        1291 :       if (input == nullptr) continue;
     371        1271 :       PrintEdge(node, i, input);
     372             :     }
     373         737 :   }
     374             : 
     375        1271 :   void PrintEdge(Node* from, int index, Node* to) {
     376        1271 :     if (first_edge_) {
     377          42 :       first_edge_ = false;
     378             :     } else {
     379        1229 :       os_ << ",\n";
     380             :     }
     381             :     const char* edge_type = nullptr;
     382        1271 :     if (index < NodeProperties::FirstValueIndex(from)) {
     383             :       edge_type = "unknown";
     384        1271 :     } else if (index < NodeProperties::FirstContextIndex(from)) {
     385             :       edge_type = "value";
     386         498 :     } else if (index < NodeProperties::FirstFrameStateIndex(from)) {
     387             :       edge_type = "context";
     388         489 :     } else if (index < NodeProperties::FirstEffectIndex(from)) {
     389             :       edge_type = "frame-state";
     390         445 :     } else if (index < NodeProperties::FirstControlIndex(from)) {
     391             :       edge_type = "effect";
     392             :     } else {
     393             :       edge_type = "control";
     394             :     }
     395        3813 :     os_ << "{\"source\":" << SafeId(to) << ",\"target\":" << SafeId(from)
     396        2542 :         << ",\"index\":" << index << ",\"type\":\"" << edge_type << "\"}";
     397        1271 :   }
     398             : 
     399             :  private:
     400             :   std::ostream& os_;
     401             :   AllNodes all_;
     402             :   bool first_edge_;
     403             : 
     404             :   DISALLOW_COPY_AND_ASSIGN(JSONGraphEdgeWriter);
     405             : };
     406             : 
     407          42 : std::ostream& operator<<(std::ostream& os, const GraphAsJSON& ad) {
     408          84 :   AccountingAllocator allocator;
     409          84 :   Zone tmp_zone(&allocator, ZONE_NAME);
     410          42 :   os << "{\n\"nodes\":[";
     411          42 :   JSONGraphNodeWriter(os, &tmp_zone, &ad.graph, ad.positions, ad.origins)
     412          84 :       .Print();
     413          42 :   os << "],\n\"edges\":[";
     414         126 :   JSONGraphEdgeWriter(os, &tmp_zone, &ad.graph).Print();
     415          42 :   os << "]}";
     416          42 :   return os;
     417             : }
     418             : 
     419             : 
     420             : class GraphC1Visualizer {
     421             :  public:
     422             :   GraphC1Visualizer(std::ostream& os, Zone* zone);  // NOLINT
     423             : 
     424             :   void PrintCompilation(const OptimizedCompilationInfo* info);
     425             :   void PrintSchedule(const char* phase, const Schedule* schedule,
     426             :                      const SourcePositionTable* positions,
     427             :                      const InstructionSequence* instructions);
     428             :   void PrintLiveRanges(const char* phase, const RegisterAllocationData* data);
     429             :   Zone* zone() const { return zone_; }
     430             : 
     431             :  private:
     432             :   void PrintIndent();
     433             :   void PrintStringProperty(const char* name, const char* value);
     434             :   void PrintLongProperty(const char* name, int64_t value);
     435             :   void PrintIntProperty(const char* name, int value);
     436             :   void PrintBlockProperty(const char* name, int rpo_number);
     437             :   void PrintNodeId(Node* n);
     438             :   void PrintNode(Node* n);
     439             :   void PrintInputs(Node* n);
     440             :   template <typename InputIterator>
     441             :   void PrintInputs(InputIterator* i, int count, const char* prefix);
     442             :   void PrintType(Node* node);
     443             : 
     444             :   void PrintLiveRange(const LiveRange* range, const char* type, int vreg);
     445             :   void PrintLiveRangeChain(const TopLevelLiveRange* range, const char* type);
     446             : 
     447             :   class Tag final {
     448             :    public:
     449          55 :     Tag(GraphC1Visualizer* visualizer, const char* name) {
     450          55 :       name_ = name;
     451          55 :       visualizer_ = visualizer;
     452             :       visualizer->PrintIndent();
     453         110 :       visualizer_->os_ << "begin_" << name << "\n";
     454          55 :       visualizer->indent_++;
     455          55 :     }
     456             : 
     457         110 :     ~Tag() {
     458          55 :       visualizer_->indent_--;
     459          55 :       visualizer_->PrintIndent();
     460         110 :       visualizer_->os_ << "end_" << name_ << "\n";
     461             :       DCHECK_LE(0, visualizer_->indent_);
     462          55 :     }
     463             : 
     464             :    private:
     465             :     GraphC1Visualizer* visualizer_;
     466             :     const char* name_;
     467             :   };
     468             : 
     469             :   std::ostream& os_;
     470             :   int indent_;
     471             :   Zone* zone_;
     472             : 
     473             :   DISALLOW_COPY_AND_ASSIGN(GraphC1Visualizer);
     474             : };
     475             : 
     476             : 
     477           0 : void GraphC1Visualizer::PrintIndent() {
     478        2683 :   for (int i = 0; i < indent_; i++) {
     479        1063 :     os_ << "  ";
     480             :   }
     481           0 : }
     482             : 
     483             : 
     484           0 : GraphC1Visualizer::GraphC1Visualizer(std::ostream& os, Zone* zone)
     485           5 :     : os_(os), indent_(0), zone_(zone) {}
     486             : 
     487             : 
     488          15 : void GraphC1Visualizer::PrintStringProperty(const char* name,
     489             :                                             const char* value) {
     490             :   PrintIndent();
     491          30 :   os_ << name << " \"" << value << "\"\n";
     492          15 : }
     493             : 
     494             : 
     495           1 : void GraphC1Visualizer::PrintLongProperty(const char* name, int64_t value) {
     496             :   PrintIndent();
     497           2 :   os_ << name << " " << static_cast<int>(value / 1000) << "\n";
     498           1 : }
     499             : 
     500             : 
     501          19 : void GraphC1Visualizer::PrintBlockProperty(const char* name, int rpo_number) {
     502             :   PrintIndent();
     503          38 :   os_ << name << " \"B" << rpo_number << "\"\n";
     504          19 : }
     505             : 
     506             : 
     507          60 : void GraphC1Visualizer::PrintIntProperty(const char* name, int value) {
     508             :   PrintIndent();
     509         120 :   os_ << name << " " << value << "\n";
     510          60 : }
     511             : 
     512           1 : void GraphC1Visualizer::PrintCompilation(const OptimizedCompilationInfo* info) {
     513           2 :   Tag tag(this, "compilation");
     514           1 :   std::unique_ptr<char[]> name = info->GetDebugName();
     515           1 :   if (info->IsOptimizing()) {
     516           1 :     PrintStringProperty("name", name.get());
     517             :     PrintIndent();
     518           3 :     os_ << "method \"" << name.get() << ":" << info->optimization_id()
     519           1 :         << "\"\n";
     520             :   } else {
     521           0 :     PrintStringProperty("name", name.get());
     522           0 :     PrintStringProperty("method", "stub");
     523             :   }
     524           1 :   PrintLongProperty(
     525             :       "date",
     526           2 :       static_cast<int64_t>(V8::GetCurrentPlatform()->CurrentClockTimeMillis()));
     527           1 : }
     528             : 
     529             : 
     530         672 : void GraphC1Visualizer::PrintNodeId(Node* n) { os_ << "n" << SafeId(n); }
     531             : 
     532             : 
     533          77 : void GraphC1Visualizer::PrintNode(Node* n) {
     534          77 :   PrintNodeId(n);
     535         154 :   os_ << " " << *n->op() << " ";
     536          77 :   PrintInputs(n);
     537          77 : }
     538             : 
     539             : 
     540             : template <typename InputIterator>
     541         390 : void GraphC1Visualizer::PrintInputs(InputIterator* i, int count,
     542             :                                     const char* prefix) {
     543         390 :   if (count > 0) {
     544         101 :     os_ << prefix;
     545             :   }
     546         682 :   while (count > 0) {
     547         146 :     os_ << " ";
     548         146 :     PrintNodeId(**i);
     549             :     ++(*i);
     550         146 :     count--;
     551             :   }
     552         390 : }
     553             : 
     554             : 
     555          78 : void GraphC1Visualizer::PrintInputs(Node* node) {
     556          78 :   auto i = node->inputs().begin();
     557          78 :   PrintInputs(&i, node->op()->ValueInputCount(), " ");
     558             :   PrintInputs(&i, OperatorProperties::GetContextInputCount(node->op()),
     559          78 :               " Ctx:");
     560             :   PrintInputs(&i, OperatorProperties::GetFrameStateInputCount(node->op()),
     561          78 :               " FS:");
     562          78 :   PrintInputs(&i, node->op()->EffectInputCount(), " Eff:");
     563          78 :   PrintInputs(&i, node->op()->ControlInputCount(), " Ctrl:");
     564          78 : }
     565             : 
     566             : 
     567          77 : void GraphC1Visualizer::PrintType(Node* node) {
     568          77 :   if (NodeProperties::IsTyped(node)) {
     569          10 :     Type type = NodeProperties::GetType(node);
     570          20 :     os_ << " type:" << type;
     571             :   }
     572          77 : }
     573             : 
     574             : 
     575           1 : void GraphC1Visualizer::PrintSchedule(const char* phase,
     576             :                                       const Schedule* schedule,
     577             :                                       const SourcePositionTable* positions,
     578             :                                       const InstructionSequence* instructions) {
     579           2 :   Tag tag(this, "cfg");
     580           1 :   PrintStringProperty("name", phase);
     581             :   const BasicBlockVector* rpo = schedule->rpo_order();
     582          21 :   for (size_t i = 0; i < rpo->size(); i++) {
     583          10 :     BasicBlock* current = (*rpo)[i];
     584          20 :     Tag block_tag(this, "block");
     585          10 :     PrintBlockProperty("name", current->rpo_number());
     586          10 :     PrintIntProperty("from_bci", -1);
     587          10 :     PrintIntProperty("to_bci", -1);
     588             : 
     589             :     PrintIndent();
     590          10 :     os_ << "predecessors";
     591          22 :     for (BasicBlock* predecessor : current->predecessors()) {
     592          24 :       os_ << " \"B" << predecessor->rpo_number() << "\"";
     593             :     }
     594          10 :     os_ << "\n";
     595             : 
     596             :     PrintIndent();
     597          10 :     os_ << "successors";
     598          22 :     for (BasicBlock* successor : current->successors()) {
     599          24 :       os_ << " \"B" << successor->rpo_number() << "\"";
     600             :     }
     601          10 :     os_ << "\n";
     602             : 
     603             :     PrintIndent();
     604          10 :     os_ << "xhandlers\n";
     605             : 
     606             :     PrintIndent();
     607          10 :     os_ << "flags\n";
     608             : 
     609          10 :     if (current->dominator() != nullptr) {
     610           9 :       PrintBlockProperty("dominator", current->dominator()->rpo_number());
     611             :     }
     612             : 
     613          10 :     PrintIntProperty("loop_depth", current->loop_depth());
     614             : 
     615             :     const InstructionBlock* instruction_block =
     616             :         instructions->InstructionBlockAt(
     617          10 :             RpoNumber::FromInt(current->rpo_number()));
     618          10 :     if (instruction_block->code_start() >= 0) {
     619             :       int first_index = instruction_block->first_instruction_index();
     620             :       int last_index = instruction_block->last_instruction_index();
     621             :       PrintIntProperty(
     622             :           "first_lir_id",
     623          10 :           LifetimePosition::GapFromInstructionIndex(first_index).value());
     624             :       PrintIntProperty("last_lir_id",
     625             :                        LifetimePosition::InstructionFromInstructionIndex(
     626          10 :                            last_index).value());
     627             :     }
     628             : 
     629             :     {
     630          20 :       Tag states_tag(this, "states");
     631          20 :       Tag locals_tag(this, "locals");
     632             :       int total = 0;
     633          83 :       for (BasicBlock::const_iterator i = current->begin(); i != current->end();
     634             :            ++i) {
     635         146 :         if ((*i)->opcode() == IrOpcode::kPhi) total++;
     636             :       }
     637          10 :       PrintIntProperty("size", total);
     638          10 :       PrintStringProperty("method", "None");
     639             :       int index = 0;
     640          83 :       for (BasicBlock::const_iterator i = current->begin(); i != current->end();
     641             :            ++i) {
     642         146 :         if ((*i)->opcode() != IrOpcode::kPhi) continue;
     643             :         PrintIndent();
     644           1 :         os_ << index << " ";
     645           1 :         PrintNodeId(*i);
     646           1 :         os_ << " [";
     647           1 :         PrintInputs(*i);
     648           1 :         os_ << "]\n";
     649           1 :         index++;
     650             :       }
     651             :     }
     652             : 
     653             :     {
     654          20 :       Tag HIR_tag(this, "HIR");
     655          83 :       for (BasicBlock::const_iterator i = current->begin(); i != current->end();
     656             :            ++i) {
     657          73 :         Node* node = *i;
     658          73 :         if (node->opcode() == IrOpcode::kPhi) continue;
     659          72 :         int uses = node->UseCount();
     660             :         PrintIndent();
     661         144 :         os_ << "0 " << uses << " ";
     662          72 :         PrintNode(node);
     663          72 :         if (FLAG_trace_turbo_types) {
     664          72 :           os_ << " ";
     665          72 :           PrintType(node);
     666             :         }
     667          72 :         if (positions != nullptr) {
     668          72 :           SourcePosition position = positions->GetSourcePosition(node);
     669          72 :           if (position.IsKnown()) {
     670          51 :             os_ << " pos:";
     671          51 :             if (position.isInlined()) {
     672           0 :               os_ << "inlining(" << position.InliningId() << "),";
     673             :             }
     674          51 :             os_ << position.ScriptOffset();
     675             :           }
     676             :         }
     677          72 :         os_ << " <|@\n";
     678             :       }
     679             : 
     680             :       BasicBlock::Control control = current->control();
     681          10 :       if (control != BasicBlock::kNone) {
     682             :         PrintIndent();
     683           9 :         os_ << "0 0 ";
     684           9 :         if (current->control_input() != nullptr) {
     685           5 :           PrintNode(current->control_input());
     686             :         } else {
     687           4 :           os_ << -1 - current->rpo_number() << " Goto";
     688             :         }
     689           9 :         os_ << " ->";
     690          21 :         for (BasicBlock* successor : current->successors()) {
     691          24 :           os_ << " B" << successor->rpo_number();
     692             :         }
     693           9 :         if (FLAG_trace_turbo_types && current->control_input() != nullptr) {
     694           5 :           os_ << " ";
     695           5 :           PrintType(current->control_input());
     696             :         }
     697           9 :         os_ << " <|@\n";
     698             :       }
     699             :     }
     700             : 
     701          10 :     if (instructions != nullptr) {
     702          20 :       Tag LIR_tag(this, "LIR");
     703          92 :       for (int j = instruction_block->first_instruction_index();
     704             :            j <= instruction_block->last_instruction_index(); j++) {
     705             :         PrintIndent();
     706          82 :         os_ << j << " " << *instructions->InstructionAt(j) << " <|@\n";
     707             :       }
     708             :     }
     709             :   }
     710           1 : }
     711             : 
     712             : 
     713           3 : void GraphC1Visualizer::PrintLiveRanges(const char* phase,
     714             :                                         const RegisterAllocationData* data) {
     715           6 :   Tag tag(this, "intervals");
     716           3 :   PrintStringProperty("name", phase);
     717             : 
     718          51 :   for (const TopLevelLiveRange* range : data->fixed_double_live_ranges()) {
     719          48 :     PrintLiveRangeChain(range, "fixed");
     720             :   }
     721             : 
     722          51 :   for (const TopLevelLiveRange* range : data->fixed_live_ranges()) {
     723          48 :     PrintLiveRangeChain(range, "fixed");
     724             :   }
     725             : 
     726         177 :   for (const TopLevelLiveRange* range : data->live_ranges()) {
     727         174 :     PrintLiveRangeChain(range, "object");
     728             :   }
     729           3 : }
     730             : 
     731         270 : void GraphC1Visualizer::PrintLiveRangeChain(const TopLevelLiveRange* range,
     732             :                                             const char* type) {
     733         270 :   if (range == nullptr || range->IsEmpty()) return;
     734             :   int vreg = range->vreg();
     735         544 :   for (const LiveRange* child = range; child != nullptr;
     736             :        child = child->next()) {
     737         188 :     PrintLiveRange(child, type, vreg);
     738             :   }
     739             : }
     740             : 
     741         188 : void GraphC1Visualizer::PrintLiveRange(const LiveRange* range, const char* type,
     742             :                                        int vreg) {
     743         188 :   if (range != nullptr && !range->IsEmpty()) {
     744             :     PrintIndent();
     745         564 :     os_ << vreg << ":" << range->relative_id() << " " << type;
     746         188 :     if (range->HasRegisterAssigned()) {
     747         212 :       AllocatedOperand op = AllocatedOperand::cast(range->GetAssignedOperand());
     748         106 :       if (op.IsRegister()) {
     749         120 :         os_ << " \"" << Register::from_code(op.register_code()) << "\"";
     750          46 :       } else if (op.IsDoubleRegister()) {
     751          92 :         os_ << " \"" << DoubleRegister::from_code(op.register_code()) << "\"";
     752             :       } else {
     753             :         DCHECK(op.IsFloatRegister());
     754           0 :         os_ << " \"" << FloatRegister::from_code(op.register_code()) << "\"";
     755             :       }
     756          82 :     } else if (range->spilled()) {
     757             :       const TopLevelLiveRange* top = range->TopLevel();
     758             :       int index = -1;
     759          22 :       if (top->HasSpillRange()) {
     760             :         index = kMaxInt;  // This hasn't been set yet.
     761          18 :       } else if (top->GetSpillOperand()->IsConstant()) {
     762           9 :         os_ << " \"const(nostack):"
     763           9 :             << ConstantOperand::cast(top->GetSpillOperand())->virtual_register()
     764           9 :             << "\"";
     765             :       } else {
     766             :         index = AllocatedOperand::cast(top->GetSpillOperand())->index();
     767           9 :         if (IsFloatingPoint(top->representation())) {
     768           0 :           os_ << " \"fp_stack:" << index << "\"";
     769             :         } else {
     770          18 :           os_ << " \"stack:" << index << "\"";
     771             :         }
     772             :       }
     773             :     }
     774             : 
     775             :     // The toplevel range might be a splinter. Pre-resolve those here so that
     776             :     // they have a proper parent.
     777             :     const TopLevelLiveRange* parent = range->TopLevel();
     778         188 :     if (parent->IsSplinter()) parent = parent->splintered_from();
     779         564 :     os_ << " " << parent->vreg() << ":" << parent->relative_id();
     780             : 
     781             :     // TODO(herhut) Find something useful to print for the hint field
     782         188 :     if (range->get_bundle() != nullptr) {
     783          18 :       os_ << " B" << range->get_bundle()->id();
     784             :     } else {
     785         179 :       os_ << " unknown";
     786             :     }
     787             : 
     788         286 :     for (const UseInterval* interval = range->first_interval();
     789         474 :          interval != nullptr; interval = interval->next()) {
     790         572 :       os_ << " [" << interval->start().value() << ", "
     791         286 :           << interval->end().value() << "[";
     792             :     }
     793             : 
     794             :     UsePosition* current_pos = range->first_pos();
     795         698 :     while (current_pos != nullptr) {
     796         255 :       if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) {
     797         318 :         os_ << " " << current_pos->pos().value() << " M";
     798             :       }
     799             :       current_pos = current_pos->next();
     800             :     }
     801             : 
     802         188 :     os_ << " \"\"\n";
     803             :   }
     804         188 : }
     805             : 
     806             : 
     807           1 : std::ostream& operator<<(std::ostream& os, const AsC1VCompilation& ac) {
     808           2 :   AccountingAllocator allocator;
     809           2 :   Zone tmp_zone(&allocator, ZONE_NAME);
     810           2 :   GraphC1Visualizer(os, &tmp_zone).PrintCompilation(ac.info_);
     811           1 :   return os;
     812             : }
     813             : 
     814             : 
     815           1 : std::ostream& operator<<(std::ostream& os, const AsC1V& ac) {
     816           2 :   AccountingAllocator allocator;
     817           2 :   Zone tmp_zone(&allocator, ZONE_NAME);
     818             :   GraphC1Visualizer(os, &tmp_zone)
     819           2 :       .PrintSchedule(ac.phase_, ac.schedule_, ac.positions_, ac.instructions_);
     820           1 :   return os;
     821             : }
     822             : 
     823             : 
     824           3 : std::ostream& operator<<(std::ostream& os,
     825             :                          const AsC1VRegisterAllocationData& ac) {
     826           6 :   AccountingAllocator allocator;
     827           6 :   Zone tmp_zone(&allocator, ZONE_NAME);
     828           6 :   GraphC1Visualizer(os, &tmp_zone).PrintLiveRanges(ac.phase_, ac.data_);
     829           3 :   return os;
     830             : }
     831             : 
     832             : const int kUnvisited = 0;
     833             : const int kOnStack = 1;
     834             : const int kVisited = 2;
     835             : 
     836          17 : std::ostream& operator<<(std::ostream& os, const AsRPO& ar) {
     837          34 :   AccountingAllocator allocator;
     838          34 :   Zone local_zone(&allocator, ZONE_NAME);
     839             : 
     840             :   // Do a post-order depth-first search on the RPO graph. For every node,
     841             :   // print:
     842             :   //
     843             :   //   - the node id
     844             :   //   - the operator mnemonic
     845             :   //   - in square brackets its parameter (if present)
     846             :   //   - in parentheses the list of argument ids and their mnemonics
     847             :   //   - the node type (if it is typed)
     848             : 
     849             :   // Post-order guarantees that all inputs of a node will be printed before
     850             :   // the node itself, if there are no cycles. Any cycles are broken
     851             :   // arbitrarily.
     852             : 
     853          17 :   ZoneVector<byte> state(ar.graph.NodeCount(), kUnvisited, &local_zone);
     854          17 :   ZoneStack<Node*> stack(&local_zone);
     855             : 
     856          34 :   stack.push(ar.graph.end());
     857          51 :   state[ar.graph.end()->id()] = kOnStack;
     858        1264 :   while (!stack.empty()) {
     859        1247 :     Node* n = stack.top();
     860             :     bool pop = true;
     861        5316 :     for (Node* const i : n->inputs()) {
     862        4684 :       if (state[i->id()] == kUnvisited) {
     863         615 :         state[i->id()] = kOnStack;
     864             :         stack.push(i);
     865             :         pop = false;
     866         615 :         break;
     867             :       }
     868             :     }
     869        1247 :     if (pop) {
     870        1264 :       state[n->id()] = kVisited;
     871             :       stack.pop();
     872         632 :       os << "#" << n->id() << ":" << *n->op() << "(";
     873             :       // Print the inputs.
     874             :       int j = 0;
     875        1789 :       for (Node* const i : n->inputs()) {
     876        1157 :         if (j++ > 0) os << ", ";
     877        2314 :         os << "#" << SafeId(i) << ":" << SafeMnemonic(i);
     878             :       }
     879         632 :       os << ")";
     880             :       // Print the node type, if any.
     881         632 :       if (NodeProperties::IsTyped(n)) {
     882         161 :         os << "  [Type: " << NodeProperties::GetType(n) << "]";
     883             :       }
     884             :       os << std::endl;
     885             :     }
     886             :   }
     887          17 :   return os;
     888             : }
     889             : 
     890             : namespace {
     891             : 
     892           0 : void PrintIndent(std::ostream& os, int indent) {
     893           0 :   os << "     ";
     894           0 :   for (int i = 0; i < indent; i++) {
     895           0 :     os << ". ";
     896             :   }
     897           0 : }
     898             : 
     899           0 : void PrintScheduledNode(std::ostream& os, int indent, Node* n) {
     900           0 :   PrintIndent(os, indent);
     901           0 :   os << "#" << n->id() << ":" << *n->op() << "(";
     902             :   // Print the inputs.
     903             :   int j = 0;
     904           0 :   for (Node* const i : n->inputs()) {
     905           0 :     if (j++ > 0) os << ", ";
     906           0 :     os << "#" << SafeId(i) << ":" << SafeMnemonic(i);
     907             :   }
     908           0 :   os << ")";
     909             :   // Print the node type, if any.
     910           0 :   if (NodeProperties::IsTyped(n)) {
     911           0 :     os << "  [Type: " << NodeProperties::GetType(n) << "]";
     912             :   }
     913           0 : }
     914             : 
     915           0 : void PrintScheduledGraph(std::ostream& os, const Schedule* schedule) {
     916             :   const BasicBlockVector* rpo = schedule->rpo_order();
     917           0 :   for (size_t i = 0; i < rpo->size(); i++) {
     918           0 :     BasicBlock* current = (*rpo)[i];
     919             :     int indent = current->loop_depth();
     920             : 
     921           0 :     os << "  + Block B" << current->rpo_number() << " (pred:";
     922           0 :     for (BasicBlock* predecessor : current->predecessors()) {
     923           0 :       os << " B" << predecessor->rpo_number();
     924             :     }
     925           0 :     if (current->IsLoopHeader()) {
     926           0 :       os << ", loop until B" << current->loop_end()->rpo_number();
     927           0 :     } else if (current->loop_header()) {
     928           0 :       os << ", in loop B" << current->loop_header()->rpo_number();
     929             :     }
     930             :     os << ")" << std::endl;
     931             : 
     932           0 :     for (BasicBlock::const_iterator i = current->begin(); i != current->end();
     933             :          ++i) {
     934           0 :       Node* node = *i;
     935           0 :       PrintScheduledNode(os, indent, node);
     936             :       os << std::endl;
     937             :     }
     938             : 
     939           0 :     if (current->SuccessorCount() > 0) {
     940           0 :       if (current->control_input() != nullptr) {
     941           0 :         PrintScheduledNode(os, indent, current->control_input());
     942             :       } else {
     943           0 :         PrintIndent(os, indent);
     944           0 :         os << "Goto";
     945             :       }
     946           0 :       os << " ->";
     947             : 
     948             :       bool isFirst = true;
     949           0 :       for (BasicBlock* successor : current->successors()) {
     950           0 :         if (isFirst) {
     951             :           isFirst = false;
     952             :         } else {
     953           0 :           os << ",";
     954             :         }
     955           0 :         os << " B" << successor->rpo_number();
     956             :       }
     957             :       os << std::endl;
     958             :     } else {
     959             :       DCHECK_NULL(current->control_input());
     960             :     }
     961             :   }
     962           0 : }
     963             : 
     964             : }  // namespace
     965             : 
     966           0 : std::ostream& operator<<(std::ostream& os, const AsScheduledGraph& scheduled) {
     967           0 :   PrintScheduledGraph(os, scheduled.schedule);
     968           0 :   return os;
     969             : }
     970             : 
     971         296 : std::ostream& operator<<(std::ostream& os, const InstructionOperandAsJSON& o) {
     972         296 :   const InstructionOperand* op = o.op_;
     973         296 :   const InstructionSequence* code = o.code_;
     974         296 :   os << "{";
     975         296 :   switch (op->kind()) {
     976             :     case InstructionOperand::UNALLOCATED: {
     977             :       const UnallocatedOperand* unalloc = UnallocatedOperand::cast(op);
     978          86 :       os << "\"type\": \"unallocated\", ";
     979          86 :       os << "\"text\": \"v" << unalloc->virtual_register() << "\"";
     980          86 :       if (unalloc->basic_policy() == UnallocatedOperand::FIXED_SLOT) {
     981           0 :         os << ",\"tooltip\": \"FIXED_SLOT: " << unalloc->fixed_slot_index()
     982           0 :            << "\"";
     983           0 :         break;
     984             :       }
     985          86 :       switch (unalloc->extended_policy()) {
     986             :         case UnallocatedOperand::NONE:
     987             :           break;
     988             :         case UnallocatedOperand::FIXED_REGISTER: {
     989             :           os << ",\"tooltip\": \"FIXED_REGISTER: "
     990           0 :              << Register::from_code(unalloc->fixed_register_index()) << "\"";
     991           0 :           break;
     992             :         }
     993             :         case UnallocatedOperand::FIXED_FP_REGISTER: {
     994             :           os << ",\"tooltip\": \"FIXED_FP_REGISTER: "
     995             :              << DoubleRegister::from_code(unalloc->fixed_register_index())
     996           0 :              << "\"";
     997           0 :           break;
     998             :         }
     999             :         case UnallocatedOperand::MUST_HAVE_REGISTER: {
    1000          29 :           os << ",\"tooltip\": \"MUST_HAVE_REGISTER\"";
    1001          29 :           break;
    1002             :         }
    1003             :         case UnallocatedOperand::MUST_HAVE_SLOT: {
    1004           7 :           os << ",\"tooltip\": \"MUST_HAVE_SLOT\"";
    1005           7 :           break;
    1006             :         }
    1007             :         case UnallocatedOperand::SAME_AS_FIRST_INPUT: {
    1008           7 :           os << ",\"tooltip\": \"SAME_AS_FIRST_INPUT\"";
    1009           7 :           break;
    1010             :         }
    1011             :         case UnallocatedOperand::REGISTER_OR_SLOT: {
    1012          29 :           os << ",\"tooltip\": \"REGISTER_OR_SLOT\"";
    1013          29 :           break;
    1014             :         }
    1015             :         case UnallocatedOperand::REGISTER_OR_SLOT_OR_CONSTANT: {
    1016           0 :           os << ",\"tooltip\": \"REGISTER_OR_SLOT_OR_CONSTANT\"";
    1017           0 :           break;
    1018             :         }
    1019             :       }
    1020             :       break;
    1021             :     }
    1022             :     case InstructionOperand::CONSTANT: {
    1023             :       int vreg = ConstantOperand::cast(op)->virtual_register();
    1024          22 :       os << "\"type\": \"constant\", ";
    1025          22 :       os << "\"text\": \"v" << vreg << "\",";
    1026          22 :       os << "\"tooltip\": \"";
    1027          44 :       std::stringstream tooltip;
    1028          22 :       tooltip << code->GetConstant(vreg);
    1029         351 :       for (const auto& c : tooltip.str()) {
    1030         658 :         os << AsEscapedUC16ForJSON(c);
    1031             :       }
    1032          22 :       os << "\"";
    1033             :       break;
    1034             :     }
    1035             :     case InstructionOperand::IMMEDIATE: {
    1036          72 :       os << "\"type\": \"immediate\", ";
    1037             :       const ImmediateOperand* imm = ImmediateOperand::cast(op);
    1038          72 :       switch (imm->type()) {
    1039             :         case ImmediateOperand::INLINE: {
    1040          20 :           os << "\"text\": \"#" << imm->inline_value() << "\"";
    1041          20 :           break;
    1042             :         }
    1043             :         case ImmediateOperand::INDEXED: {
    1044             :           int index = imm->indexed_value();
    1045          52 :           os << "\"text\": \"imm:" << index << "\",";
    1046          52 :           os << "\"tooltip\": \"";
    1047         104 :           std::stringstream tooltip;
    1048          52 :           tooltip << code->GetImmediate(imm);
    1049         892 :           for (const auto& c : tooltip.str()) {
    1050        1680 :             os << AsEscapedUC16ForJSON(c);
    1051             :           }
    1052          52 :           os << "\"";
    1053             :           break;
    1054             :         }
    1055             :       }
    1056             :       break;
    1057             :     }
    1058             :     case InstructionOperand::EXPLICIT:
    1059             :     case InstructionOperand::ALLOCATED: {
    1060             :       const LocationOperand* allocated = LocationOperand::cast(op);
    1061         116 :       os << "\"type\": ";
    1062         116 :       if (allocated->IsExplicit()) {
    1063           0 :         os << "\"explicit\", ";
    1064             :       } else {
    1065         116 :         os << "\"allocated\", ";
    1066             :       }
    1067         116 :       os << "\"text\": \"";
    1068         116 :       if (op->IsStackSlot()) {
    1069          25 :         os << "stack:" << allocated->index();
    1070          91 :       } else if (op->IsFPStackSlot()) {
    1071           0 :         os << "fp_stack:" << allocated->index();
    1072          91 :       } else if (op->IsRegister()) {
    1073          89 :         if (allocated->register_code() < Register::kNumRegisters) {
    1074             :           os << Register::from_code(allocated->register_code());
    1075             :         } else {
    1076           0 :           os << Register::GetSpecialRegisterName(allocated->register_code());
    1077             :         }
    1078           2 :       } else if (op->IsDoubleRegister()) {
    1079             :         os << DoubleRegister::from_code(allocated->register_code());
    1080           0 :       } else if (op->IsFloatRegister()) {
    1081             :         os << FloatRegister::from_code(allocated->register_code());
    1082             :       } else {
    1083             :         DCHECK(op->IsSimd128Register());
    1084             :         os << Simd128Register::from_code(allocated->register_code());
    1085             :       }
    1086         116 :       os << "\",";
    1087             :       os << "\"tooltip\": \""
    1088         232 :          << MachineReprToString(allocated->representation()) << "\"";
    1089         116 :       break;
    1090             :     }
    1091             :     case InstructionOperand::INVALID:
    1092           0 :       UNREACHABLE();
    1093             :   }
    1094         296 :   os << "}";
    1095         296 :   return os;
    1096             : }
    1097             : 
    1098          82 : std::ostream& operator<<(std::ostream& os, const InstructionAsJSON& i_json) {
    1099          82 :   const Instruction* instr = i_json.instr_;
    1100             : 
    1101          82 :   os << "{";
    1102         164 :   os << "\"id\": " << i_json.index_ << ",";
    1103         246 :   os << "\"opcode\": \"" << ArchOpcodeField::decode(instr->opcode()) << "\",";
    1104          82 :   os << "\"flags\": \"";
    1105         164 :   FlagsMode fm = FlagsModeField::decode(instr->opcode());
    1106          82 :   AddressingMode am = AddressingModeField::decode(instr->opcode());
    1107          82 :   if (am != kMode_None) {
    1108          36 :     os << " : " << AddressingModeField::decode(instr->opcode());
    1109             :   }
    1110          82 :   if (fm != kFlags_none) {
    1111          12 :     os << " && " << fm << " if "
    1112          36 :        << FlagsConditionField::decode(instr->opcode());
    1113             :   }
    1114          82 :   os << "\",";
    1115             : 
    1116          82 :   os << "\"gaps\": [";
    1117         164 :   for (int i = Instruction::FIRST_GAP_POSITION;
    1118         246 :        i <= Instruction::LAST_GAP_POSITION; i++) {
    1119         164 :     if (i != Instruction::FIRST_GAP_POSITION) os << ",";
    1120         164 :     os << "[";
    1121         164 :     const ParallelMove* pm = instr->parallel_moves()[i];
    1122         164 :     if (pm == nullptr) {
    1123         111 :       os << "]";
    1124         111 :       continue;
    1125             :     }
    1126             :     bool first = true;
    1127          97 :     for (MoveOperands* move : *pm) {
    1128          44 :       if (move->IsEliminated()) continue;
    1129          36 :       if (!first) os << ",";
    1130             :       first = false;
    1131         108 :       os << "[" << InstructionOperandAsJSON{&move->destination(), i_json.code_}
    1132         108 :          << "," << InstructionOperandAsJSON{&move->source(), i_json.code_}
    1133          36 :          << "]";
    1134             :     }
    1135          53 :     os << "]";
    1136             :   }
    1137          82 :   os << "],";
    1138             : 
    1139          82 :   os << "\"outputs\": [";
    1140             :   bool need_comma = false;
    1141         190 :   for (size_t i = 0; i < instr->OutputCount(); i++) {
    1142          54 :     if (need_comma) os << ",";
    1143             :     need_comma = true;
    1144          54 :     os << InstructionOperandAsJSON{instr->OutputAt(i), i_json.code_};
    1145             :   }
    1146          82 :   os << "],";
    1147             : 
    1148          82 :   os << "\"inputs\": [";
    1149             :   need_comma = false;
    1150         418 :   for (size_t i = 0; i < instr->InputCount(); i++) {
    1151         168 :     if (need_comma) os << ",";
    1152             :     need_comma = true;
    1153         168 :     os << InstructionOperandAsJSON{instr->InputAt(i), i_json.code_};
    1154             :   }
    1155          82 :   os << "],";
    1156             : 
    1157          82 :   os << "\"temps\": [";
    1158             :   need_comma = false;
    1159          82 :   for (size_t i = 0; i < instr->TempCount(); i++) {
    1160           0 :     if (need_comma) os << ",";
    1161             :     need_comma = true;
    1162           0 :     os << InstructionOperandAsJSON{instr->TempAt(i), i_json.code_};
    1163             :   }
    1164          82 :   os << "]";
    1165          82 :   os << "}";
    1166             : 
    1167          82 :   return os;
    1168             : }
    1169             : 
    1170          20 : std::ostream& operator<<(std::ostream& os, const InstructionBlockAsJSON& b) {
    1171          20 :   const InstructionBlock* block = b.block_;
    1172          20 :   const InstructionSequence* code = b.code_;
    1173          20 :   os << "{";
    1174          40 :   os << "\"id\": " << block->rpo_number() << ",";
    1175          40 :   os << "\"deferred\": " << (block->IsDeferred() ? "true" : "false");
    1176          20 :   os << ",";
    1177          20 :   os << "\"loop_header\": " << block->IsLoopHeader() << ",";
    1178          20 :   if (block->IsLoopHeader()) {
    1179           0 :     os << "\"loop_end\": " << block->loop_end() << ",";
    1180             :   }
    1181          20 :   os << "\"predecessors\": [";
    1182             :   bool need_comma = false;
    1183          44 :   for (RpoNumber pred : block->predecessors()) {
    1184          24 :     if (need_comma) os << ",";
    1185             :     need_comma = true;
    1186          24 :     os << pred.ToInt();
    1187             :   }
    1188          20 :   os << "],";
    1189          20 :   os << "\"successors\": [";
    1190             :   need_comma = false;
    1191          44 :   for (RpoNumber succ : block->successors()) {
    1192          24 :     if (need_comma) os << ",";
    1193             :     need_comma = true;
    1194          24 :     os << succ.ToInt();
    1195             :   }
    1196          20 :   os << "],";
    1197          20 :   os << "\"phis\": [";
    1198             :   bool needs_comma = false;
    1199          20 :   InstructionOperandAsJSON json_op = {nullptr, code};
    1200          22 :   for (const PhiInstruction* phi : block->phis()) {
    1201           2 :     if (needs_comma) os << ",";
    1202             :     needs_comma = true;
    1203           2 :     json_op.op_ = &phi->output();
    1204           2 :     os << "{\"output\" : " << json_op << ",";
    1205           2 :     os << "\"operands\": [";
    1206             :     bool op_needs_comma = false;
    1207           6 :     for (int input : phi->operands()) {
    1208           4 :       if (op_needs_comma) os << ",";
    1209             :       op_needs_comma = true;
    1210           4 :       os << "\"v" << input << "\"";
    1211             :     }
    1212           2 :     os << "]}";
    1213             :   }
    1214          20 :   os << "],";
    1215             : 
    1216          20 :   os << "\"instructions\": [";
    1217          20 :   InstructionAsJSON json_instr = {-1, nullptr, code};
    1218             :   need_comma = false;
    1219         184 :   for (int j = block->first_instruction_index();
    1220             :        j <= block->last_instruction_index(); j++) {
    1221          82 :     if (need_comma) os << ",";
    1222             :     need_comma = true;
    1223          82 :     json_instr.index_ = j;
    1224          82 :     json_instr.instr_ = code->InstructionAt(j);
    1225          82 :     os << json_instr;
    1226             :   }
    1227          20 :   os << "]";
    1228          20 :   os << "}";
    1229             : 
    1230          20 :   return os;
    1231             : }
    1232             : 
    1233           2 : std::ostream& operator<<(std::ostream& os, const InstructionSequenceAsJSON& s) {
    1234           2 :   const InstructionSequence* code = s.sequence_;
    1235             : 
    1236           2 :   os << "\"blocks\": [";
    1237             : 
    1238             :   bool need_comma = false;
    1239          42 :   for (int i = 0; i < code->InstructionBlockCount(); i++) {
    1240          20 :     if (need_comma) os << ",";
    1241             :     need_comma = true;
    1242             :     os << InstructionBlockAsJSON{
    1243          20 :         code->InstructionBlockAt(RpoNumber::FromInt(i)), code};
    1244             :   }
    1245           2 :   os << "]";
    1246             : 
    1247           2 :   return os;
    1248             : }
    1249             : 
    1250             : }  // namespace compiler
    1251             : }  // namespace internal
    1252      120216 : }  // namespace v8

Generated by: LCOV version 1.10