LCOV - code coverage report
Current view: top level - src/compiler - graph-visualizer.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 528 647 81.6 %
Date: 2019-04-18 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         106 : const char* get_cached_trace_turbo_filename(OptimizedCompilationInfo* info) {
      36         106 :   if (!info->trace_turbo_filename()) {
      37             :     info->set_trace_turbo_filename(
      38          18 :         GetVisualizerLogFileName(info, FLAG_trace_turbo_path, nullptr, "json"));
      39             :   }
      40         106 :   return info->trace_turbo_filename();
      41             : }
      42             : 
      43         106 : TurboJsonFile::TurboJsonFile(OptimizedCompilationInfo* info,
      44             :                              std::ios_base::openmode mode)
      45         106 :     : std::ofstream(get_cached_trace_turbo_filename(info), mode) {}
      46             : 
      47         212 : TurboJsonFile::~TurboJsonFile() { flush(); }
      48             : 
      49          45 : TurboCfgFile::TurboCfgFile(Isolate* isolate)
      50          90 :     : std::ofstream(Isolate::GetTurboCfgFileName(isolate).c_str(),
      51          90 :                     std::ios_base::app) {}
      52             : 
      53          90 : TurboCfgFile::~TurboCfgFile() { flush(); }
      54             : 
      55           0 : std::ostream& operator<<(std::ostream& out,
      56             :                          const SourcePositionAsJSON& asJSON) {
      57         546 :   asJSON.sp.PrintJson(out);
      58           0 :   return out;
      59             : }
      60             : 
      61           0 : std::ostream& operator<<(std::ostream& out, const NodeOriginAsJSON& asJSON) {
      62         571 :   asJSON.no.PrintJson(out);
      63           0 :   return out;
      64             : }
      65             : 
      66        2976 : 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       78719 :     for (char c : e.str_) PipeCharacter(os, c);
      72             :     return os;
      73             :   }
      74             : 
      75             :  private:
      76       75743 :   static std::ostream& PipeCharacter(std::ostream& os, char c) {
      77       75743 :     if (c == '"') return os << "\\\"";
      78       75743 :     if (c == '\\') return os << "\\\\";
      79       75743 :     if (c == '\b') return os << "\\b";
      80       75743 :     if (c == '\f') return os << "\\f";
      81       75743 :     if (c == '\n') return os << "\\n";
      82       75743 :     if (c == '\r') return os << "\\r";
      83       75743 :     if (c == '\t') return os << "\\t";
      84       75743 :     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           9 : 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           9 :   std::unique_ptr<char[]> debug_name = info->GetDebugName();
     206           9 :   int optimization_id = info->IsOptimizing() ? info->optimization_id() : 0;
     207           9 :   if (strlen(debug_name.get()) > 0) {
     208           9 :     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          18 :   if (FLAG_trace_file_names && info->has_shared_info() &&
     219           9 :       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           9 :   std::replace(filename.start(), filename.start() + filename.length(), ' ',
     232             :                '_');
     233             : 
     234             :   EmbeddedVector<char, 256> base_dir;
     235           9 :   if (optional_base_dir != nullptr) {
     236           9 :     SNPrintF(base_dir, "%s%c", optional_base_dir,
     237          18 :              base::OS::DirectorySeparator());
     238             :   } else {
     239           0 :     base_dir[0] = '\0';
     240             :   }
     241             : 
     242             :   EmbeddedVector<char, 256> full_filename;
     243           9 :   if (phase == nullptr && !source_available) {
     244             :     SNPrintF(full_filename, "%s%s.%s", base_dir.start(), filename.start(),
     245           9 :              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           9 :   char* buffer = new char[full_filename.length() + 1];
     258           9 :   memcpy(buffer, full_filename.start(), full_filename.length());
     259           9 :   buffer[full_filename.length()] = '\0';
     260           9 :   return std::unique_ptr<char[]>(buffer);
     261             : }
     262             : 
     263             : 
     264        9817 : static int SafeId(Node* node) { return node == nullptr ? -1 : node->id(); }
     265             : static const char* SafeMnemonic(Node* node) {
     266        1377 :   return node == nullptr ? "null" : node->op()->mnemonic();
     267             : }
     268             : 
     269          67 : class JSONGraphNodeWriter {
     270             :  public:
     271          67 :   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          67 :         first_node_(true) {}
     280             : 
     281          67 :   void Print() {
     282        1001 :     for (Node* const node : all_.reachable) PrintNode(node);
     283          67 :     os_ << "\n";
     284          67 :   }
     285             : 
     286         934 :   void PrintNode(Node* node) {
     287         934 :     if (first_node_) {
     288          67 :       first_node_ = false;
     289             :     } else {
     290         867 :       os_ << ",\n";
     291             :     }
     292        1868 :     std::ostringstream label, title, properties;
     293             :     node->op()->PrintTo(label, Operator::PrintVerbosity::kSilent);
     294             :     node->op()->PrintTo(title, Operator::PrintVerbosity::kVerbose);
     295         934 :     node->op()->PrintPropsTo(properties);
     296        2802 :     os_ << "{\"id\":" << SafeId(node) << ",\"label\":\"" << JSONEscaped(label)
     297             :         << "\""
     298         934 :         << ",\"title\":\"" << JSONEscaped(title) << "\""
     299        1868 :         << ",\"live\": " << (live_.IsLive(node) ? "true" : "false")
     300        1868 :         << ",\"properties\":\"" << JSONEscaped(properties) << "\"";
     301             :     IrOpcode::Value opcode = node->opcode();
     302         934 :     if (IrOpcode::IsPhiOpcode(opcode)) {
     303          48 :       os_ << ",\"rankInputs\":[0," << NodeProperties::FirstControlIndex(node)
     304          24 :           << "]";
     305          48 :       os_ << ",\"rankWithInput\":[" << NodeProperties::FirstControlIndex(node)
     306          24 :           << "]";
     307        1820 :     } else if (opcode == IrOpcode::kIfTrue || opcode == IrOpcode::kIfFalse ||
     308         910 :                opcode == IrOpcode::kLoop) {
     309          36 :       os_ << ",\"rankInputs\":[" << NodeProperties::FirstControlIndex(node)
     310          18 :           << "]";
     311             :     }
     312         934 :     if (opcode == IrOpcode::kBranch) {
     313           9 :       os_ << ",\"rankInputs\":[0]";
     314             :     }
     315         934 :     if (positions_ != nullptr) {
     316         934 :       SourcePosition position = positions_->GetSourcePosition(node);
     317         934 :       if (position.IsKnown()) {
     318         546 :         os_ << ", \"sourcePosition\" : " << AsJSON(position);
     319             :       }
     320             :     }
     321         934 :     if (origins_) {
     322         934 :       NodeOrigin origin = origins_->GetNodeOrigin(node);
     323         934 :       if (origin.IsKnown()) {
     324         571 :         os_ << ", \"origin\" : " << AsJSON(origin);
     325             :       }
     326             :     }
     327        1868 :     os_ << ",\"opcode\":\"" << IrOpcode::Mnemonic(node->opcode()) << "\"";
     328         934 :     os_ << ",\"control\":" << (NodeProperties::IsControl(node) ? "true"
     329        1868 :                                                                : "false");
     330        1868 :     os_ << ",\"opinfo\":\"" << node->op()->ValueInputCount() << " v "
     331         934 :         << node->op()->EffectInputCount() << " eff "
     332         934 :         << node->op()->ControlInputCount() << " ctrl in, "
     333         934 :         << node->op()->ValueOutputCount() << " v "
     334         934 :         << node->op()->EffectOutputCount() << " eff "
     335         934 :         << node->op()->ControlOutputCount() << " ctrl out\"";
     336         934 :     if (NodeProperties::IsTyped(node)) {
     337         172 :       Type type = NodeProperties::GetType(node);
     338         344 :       std::ostringstream type_out;
     339         172 :       type.PrintTo(type_out);
     340         516 :       os_ << ",\"type\":\"" << JSONEscaped(type_out) << "\"";
     341             :     }
     342         934 :     os_ << "}";
     343         934 :   }
     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          67 : class JSONGraphEdgeWriter {
     358             :  public:
     359             :   JSONGraphEdgeWriter(std::ostream& os, Zone* zone, const Graph* graph)
     360          67 :       : os_(os), all_(zone, graph, false), first_edge_(true) {}
     361             : 
     362          67 :   void Print() {
     363        1001 :     for (Node* const node : all_.reachable) PrintEdges(node);
     364          67 :     os_ << "\n";
     365          67 :   }
     366             : 
     367         934 :   void PrintEdges(Node* node) {
     368        3956 :     for (int i = 0; i < node->InputCount(); i++) {
     369             :       Node* input = node->InputAt(i);
     370        1511 :       if (input == nullptr) continue;
     371        1491 :       PrintEdge(node, i, input);
     372             :     }
     373         934 :   }
     374             : 
     375        1491 :   void PrintEdge(Node* from, int index, Node* to) {
     376        1491 :     if (first_edge_) {
     377          67 :       first_edge_ = false;
     378             :     } else {
     379        1424 :       os_ << ",\n";
     380             :     }
     381             :     const char* edge_type = nullptr;
     382        1491 :     if (index < NodeProperties::FirstValueIndex(from)) {
     383             :       edge_type = "unknown";
     384        1491 :     } else if (index < NodeProperties::FirstContextIndex(from)) {
     385             :       edge_type = "value";
     386         544 :     } else if (index < NodeProperties::FirstFrameStateIndex(from)) {
     387             :       edge_type = "context";
     388         535 :     } else if (index < NodeProperties::FirstEffectIndex(from)) {
     389             :       edge_type = "frame-state";
     390         490 :     } else if (index < NodeProperties::FirstControlIndex(from)) {
     391             :       edge_type = "effect";
     392             :     } else {
     393             :       edge_type = "control";
     394             :     }
     395        4473 :     os_ << "{\"source\":" << SafeId(to) << ",\"target\":" << SafeId(from)
     396        2982 :         << ",\"index\":" << index << ",\"type\":\"" << edge_type << "\"}";
     397        1491 :   }
     398             : 
     399             :  private:
     400             :   std::ostream& os_;
     401             :   AllNodes all_;
     402             :   bool first_edge_;
     403             : 
     404             :   DISALLOW_COPY_AND_ASSIGN(JSONGraphEdgeWriter);
     405             : };
     406             : 
     407          67 : std::ostream& operator<<(std::ostream& os, const GraphAsJSON& ad) {
     408         134 :   AccountingAllocator allocator;
     409         134 :   Zone tmp_zone(&allocator, ZONE_NAME);
     410          67 :   os << "{\n\"nodes\":[";
     411          67 :   JSONGraphNodeWriter(os, &tmp_zone, &ad.graph, ad.positions, ad.origins)
     412         134 :       .Print();
     413          67 :   os << "],\n\"edges\":[";
     414         201 :   JSONGraphEdgeWriter(os, &tmp_zone, &ad.graph).Print();
     415          67 :   os << "]}";
     416          67 :   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         150 :     Tag(GraphC1Visualizer* visualizer, const char* name) {
     450         150 :       name_ = name;
     451         150 :       visualizer_ = visualizer;
     452             :       visualizer->PrintIndent();
     453         300 :       visualizer_->os_ << "begin_" << name << "\n";
     454         150 :       visualizer->indent_++;
     455         150 :     }
     456             : 
     457         300 :     ~Tag() {
     458         150 :       visualizer_->indent_--;
     459         150 :       visualizer_->PrintIndent();
     460         300 :       visualizer_->os_ << "end_" << name_ << "\n";
     461             :       DCHECK_LE(0, visualizer_->indent_);
     462         150 :     }
     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        5003 :   for (int i = 0; i < indent_; i++) {
     479        1959 :     os_ << "  ";
     480             :   }
     481           0 : }
     482             : 
     483             : 
     484           0 : GraphC1Visualizer::GraphC1Visualizer(std::ostream& os, Zone* zone)
     485          45 :     : os_(os), indent_(0), zone_(zone) {}
     486             : 
     487             : 
     488          74 : void GraphC1Visualizer::PrintStringProperty(const char* name,
     489             :                                             const char* value) {
     490             :   PrintIndent();
     491         148 :   os_ << name << " \"" << value << "\"\n";
     492          74 : }
     493             : 
     494             : 
     495           9 : void GraphC1Visualizer::PrintLongProperty(const char* name, int64_t value) {
     496             :   PrintIndent();
     497          18 :   os_ << name << " " << static_cast<int>(value / 1000) << "\n";
     498           9 : }
     499             : 
     500             : 
     501          33 : void GraphC1Visualizer::PrintBlockProperty(const char* name, int rpo_number) {
     502             :   PrintIndent();
     503          66 :   os_ << name << " \"B" << rpo_number << "\"\n";
     504          33 : }
     505             : 
     506             : 
     507         126 : void GraphC1Visualizer::PrintIntProperty(const char* name, int value) {
     508             :   PrintIndent();
     509         252 :   os_ << name << " " << value << "\n";
     510         126 : }
     511             : 
     512           9 : void GraphC1Visualizer::PrintCompilation(const OptimizedCompilationInfo* info) {
     513          18 :   Tag tag(this, "compilation");
     514           9 :   std::unique_ptr<char[]> name = info->GetDebugName();
     515           9 :   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           8 :     PrintStringProperty("name", name.get());
     522           8 :     PrintStringProperty("method", "stub");
     523             :   }
     524           9 :   PrintLongProperty(
     525             :       "date",
     526          18 :       static_cast<int64_t>(V8::GetCurrentPlatform()->CurrentClockTimeMillis()));
     527           9 : }
     528             : 
     529             : 
     530        1083 : void GraphC1Visualizer::PrintNodeId(Node* n) { os_ << "n" << SafeId(n); }
     531             : 
     532             : 
     533         141 : void GraphC1Visualizer::PrintNode(Node* n) {
     534         141 :   PrintNodeId(n);
     535         282 :   os_ << " " << *n->op() << " ";
     536         141 :   PrintInputs(n);
     537         141 : }
     538             : 
     539             : 
     540             : template <typename InputIterator>
     541         705 : void GraphC1Visualizer::PrintInputs(InputIterator* i, int count,
     542             :                                     const char* prefix) {
     543         705 :   if (count > 0) {
     544         162 :     os_ << prefix;
     545             :   }
     546        1145 :   while (count > 0) {
     547         220 :     os_ << " ";
     548         220 :     PrintNodeId(**i);
     549             :     ++(*i);
     550         220 :     count--;
     551             :   }
     552         705 : }
     553             : 
     554             : 
     555         141 : void GraphC1Visualizer::PrintInputs(Node* node) {
     556         141 :   auto i = node->inputs().begin();
     557         141 :   PrintInputs(&i, node->op()->ValueInputCount(), " ");
     558             :   PrintInputs(&i, OperatorProperties::GetContextInputCount(node->op()),
     559         141 :               " Ctx:");
     560             :   PrintInputs(&i, OperatorProperties::GetFrameStateInputCount(node->op()),
     561         141 :               " FS:");
     562         141 :   PrintInputs(&i, node->op()->EffectInputCount(), " Eff:");
     563         141 :   PrintInputs(&i, node->op()->ControlInputCount(), " Ctrl:");
     564         141 : }
     565             : 
     566             : 
     567         141 : void GraphC1Visualizer::PrintType(Node* node) {
     568         141 :   if (NodeProperties::IsTyped(node)) {
     569          10 :     Type type = NodeProperties::GetType(node);
     570          20 :     os_ << " type:" << type;
     571             :   }
     572         141 : }
     573             : 
     574             : 
     575           9 : void GraphC1Visualizer::PrintSchedule(const char* phase,
     576             :                                       const Schedule* schedule,
     577             :                                       const SourcePositionTable* positions,
     578             :                                       const InstructionSequence* instructions) {
     579          18 :   Tag tag(this, "cfg");
     580           9 :   PrintStringProperty("name", phase);
     581             :   const BasicBlockVector* rpo = schedule->rpo_order();
     582          51 :   for (size_t i = 0; i < rpo->size(); i++) {
     583          21 :     BasicBlock* current = (*rpo)[i];
     584          42 :     Tag block_tag(this, "block");
     585          21 :     PrintBlockProperty("name", current->rpo_number());
     586          21 :     PrintIntProperty("from_bci", -1);
     587          21 :     PrintIntProperty("to_bci", -1);
     588             : 
     589             :     PrintIndent();
     590          21 :     os_ << "predecessors";
     591          34 :     for (BasicBlock* predecessor : current->predecessors()) {
     592          26 :       os_ << " \"B" << predecessor->rpo_number() << "\"";
     593             :     }
     594          21 :     os_ << "\n";
     595             : 
     596             :     PrintIndent();
     597          21 :     os_ << "successors";
     598          34 :     for (BasicBlock* successor : current->successors()) {
     599          26 :       os_ << " \"B" << successor->rpo_number() << "\"";
     600             :     }
     601          21 :     os_ << "\n";
     602             : 
     603             :     PrintIndent();
     604          21 :     os_ << "xhandlers\n";
     605             : 
     606             :     PrintIndent();
     607          21 :     os_ << "flags\n";
     608             : 
     609          21 :     if (current->dominator() != nullptr) {
     610          12 :       PrintBlockProperty("dominator", current->dominator()->rpo_number());
     611             :     }
     612             : 
     613          21 :     PrintIntProperty("loop_depth", current->loop_depth());
     614             : 
     615             :     const InstructionBlock* instruction_block =
     616             :         instructions->InstructionBlockAt(
     617          21 :             RpoNumber::FromInt(current->rpo_number()));
     618          21 :     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          21 :           LifetimePosition::GapFromInstructionIndex(first_index).value());
     624             :       PrintIntProperty("last_lir_id",
     625             :                        LifetimePosition::InstructionFromInstructionIndex(
     626          21 :                            last_index).value());
     627             :     }
     628             : 
     629             :     {
     630          42 :       Tag states_tag(this, "states");
     631          42 :       Tag locals_tag(this, "locals");
     632             :       int total = 0;
     633         152 :       for (BasicBlock::const_iterator i = current->begin(); i != current->end();
     634             :            ++i) {
     635         262 :         if ((*i)->opcode() == IrOpcode::kPhi) total++;
     636             :       }
     637          21 :       PrintIntProperty("size", total);
     638          21 :       PrintStringProperty("method", "None");
     639             :       int index = 0;
     640         152 :       for (BasicBlock::const_iterator i = current->begin(); i != current->end();
     641             :            ++i) {
     642         262 :         if ((*i)->opcode() != IrOpcode::kPhi) continue;
     643             :         PrintIndent();
     644           0 :         os_ << index << " ";
     645           0 :         PrintNodeId(*i);
     646           0 :         os_ << " [";
     647           0 :         PrintInputs(*i);
     648           0 :         os_ << "]\n";
     649           0 :         index++;
     650             :       }
     651             :     }
     652             : 
     653             :     {
     654          42 :       Tag HIR_tag(this, "HIR");
     655         152 :       for (BasicBlock::const_iterator i = current->begin(); i != current->end();
     656             :            ++i) {
     657         131 :         Node* node = *i;
     658         131 :         if (node->opcode() == IrOpcode::kPhi) continue;
     659         131 :         int uses = node->UseCount();
     660             :         PrintIndent();
     661         262 :         os_ << "0 " << uses << " ";
     662         131 :         PrintNode(node);
     663         131 :         if (FLAG_trace_turbo_types) {
     664         131 :           os_ << " ";
     665         131 :           PrintType(node);
     666             :         }
     667         131 :         if (positions != nullptr) {
     668         131 :           SourcePosition position = positions->GetSourcePosition(node);
     669         131 :           if (position.IsKnown()) {
     670          43 :             os_ << " pos:";
     671          43 :             if (position.isInlined()) {
     672           0 :               os_ << "inlining(" << position.InliningId() << "),";
     673             :             }
     674          43 :             os_ << position.ScriptOffset();
     675             :           }
     676             :         }
     677         131 :         os_ << " <|@\n";
     678             :       }
     679             : 
     680             :       BasicBlock::Control control = current->control();
     681          21 :       if (control != BasicBlock::kNone) {
     682             :         PrintIndent();
     683          12 :         os_ << "0 0 ";
     684          12 :         if (current->control_input() != nullptr) {
     685          10 :           PrintNode(current->control_input());
     686             :         } else {
     687           2 :           os_ << -1 - current->rpo_number() << " Goto";
     688             :         }
     689          12 :         os_ << " ->";
     690          25 :         for (BasicBlock* successor : current->successors()) {
     691          26 :           os_ << " B" << successor->rpo_number();
     692             :         }
     693          12 :         if (FLAG_trace_turbo_types && current->control_input() != nullptr) {
     694          10 :           os_ << " ";
     695          10 :           PrintType(current->control_input());
     696             :         }
     697          12 :         os_ << " <|@\n";
     698             :       }
     699             :     }
     700             : 
     701          21 :     if (instructions != nullptr) {
     702          42 :       Tag LIR_tag(this, "LIR");
     703         141 :       for (int j = instruction_block->first_instruction_index();
     704             :            j <= instruction_block->last_instruction_index(); j++) {
     705             :         PrintIndent();
     706         120 :         os_ << j << " " << *instructions->InstructionAt(j) << " <|@\n";
     707             :       }
     708             :     }
     709             :   }
     710           9 : }
     711             : 
     712             : 
     713          27 : void GraphC1Visualizer::PrintLiveRanges(const char* phase,
     714             :                                         const RegisterAllocationData* data) {
     715          54 :   Tag tag(this, "intervals");
     716          27 :   PrintStringProperty("name", phase);
     717             : 
     718         891 :   for (const TopLevelLiveRange* range : data->fixed_double_live_ranges()) {
     719         864 :     PrintLiveRangeChain(range, "fixed");
     720             :   }
     721             : 
     722         891 :   for (const TopLevelLiveRange* range : data->fixed_live_ranges()) {
     723         864 :     PrintLiveRangeChain(range, "fixed");
     724             :   }
     725             : 
     726         249 :   for (const TopLevelLiveRange* range : data->live_ranges()) {
     727         222 :     PrintLiveRangeChain(range, "object");
     728             :   }
     729          27 : }
     730             : 
     731        1950 : void GraphC1Visualizer::PrintLiveRangeChain(const TopLevelLiveRange* range,
     732             :                                             const char* type) {
     733        1950 :   if (range == nullptr || range->IsEmpty()) return;
     734             :   int vreg = range->vreg();
     735         752 :   for (const LiveRange* child = range; child != nullptr;
     736             :        child = child->next()) {
     737         255 :     PrintLiveRange(child, type, vreg);
     738             :   }
     739             : }
     740             : 
     741         255 : void GraphC1Visualizer::PrintLiveRange(const LiveRange* range, const char* type,
     742             :                                        int vreg) {
     743         255 :   if (range != nullptr && !range->IsEmpty()) {
     744             :     PrintIndent();
     745         765 :     os_ << vreg << ":" << range->relative_id() << " " << type;
     746         255 :     if (range->HasRegisterAssigned()) {
     747         324 :       AllocatedOperand op = AllocatedOperand::cast(range->GetAssignedOperand());
     748         162 :       if (op.IsRegister()) {
     749         234 :         os_ << " \"" << Register::from_code(op.register_code()) << "\"";
     750          45 :       } else if (op.IsDoubleRegister()) {
     751          90 :         os_ << " \"" << DoubleRegister::from_code(op.register_code()) << "\"";
     752             :       } else {
     753             :         DCHECK(op.IsFloatRegister());
     754           0 :         os_ << " \"" << FloatRegister::from_code(op.register_code()) << "\"";
     755             :       }
     756          93 :     } else if (range->spilled()) {
     757             :       const TopLevelLiveRange* top = range->TopLevel();
     758             :       int index = -1;
     759          16 :       if (top->HasSpillRange()) {
     760             :         index = kMaxInt;  // This hasn't been set yet.
     761          13 :       } else if (top->GetSpillOperand()->IsConstant()) {
     762           4 :         os_ << " \"const(nostack):"
     763           4 :             << ConstantOperand::cast(top->GetSpillOperand())->virtual_register()
     764           4 :             << "\"";
     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         255 :     if (parent->IsSplinter()) parent = parent->splintered_from();
     779         765 :     os_ << " " << parent->vreg() << ":" << parent->relative_id();
     780             : 
     781             :     // TODO(herhut) Find something useful to print for the hint field
     782         255 :     if (range->get_bundle() != nullptr) {
     783           0 :       os_ << " B" << range->get_bundle()->id();
     784             :     } else {
     785         255 :       os_ << " unknown";
     786             :     }
     787             : 
     788         289 :     for (const UseInterval* interval = range->first_interval();
     789         544 :          interval != nullptr; interval = interval->next()) {
     790         578 :       os_ << " [" << interval->start().value() << ", "
     791         289 :           << interval->end().value() << "[";
     792             :     }
     793             : 
     794             :     UsePosition* current_pos = range->first_pos();
     795         831 :     while (current_pos != nullptr) {
     796         288 :       if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) {
     797         276 :         os_ << " " << current_pos->pos().value() << " M";
     798             :       }
     799             :       current_pos = current_pos->next();
     800             :     }
     801             : 
     802         255 :     os_ << " \"\"\n";
     803             :   }
     804         255 : }
     805             : 
     806             : 
     807           9 : std::ostream& operator<<(std::ostream& os, const AsC1VCompilation& ac) {
     808          18 :   AccountingAllocator allocator;
     809          18 :   Zone tmp_zone(&allocator, ZONE_NAME);
     810          18 :   GraphC1Visualizer(os, &tmp_zone).PrintCompilation(ac.info_);
     811           9 :   return os;
     812             : }
     813             : 
     814             : 
     815           9 : std::ostream& operator<<(std::ostream& os, const AsC1V& ac) {
     816          18 :   AccountingAllocator allocator;
     817          18 :   Zone tmp_zone(&allocator, ZONE_NAME);
     818             :   GraphC1Visualizer(os, &tmp_zone)
     819          18 :       .PrintSchedule(ac.phase_, ac.schedule_, ac.positions_, ac.instructions_);
     820           9 :   return os;
     821             : }
     822             : 
     823             : 
     824          27 : std::ostream& operator<<(std::ostream& os,
     825             :                          const AsC1VRegisterAllocationData& ac) {
     826          54 :   AccountingAllocator allocator;
     827          54 :   Zone tmp_zone(&allocator, ZONE_NAME);
     828          54 :   GraphC1Visualizer(os, &tmp_zone).PrintLiveRanges(ac.phase_, ac.data_);
     829          27 :   return os;
     830             : }
     831             : 
     832             : const int kUnvisited = 0;
     833             : const int kOnStack = 1;
     834             : const int kVisited = 2;
     835             : 
     836          42 : std::ostream& operator<<(std::ostream& os, const AsRPO& ar) {
     837          84 :   AccountingAllocator allocator;
     838          84 :   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          42 :   ZoneVector<byte> state(ar.graph.NodeCount(), kUnvisited, &local_zone);
     854          42 :   ZoneStack<Node*> stack(&local_zone);
     855             : 
     856          84 :   stack.push(ar.graph.end());
     857         126 :   state[ar.graph.end()->id()] = kOnStack;
     858        1658 :   while (!stack.empty()) {
     859        1616 :     Node* n = stack.top();
     860             :     bool pop = true;
     861        6495 :     for (Node* const i : n->inputs()) {
     862        5666 :       if (state[i->id()] == kUnvisited) {
     863         787 :         state[i->id()] = kOnStack;
     864             :         stack.push(i);
     865             :         pop = false;
     866         787 :         break;
     867             :       }
     868             :     }
     869        1616 :     if (pop) {
     870        1658 :       state[n->id()] = kVisited;
     871             :       stack.pop();
     872         829 :       os << "#" << n->id() << ":" << *n->op() << "(";
     873             :       // Print the inputs.
     874             :       int j = 0;
     875        2206 :       for (Node* const i : n->inputs()) {
     876        1377 :         if (j++ > 0) os << ", ";
     877        2754 :         os << "#" << SafeId(i) << ":" << SafeMnemonic(i);
     878             :       }
     879         829 :       os << ")";
     880             :       // Print the node type, if any.
     881         829 :       if (NodeProperties::IsTyped(n)) {
     882         171 :         os << "  [Type: " << NodeProperties::GetType(n) << "]";
     883             :       }
     884             :       os << std::endl;
     885             :     }
     886             :   }
     887          42 :   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         326 : std::ostream& operator<<(std::ostream& os, const InstructionOperandAsJSON& o) {
     972         326 :   const InstructionOperand* op = o.op_;
     973         326 :   const InstructionSequence* code = o.code_;
     974         326 :   os << "{";
     975         326 :   switch (op->kind()) {
     976             :     case InstructionOperand::UNALLOCATED: {
     977             :       const UnallocatedOperand* unalloc = UnallocatedOperand::cast(op);
     978          95 :       os << "\"type\": \"unallocated\", ";
     979          95 :       os << "\"text\": \"v" << unalloc->virtual_register() << "\"";
     980          95 :       if (unalloc->basic_policy() == UnallocatedOperand::FIXED_SLOT) {
     981           0 :         os << ",\"tooltip\": \"FIXED_SLOT: " << unalloc->fixed_slot_index()
     982           0 :            << "\"";
     983           0 :         break;
     984             :       }
     985          95 :       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          32 :           os << ",\"tooltip\": \"MUST_HAVE_REGISTER\"";
    1001          32 :           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           5 :           os << ",\"tooltip\": \"SAME_AS_FIRST_INPUT\"";
    1009           5 :           break;
    1010             :         }
    1011             :         case UnallocatedOperand::REGISTER_OR_SLOT: {
    1012          46 :           os << ",\"tooltip\": \"REGISTER_OR_SLOT\"";
    1013          46 :           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           9 :       os << "\"type\": \"constant\", ";
    1025           9 :       os << "\"text\": \"v" << vreg << "\",";
    1026           9 :       os << "\"tooltip\": \"";
    1027          18 :       std::stringstream tooltip;
    1028           9 :       tooltip << code->GetConstant(vreg);
    1029         159 :       for (const auto& c : tooltip.str()) {
    1030         300 :         os << AsEscapedUC16ForJSON(c);
    1031             :       }
    1032           9 :       os << "\"";
    1033             :       break;
    1034             :     }
    1035             :     case InstructionOperand::IMMEDIATE: {
    1036          56 :       os << "\"type\": \"immediate\", ";
    1037             :       const ImmediateOperand* imm = ImmediateOperand::cast(op);
    1038          56 :       switch (imm->type()) {
    1039             :         case ImmediateOperand::INLINE: {
    1040          32 :           os << "\"text\": \"#" << imm->inline_value() << "\"";
    1041          32 :           break;
    1042             :         }
    1043             :         case ImmediateOperand::INDEXED: {
    1044             :           int index = imm->indexed_value();
    1045          24 :           os << "\"text\": \"imm:" << index << "\",";
    1046          24 :           os << "\"tooltip\": \"";
    1047          48 :           std::stringstream tooltip;
    1048          24 :           tooltip << code->GetImmediate(imm);
    1049         672 :           for (const auto& c : tooltip.str()) {
    1050        1296 :             os << AsEscapedUC16ForJSON(c);
    1051             :           }
    1052          24 :           os << "\"";
    1053             :           break;
    1054             :         }
    1055             :       }
    1056             :       break;
    1057             :     }
    1058             :     case InstructionOperand::EXPLICIT:
    1059             :     case InstructionOperand::ALLOCATED: {
    1060             :       const LocationOperand* allocated = LocationOperand::cast(op);
    1061         166 :       os << "\"type\": ";
    1062         166 :       if (allocated->IsExplicit()) {
    1063           0 :         os << "\"explicit\", ";
    1064             :       } else {
    1065         166 :         os << "\"allocated\", ";
    1066             :       }
    1067         166 :       os << "\"text\": \"";
    1068         166 :       if (op->IsStackSlot()) {
    1069          23 :         os << "stack:" << allocated->index();
    1070         143 :       } else if (op->IsFPStackSlot()) {
    1071           0 :         os << "fp_stack:" << allocated->index();
    1072         143 :       } else if (op->IsRegister()) {
    1073         143 :         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           0 :       } 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         166 :       os << "\",";
    1087             :       os << "\"tooltip\": \""
    1088         332 :          << MachineReprToString(allocated->representation()) << "\"";
    1089         166 :       break;
    1090             :     }
    1091             :     case InstructionOperand::INVALID:
    1092           0 :       UNREACHABLE();
    1093             :   }
    1094         326 :   os << "}";
    1095         326 :   return os;
    1096             : }
    1097             : 
    1098         120 : std::ostream& operator<<(std::ostream& os, const InstructionAsJSON& i_json) {
    1099         120 :   const Instruction* instr = i_json.instr_;
    1100             : 
    1101         120 :   os << "{";
    1102         240 :   os << "\"id\": " << i_json.index_ << ",";
    1103         360 :   os << "\"opcode\": \"" << ArchOpcodeField::decode(instr->opcode()) << "\",";
    1104         120 :   os << "\"flags\": \"";
    1105         240 :   FlagsMode fm = FlagsModeField::decode(instr->opcode());
    1106         120 :   AddressingMode am = AddressingModeField::decode(instr->opcode());
    1107         120 :   if (am != kMode_None) {
    1108          32 :     os << " : " << AddressingModeField::decode(instr->opcode());
    1109             :   }
    1110         120 :   if (fm != kFlags_none) {
    1111           8 :     os << " && " << fm << " if "
    1112          24 :        << FlagsConditionField::decode(instr->opcode());
    1113             :   }
    1114         120 :   os << "\",";
    1115             : 
    1116         120 :   os << "\"gaps\": [";
    1117         240 :   for (int i = Instruction::FIRST_GAP_POSITION;
    1118         360 :        i <= Instruction::LAST_GAP_POSITION; i++) {
    1119         240 :     if (i != Instruction::FIRST_GAP_POSITION) os << ",";
    1120         240 :     os << "[";
    1121         240 :     const ParallelMove* pm = instr->parallel_moves()[i];
    1122         240 :     if (pm == nullptr) {
    1123         162 :       os << "]";
    1124         162 :       continue;
    1125             :     }
    1126             :     bool first = true;
    1127         128 :     for (MoveOperands* move : *pm) {
    1128          50 :       if (move->IsEliminated()) continue;
    1129          46 :       if (!first) os << ",";
    1130             :       first = false;
    1131         138 :       os << "[" << InstructionOperandAsJSON{&move->destination(), i_json.code_}
    1132         138 :          << "," << InstructionOperandAsJSON{&move->source(), i_json.code_}
    1133          46 :          << "]";
    1134             :     }
    1135          78 :     os << "]";
    1136             :   }
    1137         120 :   os << "],";
    1138             : 
    1139         120 :   os << "\"outputs\": [";
    1140             :   bool need_comma = false;
    1141         268 :   for (size_t i = 0; i < instr->OutputCount(); i++) {
    1142          74 :     if (need_comma) os << ",";
    1143             :     need_comma = true;
    1144          74 :     os << InstructionOperandAsJSON{instr->OutputAt(i), i_json.code_};
    1145             :   }
    1146         120 :   os << "],";
    1147             : 
    1148         120 :   os << "\"inputs\": [";
    1149             :   need_comma = false;
    1150         440 :   for (size_t i = 0; i < instr->InputCount(); i++) {
    1151         160 :     if (need_comma) os << ",";
    1152             :     need_comma = true;
    1153         160 :     os << InstructionOperandAsJSON{instr->InputAt(i), i_json.code_};
    1154             :   }
    1155         120 :   os << "],";
    1156             : 
    1157         120 :   os << "\"temps\": [";
    1158             :   need_comma = false;
    1159         120 :   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         120 :   os << "]";
    1165         120 :   os << "}";
    1166             : 
    1167         120 :   return os;
    1168             : }
    1169             : 
    1170          42 : std::ostream& operator<<(std::ostream& os, const InstructionBlockAsJSON& b) {
    1171          42 :   const InstructionBlock* block = b.block_;
    1172          42 :   const InstructionSequence* code = b.code_;
    1173          42 :   os << "{";
    1174          84 :   os << "\"id\": " << block->rpo_number() << ",";
    1175          84 :   os << "\"deferred\": " << (block->IsDeferred() ? "true" : "false");
    1176          42 :   os << ",";
    1177          42 :   os << "\"loop_header\": " << block->IsLoopHeader() << ",";
    1178          42 :   if (block->IsLoopHeader()) {
    1179           0 :     os << "\"loop_end\": " << block->loop_end() << ",";
    1180             :   }
    1181          42 :   os << "\"predecessors\": [";
    1182             :   bool need_comma = false;
    1183          68 :   for (RpoNumber pred : block->predecessors()) {
    1184          26 :     if (need_comma) os << ",";
    1185             :     need_comma = true;
    1186          26 :     os << pred.ToInt();
    1187             :   }
    1188          42 :   os << "],";
    1189          42 :   os << "\"successors\": [";
    1190             :   need_comma = false;
    1191          68 :   for (RpoNumber succ : block->successors()) {
    1192          26 :     if (need_comma) os << ",";
    1193             :     need_comma = true;
    1194          26 :     os << succ.ToInt();
    1195             :   }
    1196          42 :   os << "],";
    1197          42 :   os << "\"phis\": [";
    1198             :   bool needs_comma = false;
    1199          42 :   InstructionOperandAsJSON json_op = {nullptr, code};
    1200          42 :   for (const PhiInstruction* phi : block->phis()) {
    1201           0 :     if (needs_comma) os << ",";
    1202             :     needs_comma = true;
    1203           0 :     json_op.op_ = &phi->output();
    1204           0 :     os << "{\"output\" : " << json_op << ",";
    1205           0 :     os << "\"operands\": [";
    1206             :     bool op_needs_comma = false;
    1207           0 :     for (int input : phi->operands()) {
    1208           0 :       if (op_needs_comma) os << ",";
    1209             :       op_needs_comma = true;
    1210           0 :       os << "\"v" << input << "\"";
    1211             :     }
    1212           0 :     os << "]}";
    1213             :   }
    1214          42 :   os << "],";
    1215             : 
    1216          42 :   os << "\"instructions\": [";
    1217          42 :   InstructionAsJSON json_instr = {-1, nullptr, code};
    1218             :   need_comma = false;
    1219         282 :   for (int j = block->first_instruction_index();
    1220             :        j <= block->last_instruction_index(); j++) {
    1221         120 :     if (need_comma) os << ",";
    1222             :     need_comma = true;
    1223         120 :     json_instr.index_ = j;
    1224         120 :     json_instr.instr_ = code->InstructionAt(j);
    1225         120 :     os << json_instr;
    1226             :   }
    1227          42 :   os << "]";
    1228          42 :   os << "}";
    1229             : 
    1230          42 :   return os;
    1231             : }
    1232             : 
    1233          18 : std::ostream& operator<<(std::ostream& os, const InstructionSequenceAsJSON& s) {
    1234          18 :   const InstructionSequence* code = s.sequence_;
    1235             : 
    1236          18 :   os << "\"blocks\": [";
    1237             : 
    1238             :   bool need_comma = false;
    1239         102 :   for (int i = 0; i < code->InstructionBlockCount(); i++) {
    1240          42 :     if (need_comma) os << ",";
    1241             :     need_comma = true;
    1242             :     os << InstructionBlockAsJSON{
    1243          42 :         code->InstructionBlockAt(RpoNumber::FromInt(i)), code};
    1244             :   }
    1245          18 :   os << "]";
    1246             : 
    1247          18 :   return os;
    1248             : }
    1249             : 
    1250             : }  // namespace compiler
    1251             : }  // namespace internal
    1252      122036 : }  // namespace v8

Generated by: LCOV version 1.10