LCOV - code coverage report
Current view: top level - src/compiler - graph-visualizer.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 548 659 83.2 %
Date: 2019-02-19 Functions: 44 59 74.6 %

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

Generated by: LCOV version 1.10