LCOV - code coverage report
Current view: top level - src/compiler/backend - instruction.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 320 459 69.7 %
Date: 2019-03-21 Functions: 53 68 77.9 %

          Line data    Source code
       1             : // Copyright 2014 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/backend/instruction.h"
       6             : 
       7             : #include <iomanip>
       8             : 
       9             : #include "src/compiler/common-operator.h"
      10             : #include "src/compiler/graph.h"
      11             : #include "src/compiler/schedule.h"
      12             : #include "src/compiler/state-values-utils.h"
      13             : #include "src/register-configuration.h"
      14             : #include "src/source-position.h"
      15             : 
      16             : namespace v8 {
      17             : namespace internal {
      18             : namespace compiler {
      19             : 
      20             : const RegisterConfiguration* (*GetRegConfig)() = RegisterConfiguration::Default;
      21             : 
      22     1116478 : FlagsCondition CommuteFlagsCondition(FlagsCondition condition) {
      23     1116478 :   switch (condition) {
      24             :     case kSignedLessThan:
      25             :       return kSignedGreaterThan;
      26             :     case kSignedGreaterThanOrEqual:
      27         555 :       return kSignedLessThanOrEqual;
      28             :     case kSignedLessThanOrEqual:
      29       11719 :       return kSignedGreaterThanOrEqual;
      30             :     case kSignedGreaterThan:
      31        1027 :       return kSignedLessThan;
      32             :     case kUnsignedLessThan:
      33      930601 :       return kUnsignedGreaterThan;
      34             :     case kUnsignedGreaterThanOrEqual:
      35       17866 :       return kUnsignedLessThanOrEqual;
      36             :     case kUnsignedLessThanOrEqual:
      37       73355 :       return kUnsignedGreaterThanOrEqual;
      38             :     case kUnsignedGreaterThan:
      39        1280 :       return kUnsignedLessThan;
      40             :     case kFloatLessThanOrUnordered:
      41           0 :       return kFloatGreaterThanOrUnordered;
      42             :     case kFloatGreaterThanOrEqual:
      43           0 :       return kFloatLessThanOrEqual;
      44             :     case kFloatLessThanOrEqual:
      45           0 :       return kFloatGreaterThanOrEqual;
      46             :     case kFloatGreaterThanOrUnordered:
      47           0 :       return kFloatLessThanOrUnordered;
      48             :     case kFloatLessThan:
      49           0 :       return kFloatGreaterThan;
      50             :     case kFloatGreaterThanOrEqualOrUnordered:
      51           0 :       return kFloatLessThanOrEqualOrUnordered;
      52             :     case kFloatLessThanOrEqualOrUnordered:
      53           0 :       return kFloatGreaterThanOrEqualOrUnordered;
      54             :     case kFloatGreaterThan:
      55           0 :       return kFloatLessThan;
      56             :     case kPositiveOrZero:
      57             :     case kNegative:
      58           0 :       UNREACHABLE();
      59             :       break;
      60             :     case kEqual:
      61             :     case kNotEqual:
      62             :     case kOverflow:
      63             :     case kNotOverflow:
      64             :     case kUnorderedEqual:
      65             :     case kUnorderedNotEqual:
      66         700 :       return condition;
      67             :   }
      68           0 :   UNREACHABLE();
      69             : }
      70             : 
      71    65032922 : bool InstructionOperand::InterferesWith(const InstructionOperand& other) const {
      72             :   if (kSimpleFPAliasing || !this->IsFPLocationOperand() ||
      73             :       !other.IsFPLocationOperand())
      74             :     return EqualsCanonicalized(other);
      75             :   // Aliasing is complex and both operands are fp locations.
      76             :   const LocationOperand& loc = *LocationOperand::cast(this);
      77             :   const LocationOperand& other_loc = LocationOperand::cast(other);
      78             :   LocationOperand::LocationKind kind = loc.location_kind();
      79             :   LocationOperand::LocationKind other_kind = other_loc.location_kind();
      80             :   if (kind != other_kind) return false;
      81             :   MachineRepresentation rep = loc.representation();
      82             :   MachineRepresentation other_rep = other_loc.representation();
      83             :   if (rep == other_rep) return EqualsCanonicalized(other);
      84             :   if (kind == LocationOperand::REGISTER) {
      85             :     // FP register-register interference.
      86             :     return GetRegConfig()->AreAliases(rep, loc.register_code(), other_rep,
      87             :                                       other_loc.register_code());
      88             :   } else {
      89             :     // FP slot-slot interference. Slots of different FP reps can alias because
      90             :     // the gap resolver may break a move into 2 or 4 equivalent smaller moves.
      91             :     DCHECK_EQ(LocationOperand::STACK_SLOT, kind);
      92             :     int index_hi = loc.index();
      93             :     int index_lo =
      94             :         index_hi - (1 << ElementSizeLog2Of(rep)) / kSystemPointerSize + 1;
      95             :     int other_index_hi = other_loc.index();
      96             :     int other_index_lo =
      97             :         other_index_hi -
      98             :         (1 << ElementSizeLog2Of(other_rep)) / kSystemPointerSize + 1;
      99             :     return other_index_hi >= index_lo && index_hi >= other_index_lo;
     100             :   }
     101             :   return false;
     102             : }
     103             : 
     104           0 : bool LocationOperand::IsCompatible(LocationOperand* op) {
     105           0 :   if (IsRegister() || IsStackSlot()) {
     106           0 :     return op->IsRegister() || op->IsStackSlot();
     107             :   } else if (kSimpleFPAliasing) {
     108             :     // A backend may choose to generate the same instruction sequence regardless
     109             :     // of the FP representation. As a result, we can relax the compatibility and
     110             :     // allow a Double to be moved in a Float for example. However, this is only
     111             :     // allowed if registers do not overlap.
     112           0 :     return (IsFPRegister() || IsFPStackSlot()) &&
     113           0 :            (op->IsFPRegister() || op->IsFPStackSlot());
     114             :   } else if (IsFloatRegister() || IsFloatStackSlot()) {
     115             :     return op->IsFloatRegister() || op->IsFloatStackSlot();
     116             :   } else if (IsDoubleRegister() || IsDoubleStackSlot()) {
     117             :     return op->IsDoubleRegister() || op->IsDoubleStackSlot();
     118             :   } else {
     119             :     return (IsSimd128Register() || IsSimd128StackSlot()) &&
     120             :            (op->IsSimd128Register() || op->IsSimd128StackSlot());
     121             :   }
     122             : }
     123             : 
     124           0 : void InstructionOperand::Print() const { StdoutStream{} << *this << std::endl; }
     125             : 
     126         407 : std::ostream& operator<<(std::ostream& os, const InstructionOperand& op) {
     127         407 :   switch (op.kind()) {
     128             :     case InstructionOperand::UNALLOCATED: {
     129             :       const UnallocatedOperand* unalloc = UnallocatedOperand::cast(&op);
     130         154 :       os << "v" << unalloc->virtual_register();
     131         154 :       if (unalloc->basic_policy() == UnallocatedOperand::FIXED_SLOT) {
     132           6 :         return os << "(=" << unalloc->fixed_slot_index() << "S)";
     133             :       }
     134         151 :       switch (unalloc->extended_policy()) {
     135             :         case UnallocatedOperand::NONE:
     136             :           return os;
     137             :         case UnallocatedOperand::FIXED_REGISTER:
     138             :           return os << "(="
     139             :                     << Register::from_code(unalloc->fixed_register_index())
     140           9 :                     << ")";
     141             :         case UnallocatedOperand::FIXED_FP_REGISTER:
     142             :           return os << "(="
     143             :                     << DoubleRegister::from_code(
     144             :                            unalloc->fixed_register_index())
     145           0 :                     << ")";
     146             :         case UnallocatedOperand::MUST_HAVE_REGISTER:
     147          54 :           return os << "(R)";
     148             :         case UnallocatedOperand::MUST_HAVE_SLOT:
     149          14 :           return os << "(S)";
     150             :         case UnallocatedOperand::SAME_AS_FIRST_INPUT:
     151          14 :           return os << "(1)";
     152             :         case UnallocatedOperand::REGISTER_OR_SLOT:
     153          38 :           return os << "(-)";
     154             :         case UnallocatedOperand::REGISTER_OR_SLOT_OR_CONSTANT:
     155           0 :           return os << "(*)";
     156             :       }
     157             :     }
     158             :     case InstructionOperand::CONSTANT:
     159          29 :       return os << "[constant:" << ConstantOperand::cast(op).virtual_register()
     160             :                 << "]";
     161             :     case InstructionOperand::IMMEDIATE: {
     162             :       ImmediateOperand imm = ImmediateOperand::cast(op);
     163         108 :       switch (imm.type()) {
     164             :         case ImmediateOperand::INLINE:
     165          30 :           return os << "#" << imm.inline_value();
     166             :         case ImmediateOperand::INDEXED:
     167         156 :           return os << "[immediate:" << imm.indexed_value() << "]";
     168             :       }
     169             :     }
     170             :     case InstructionOperand::EXPLICIT:
     171             :     case InstructionOperand::ALLOCATED: {
     172             :       LocationOperand allocated = LocationOperand::cast(op);
     173         116 :       if (op.IsStackSlot()) {
     174          25 :         os << "[stack:" << allocated.index();
     175          91 :       } else if (op.IsFPStackSlot()) {
     176           0 :         os << "[fp_stack:" << allocated.index();
     177          91 :       } else if (op.IsRegister()) {
     178             :         const char* name =
     179             :             allocated.register_code() < Register::kNumRegisters
     180             :                 ? RegisterName(Register::from_code(allocated.register_code()))
     181          89 :                 : Register::GetSpecialRegisterName(allocated.register_code());
     182          89 :         os << "[" << name << "|R";
     183           2 :       } else if (op.IsDoubleRegister()) {
     184             :         os << "[" << DoubleRegister::from_code(allocated.register_code())
     185           2 :            << "|R";
     186           0 :       } else if (op.IsFloatRegister()) {
     187             :         os << "[" << FloatRegister::from_code(allocated.register_code())
     188           0 :            << "|R";
     189             :       } else {
     190             :         DCHECK(op.IsSimd128Register());
     191             :         os << "[" << Simd128Register::from_code(allocated.register_code())
     192           0 :            << "|R";
     193             :       }
     194         116 :       if (allocated.IsExplicit()) {
     195           0 :         os << "|E";
     196             :       }
     197         116 :       switch (allocated.representation()) {
     198             :         case MachineRepresentation::kNone:
     199           0 :           os << "|-";
     200           0 :           break;
     201             :         case MachineRepresentation::kBit:
     202           0 :           os << "|b";
     203           0 :           break;
     204             :         case MachineRepresentation::kWord8:
     205           0 :           os << "|w8";
     206           0 :           break;
     207             :         case MachineRepresentation::kWord16:
     208           0 :           os << "|w16";
     209           0 :           break;
     210             :         case MachineRepresentation::kWord32:
     211           7 :           os << "|w32";
     212           7 :           break;
     213             :         case MachineRepresentation::kWord64:
     214          48 :           os << "|w64";
     215          48 :           break;
     216             :         case MachineRepresentation::kFloat32:
     217           0 :           os << "|f32";
     218           0 :           break;
     219             :         case MachineRepresentation::kFloat64:
     220           2 :           os << "|f64";
     221           2 :           break;
     222             :         case MachineRepresentation::kSimd128:
     223           0 :           os << "|s128";
     224           0 :           break;
     225             :         case MachineRepresentation::kTaggedSigned:
     226           0 :           os << "|ts";
     227           0 :           break;
     228             :         case MachineRepresentation::kTaggedPointer:
     229           4 :           os << "|tp";
     230           4 :           break;
     231             :         case MachineRepresentation::kTagged:
     232          55 :           os << "|t";
     233          55 :           break;
     234             :         case MachineRepresentation::kCompressedSigned:
     235           0 :           os << "|cs";
     236           0 :           break;
     237             :         case MachineRepresentation::kCompressedPointer:
     238           0 :           os << "|cp";
     239           0 :           break;
     240             :         case MachineRepresentation::kCompressed:
     241           0 :           os << "|c";
     242           0 :           break;
     243             :       }
     244             :       return os << "]";
     245             :     }
     246             :     case InstructionOperand::INVALID:
     247           0 :       return os << "(x)";
     248             :   }
     249           0 :   UNREACHABLE();
     250             : }
     251             : 
     252           0 : void MoveOperands::Print() const {
     253           0 :   StdoutStream{} << destination() << " = " << source() << std::endl;
     254           0 : }
     255             : 
     256          36 : std::ostream& operator<<(std::ostream& os, const MoveOperands& mo) {
     257          36 :   os << mo.destination();
     258          36 :   if (!mo.source().Equals(mo.destination())) {
     259          36 :     os << " = " << mo.source();
     260             :   }
     261          36 :   return os << ";";
     262             : }
     263             : 
     264           0 : bool ParallelMove::IsRedundant() const {
     265    40790515 :   for (MoveOperands* move : *this) {
     266    22648129 :     if (!move->IsRedundant()) return false;
     267             :   }
     268             :   return true;
     269             : }
     270             : 
     271    14863036 : void ParallelMove::PrepareInsertAfter(
     272             :     MoveOperands* move, ZoneVector<MoveOperands*>* to_eliminate) const {
     273             :   bool no_aliasing =
     274             :       kSimpleFPAliasing || !move->destination().IsFPLocationOperand();
     275             :   MoveOperands* replacement = nullptr;
     276             :   MoveOperands* eliminated = nullptr;
     277    38818838 :   for (MoveOperands* curr : *this) {
     278    23965128 :     if (curr->IsEliminated()) continue;
     279    23672405 :     if (curr->destination().EqualsCanonicalized(move->source())) {
     280             :       // We must replace move's source with curr's destination in order to
     281             :       // insert it into this ParallelMove.
     282             :       DCHECK(!replacement);
     283             :       replacement = curr;
     284     1682854 :       if (no_aliasing && eliminated != nullptr) break;
     285    21989561 :     } else if (curr->destination().InterferesWith(move->destination())) {
     286             :       // We can eliminate curr, since move overwrites at least a part of its
     287             :       // destination, implying its value is no longer live.
     288             :       eliminated = curr;
     289      257578 :       to_eliminate->push_back(curr);
     290      257580 :       if (no_aliasing && replacement != nullptr) break;
     291             :     }
     292             :   }
     293    14863055 :   if (replacement != nullptr) move->set_source(replacement->source());
     294    14863055 : }
     295             : 
     296      710598 : ExplicitOperand::ExplicitOperand(LocationKind kind, MachineRepresentation rep,
     297             :                                  int index)
     298             :     : LocationOperand(EXPLICIT, kind, rep, index) {
     299             :   DCHECK_IMPLIES(kind == REGISTER && !IsFloatingPoint(rep),
     300             :                  GetRegConfig()->IsAllocatableGeneralCode(index));
     301             :   DCHECK_IMPLIES(kind == REGISTER && rep == MachineRepresentation::kFloat32,
     302             :                  GetRegConfig()->IsAllocatableFloatCode(index));
     303             :   DCHECK_IMPLIES(kind == REGISTER && (rep == MachineRepresentation::kFloat64),
     304             :                  GetRegConfig()->IsAllocatableDoubleCode(index));
     305      710598 : }
     306             : 
     307           0 : Instruction::Instruction(InstructionCode opcode)
     308             :     : opcode_(opcode),
     309             :       bit_field_(OutputCountField::encode(0) | InputCountField::encode(0) |
     310             :                  TempCountField::encode(0) | IsCallField::encode(false)),
     311             :       reference_map_(nullptr),
     312           0 :       block_(nullptr) {
     313           0 :   parallel_moves_[0] = nullptr;
     314           0 :   parallel_moves_[1] = nullptr;
     315           0 : }
     316             : 
     317    69647578 : Instruction::Instruction(InstructionCode opcode, size_t output_count,
     318             :                          InstructionOperand* outputs, size_t input_count,
     319             :                          InstructionOperand* inputs, size_t temp_count,
     320             :                          InstructionOperand* temps)
     321             :     : opcode_(opcode),
     322    69647578 :       bit_field_(OutputCountField::encode(output_count) |
     323    69647578 :                  InputCountField::encode(input_count) |
     324             :                  TempCountField::encode(temp_count) |
     325             :                  IsCallField::encode(false)),
     326             :       reference_map_(nullptr),
     327   208941823 :       block_(nullptr) {
     328    69647578 :   parallel_moves_[0] = nullptr;
     329    69647578 :   parallel_moves_[1] = nullptr;
     330             :   size_t offset = 0;
     331   150016716 :   for (size_t i = 0; i < output_count; ++i) {
     332             :     DCHECK(!outputs[i].IsInvalid());
     333    40184569 :     operands_[offset++] = outputs[i];
     334             :   }
     335   349833442 :   for (size_t i = 0; i < input_count; ++i) {
     336             :     DCHECK(!inputs[i].IsInvalid());
     337   140092932 :     operands_[offset++] = inputs[i];
     338             :   }
     339    71169256 :   for (size_t i = 0; i < temp_count; ++i) {
     340             :     DCHECK(!temps[i].IsInvalid());
     341      760839 :     operands_[offset++] = temps[i];
     342             :   }
     343    69647578 : }
     344             : 
     345    59747339 : bool Instruction::AreMovesRedundant() const {
     346   105037934 :   for (int i = Instruction::FIRST_GAP_POSITION;
     347   164785273 :        i <= Instruction::LAST_GAP_POSITION; i++) {
     348   137618076 :     if (parallel_moves_[i] != nullptr && !parallel_moves_[i]->IsRedundant()) {
     349             :       return false;
     350             :     }
     351             :   }
     352             :   return true;
     353             : }
     354             : 
     355           0 : void Instruction::Print() const { StdoutStream{} << *this << std::endl; }
     356             : 
     357          53 : std::ostream& operator<<(std::ostream& os, const ParallelMove& pm) {
     358             :   const char* space = "";
     359          97 :   for (MoveOperands* move : pm) {
     360          44 :     if (move->IsEliminated()) continue;
     361          36 :     os << space << *move;
     362             :     space = " ";
     363             :   }
     364          53 :   return os;
     365             : }
     366             : 
     367    39508478 : void ReferenceMap::RecordReference(const AllocatedOperand& op) {
     368             :   // Do not record arguments as pointers.
     369    63588930 :   if (op.IsStackSlot() && LocationOperand::cast(op).index() < 0) return;
     370             :   DCHECK(!op.IsFPRegister() && !op.IsFPStackSlot());
     371    31744711 :   reference_operands_.push_back(op);
     372             : }
     373             : 
     374           0 : std::ostream& operator<<(std::ostream& os, const ReferenceMap& pm) {
     375           0 :   os << "{";
     376             :   const char* separator = "";
     377           0 :   for (const InstructionOperand& op : pm.reference_operands_) {
     378           0 :     os << separator << op;
     379             :     separator = ";";
     380             :   }
     381           0 :   return os << "}";
     382             : }
     383             : 
     384         205 : std::ostream& operator<<(std::ostream& os, const ArchOpcode& ao) {
     385         205 :   switch (ao) {
     386             : #define CASE(Name) \
     387             :   case k##Name:    \
     388             :     return os << #Name;
     389         205 :     ARCH_OPCODE_LIST(CASE)
     390             : #undef CASE
     391             :   }
     392           0 :   UNREACHABLE();
     393             : }
     394             : 
     395          45 : std::ostream& operator<<(std::ostream& os, const AddressingMode& am) {
     396          45 :   switch (am) {
     397             :     case kMode_None:
     398             :       return os;
     399             : #define CASE(Name)   \
     400             :   case kMode_##Name: \
     401             :     return os << #Name;
     402          45 :       TARGET_ADDRESSING_MODE_LIST(CASE)
     403             : #undef CASE
     404             :   }
     405           0 :   UNREACHABLE();
     406             : }
     407             : 
     408          30 : std::ostream& operator<<(std::ostream& os, const FlagsMode& fm) {
     409          30 :   switch (fm) {
     410             :     case kFlags_none:
     411             :       return os;
     412             :     case kFlags_branch:
     413          15 :       return os << "branch";
     414             :     case kFlags_branch_and_poison:
     415           0 :       return os << "branch_and_poison";
     416             :     case kFlags_deoptimize:
     417          15 :       return os << "deoptimize";
     418             :     case kFlags_deoptimize_and_poison:
     419           0 :       return os << "deoptimize_and_poison";
     420             :     case kFlags_set:
     421           0 :       return os << "set";
     422             :     case kFlags_trap:
     423           0 :       return os << "trap";
     424             :   }
     425           0 :   UNREACHABLE();
     426             : }
     427             : 
     428          30 : std::ostream& operator<<(std::ostream& os, const FlagsCondition& fc) {
     429          30 :   switch (fc) {
     430             :     case kEqual:
     431           0 :       return os << "equal";
     432             :     case kNotEqual:
     433          10 :       return os << "not equal";
     434             :     case kSignedLessThan:
     435           0 :       return os << "signed less than";
     436             :     case kSignedGreaterThanOrEqual:
     437           0 :       return os << "signed greater than or equal";
     438             :     case kSignedLessThanOrEqual:
     439           0 :       return os << "signed less than or equal";
     440             :     case kSignedGreaterThan:
     441           0 :       return os << "signed greater than";
     442             :     case kUnsignedLessThan:
     443           0 :       return os << "unsigned less than";
     444             :     case kUnsignedGreaterThanOrEqual:
     445           0 :       return os << "unsigned greater than or equal";
     446             :     case kUnsignedLessThanOrEqual:
     447           0 :       return os << "unsigned less than or equal";
     448             :     case kUnsignedGreaterThan:
     449          10 :       return os << "unsigned greater than";
     450             :     case kFloatLessThanOrUnordered:
     451           0 :       return os << "less than or unordered (FP)";
     452             :     case kFloatGreaterThanOrEqual:
     453           0 :       return os << "greater than or equal (FP)";
     454             :     case kFloatLessThanOrEqual:
     455           0 :       return os << "less than or equal (FP)";
     456             :     case kFloatGreaterThanOrUnordered:
     457           0 :       return os << "greater than or unordered (FP)";
     458             :     case kFloatLessThan:
     459           0 :       return os << "less than (FP)";
     460             :     case kFloatGreaterThanOrEqualOrUnordered:
     461           0 :       return os << "greater than, equal or unordered (FP)";
     462             :     case kFloatLessThanOrEqualOrUnordered:
     463           0 :       return os << "less than, equal or unordered (FP)";
     464             :     case kFloatGreaterThan:
     465           0 :       return os << "greater than (FP)";
     466             :     case kUnorderedEqual:
     467           0 :       return os << "unordered equal";
     468             :     case kUnorderedNotEqual:
     469           0 :       return os << "unordered not equal";
     470             :     case kOverflow:
     471          10 :       return os << "overflow";
     472             :     case kNotOverflow:
     473           0 :       return os << "not overflow";
     474             :     case kPositiveOrZero:
     475           0 :       return os << "positive or zero";
     476             :     case kNegative:
     477           0 :       return os << "negative";
     478             :   }
     479           0 :   UNREACHABLE();
     480             : }
     481             : 
     482         123 : std::ostream& operator<<(std::ostream& os, const Instruction& instr) {
     483         123 :   os << "gap ";
     484         246 :   for (int i = Instruction::FIRST_GAP_POSITION;
     485         369 :        i <= Instruction::LAST_GAP_POSITION; i++) {
     486         246 :     os << "(";
     487         246 :     if (instr.parallel_moves()[i] != nullptr) {
     488          53 :       os << *instr.parallel_moves()[i];
     489             :     }
     490         246 :     os << ") ";
     491             :   }
     492         123 :   os << "\n          ";
     493             : 
     494         123 :   if (instr.OutputCount() == 1) {
     495          81 :     os << *instr.OutputAt(0) << " = ";
     496          42 :   } else if (instr.OutputCount() > 1) {
     497           0 :     os << "(" << *instr.OutputAt(0);
     498           0 :     for (size_t i = 1; i < instr.OutputCount(); i++) {
     499           0 :       os << ", " << *instr.OutputAt(i);
     500             :     }
     501           0 :     os << ") = ";
     502             :   }
     503             : 
     504         246 :   os << ArchOpcodeField::decode(instr.opcode());
     505         123 :   AddressingMode am = AddressingModeField::decode(instr.opcode());
     506         123 :   if (am != kMode_None) {
     507          54 :     os << " : " << AddressingModeField::decode(instr.opcode());
     508             :   }
     509         246 :   FlagsMode fm = FlagsModeField::decode(instr.opcode());
     510         123 :   if (fm != kFlags_none) {
     511          54 :     os << " && " << fm << " if " << FlagsConditionField::decode(instr.opcode());
     512             :   }
     513         627 :   for (size_t i = 0; i < instr.InputCount(); i++) {
     514         252 :     os << " " << *instr.InputAt(i);
     515             :   }
     516         123 :   return os;
     517             : }
     518             : 
     519    41093371 : Constant::Constant(int32_t v) : type_(kInt32), value_(v) {}
     520             : 
     521       93123 : Constant::Constant(RelocatablePtrConstantInfo info) {
     522       93123 :   if (info.type() == RelocatablePtrConstantInfo::kInt32) {
     523           0 :     type_ = kInt32;
     524       93123 :   } else if (info.type() == RelocatablePtrConstantInfo::kInt64) {
     525       93123 :     type_ = kInt64;
     526             :   } else {
     527           0 :     UNREACHABLE();
     528             :   }
     529       93123 :   value_ = info.value();
     530       93123 :   rmode_ = info.rmode();
     531       93123 : }
     532             : 
     533    14397100 : Handle<HeapObject> Constant::ToHeapObject() const {
     534             :   DCHECK_EQ(kHeapObject, type());
     535             :   Handle<HeapObject> value(
     536    14397134 :       reinterpret_cast<Address*>(static_cast<intptr_t>(value_)));
     537    14397100 :   return value;
     538             : }
     539             : 
     540     4794123 : Handle<Code> Constant::ToCode() const {
     541             :   DCHECK_EQ(kHeapObject, type());
     542     4794123 :   Handle<Code> value(reinterpret_cast<Address*>(static_cast<intptr_t>(value_)));
     543     4794123 :   return value;
     544             : }
     545             : 
     546        4592 : const StringConstantBase* Constant::ToDelayedStringConstant() const {
     547             :   DCHECK_EQ(kDelayedStringConstant, type());
     548             :   const StringConstantBase* value =
     549        4592 :       bit_cast<StringConstantBase*>(static_cast<intptr_t>(value_));
     550        4592 :   return value;
     551             : }
     552             : 
     553         140 : std::ostream& operator<<(std::ostream& os, const Constant& constant) {
     554         140 :   switch (constant.type()) {
     555             :     case Constant::kInt32:
     556           5 :       return os << constant.ToInt32();
     557             :     case Constant::kInt64:
     558          37 :       return os << constant.ToInt64() << "l";
     559             :     case Constant::kFloat32:
     560           0 :       return os << constant.ToFloat32() << "f";
     561             :     case Constant::kFloat64:
     562             :       return os << constant.ToFloat64().value();
     563             :     case Constant::kExternalReference:
     564             :       return os << constant.ToExternalReference().address();
     565             :     case Constant::kHeapObject:
     566          34 :       return os << Brief(*constant.ToHeapObject());
     567             :     case Constant::kRpoNumber:
     568          48 :       return os << "RPO" << constant.ToRpoNumber().ToInt();
     569             :     case Constant::kDelayedStringConstant:
     570             :       return os << "DelayedStringConstant: "
     571           0 :                 << constant.ToDelayedStringConstant();
     572             :   }
     573           0 :   UNREACHABLE();
     574             : }
     575             : 
     576     2161875 : PhiInstruction::PhiInstruction(Zone* zone, int virtual_register,
     577             :                                size_t input_count)
     578             :     : virtual_register_(virtual_register),
     579             :       output_(UnallocatedOperand(UnallocatedOperand::NONE, virtual_register)),
     580             :       operands_(input_count, InstructionOperand::kInvalidVirtualRegister,
     581     6485629 :                 zone) {}
     582             : 
     583     5216544 : void PhiInstruction::SetInput(size_t offset, int virtual_register) {
     584             :   DCHECK_EQ(InstructionOperand::kInvalidVirtualRegister, operands_[offset]);
     585     5216544 :   operands_[offset] = virtual_register;
     586     5216544 : }
     587             : 
     588      296376 : void PhiInstruction::RenameInput(size_t offset, int virtual_register) {
     589             :   DCHECK_NE(InstructionOperand::kInvalidVirtualRegister, operands_[offset]);
     590      296376 :   operands_[offset] = virtual_register;
     591      296376 : }
     592             : 
     593        7395 : InstructionBlock::InstructionBlock(Zone* zone, RpoNumber rpo_number,
     594             :                                    RpoNumber loop_header, RpoNumber loop_end,
     595             :                                    bool deferred, bool handler)
     596             :     : successors_(zone),
     597             :       predecessors_(zone),
     598             :       phis_(zone),
     599             :       ao_number_(RpoNumber::Invalid()),
     600             :       rpo_number_(rpo_number),
     601             :       loop_header_(loop_header),
     602             :       loop_end_(loop_end),
     603             :       deferred_(deferred),
     604    20315931 :       handler_(handler) {}
     605             : 
     606    23576925 : size_t InstructionBlock::PredecessorIndexOf(RpoNumber rpo_number) const {
     607             :   size_t j = 0;
     608  1669545707 :   for (InstructionBlock::Predecessors::const_iterator i = predecessors_.begin();
     609             :        i != predecessors_.end(); ++i, ++j) {
     610   847043652 :     if (*i == rpo_number) break;
     611             :   }
     612    23576925 :   return j;
     613             : }
     614             : 
     615             : static RpoNumber GetRpo(const BasicBlock* block) {
     616    67932693 :   if (block == nullptr) return RpoNumber::Invalid();
     617             :   return RpoNumber::FromInt(block->rpo_number());
     618             : }
     619             : 
     620             : static RpoNumber GetLoopEndRpo(const BasicBlock* block) {
     621    20307867 :   if (!block->IsLoopHeader()) return RpoNumber::Invalid();
     622             :   return RpoNumber::FromInt(block->loop_end()->rpo_number());
     623             : }
     624             : 
     625    20307867 : static InstructionBlock* InstructionBlockFor(Zone* zone,
     626             :                                              const BasicBlock* block) {
     627             :   bool is_handler =
     628    40424560 :       !block->empty() && block->front()->opcode() == IrOpcode::kIfException;
     629             :   InstructionBlock* instr_block = new (zone)
     630             :       InstructionBlock(zone, GetRpo(block), GetRpo(block->loop_header()),
     631             :                        GetLoopEndRpo(block), block->deferred(), is_handler);
     632             :   // Map successors and precessors
     633    20308536 :   instr_block->successors().reserve(block->SuccessorCount());
     634    44121341 :   for (BasicBlock* successor : block->successors()) {
     635    47623819 :     instr_block->successors().push_back(GetRpo(successor));
     636             :   }
     637    20309661 :   instr_block->predecessors().reserve(block->PredecessorCount());
     638    44123034 :   for (BasicBlock* predecessor : block->predecessors()) {
     639    47626399 :     instr_block->predecessors().push_back(GetRpo(predecessor));
     640             :   }
     641    34322303 :   if (block->PredecessorCount() == 1 &&
     642    14012415 :       block->predecessors()[0]->control() == BasicBlock::Control::kSwitch) {
     643             :     instr_block->set_switch_target(true);
     644             :   }
     645    20309888 :   return instr_block;
     646             : }
     647             : 
     648          20 : std::ostream& operator<<(std::ostream& os,
     649             :                          const PrintableInstructionBlock& printable_block) {
     650          20 :   const InstructionBlock* block = printable_block.block_;
     651          20 :   const InstructionSequence* code = printable_block.code_;
     652             : 
     653             :   os << "B" << block->rpo_number();
     654             :   os << ": AO#" << block->ao_number();
     655          20 :   if (block->IsDeferred()) os << " (deferred)";
     656          20 :   if (!block->needs_frame()) os << " (no frame)";
     657          20 :   if (block->must_construct_frame()) os << " (construct frame)";
     658          20 :   if (block->must_deconstruct_frame()) os << " (deconstruct frame)";
     659          20 :   if (block->IsLoopHeader()) {
     660             :     os << " loop blocks: [" << block->rpo_number() << ", " << block->loop_end()
     661           0 :        << ")";
     662             :   }
     663          40 :   os << "  instructions: [" << block->code_start() << ", " << block->code_end()
     664             :      << ")" << std::endl
     665          20 :      << " predecessors:";
     666             : 
     667          44 :   for (RpoNumber pred : block->predecessors()) {
     668          24 :     os << " B" << pred.ToInt();
     669             :   }
     670             :   os << std::endl;
     671             : 
     672          22 :   for (const PhiInstruction* phi : block->phis()) {
     673           2 :     os << "     phi: " << phi->output() << " =";
     674           6 :     for (int input : phi->operands()) {
     675           4 :       os << " v" << input;
     676             :     }
     677             :     os << std::endl;
     678             :   }
     679             : 
     680         184 :   for (int j = block->first_instruction_index();
     681             :        j <= block->last_instruction_index(); j++) {
     682         164 :     os << "   " << std::setw(5) << j << ": " << *code->InstructionAt(j)
     683             :        << std::endl;
     684             :   }
     685             : 
     686          20 :   os << " successors:";
     687          44 :   for (RpoNumber succ : block->successors()) {
     688          24 :     os << " B" << succ.ToInt();
     689             :   }
     690             :   os << std::endl;
     691          20 :   return os;
     692             : }
     693             : 
     694     2515227 : InstructionBlocks* InstructionSequence::InstructionBlocksFor(
     695             :     Zone* zone, const Schedule* schedule) {
     696             :   InstructionBlocks* blocks = zone->NewArray<InstructionBlocks>(1);
     697             :   new (blocks) InstructionBlocks(
     698     2517818 :       static_cast<int>(schedule->rpo_order()->size()), nullptr, zone);
     699             :   size_t rpo_number = 0;
     700    43135827 :   for (BasicBlockVector::const_iterator it = schedule->rpo_order()->begin();
     701             :        it != schedule->rpo_order()->end(); ++it, ++rpo_number) {
     702             :     DCHECK(!(*blocks)[rpo_number]);
     703             :     DCHECK(GetRpo(*it).ToSize() == rpo_number);
     704    20308537 :     (*blocks)[rpo_number] = InstructionBlockFor(zone, *it);
     705             :   }
     706     2517737 :   return blocks;
     707             : }
     708             : 
     709           0 : void InstructionSequence::ValidateEdgeSplitForm() const {
     710             :   // Validate blocks are in edge-split form: no block with multiple successors
     711             :   // has an edge to a block (== a successor) with more than one predecessors.
     712           0 :   for (const InstructionBlock* block : instruction_blocks()) {
     713           0 :     if (block->SuccessorCount() > 1) {
     714           0 :       for (const RpoNumber& successor_id : block->successors()) {
     715           0 :         const InstructionBlock* successor = InstructionBlockAt(successor_id);
     716             :         // Expect precisely one predecessor: "block".
     717           0 :         CHECK(successor->PredecessorCount() == 1 &&
     718             :               successor->predecessors()[0] == block->rpo_number());
     719             :       }
     720             :     }
     721             :   }
     722           0 : }
     723             : 
     724           0 : void InstructionSequence::ValidateDeferredBlockExitPaths() const {
     725             :   // A deferred block with more than one successor must have all its successors
     726             :   // deferred.
     727           0 :   for (const InstructionBlock* block : instruction_blocks()) {
     728           0 :     if (!block->IsDeferred() || block->SuccessorCount() <= 1) continue;
     729           0 :     for (RpoNumber successor_id : block->successors()) {
     730           0 :       CHECK(InstructionBlockAt(successor_id)->IsDeferred());
     731             :     }
     732             :   }
     733           0 : }
     734             : 
     735           0 : void InstructionSequence::ValidateDeferredBlockEntryPaths() const {
     736             :   // If a deferred block has multiple predecessors, they have to
     737             :   // all be deferred. Otherwise, we can run into a situation where a range
     738             :   // that spills only in deferred blocks inserts its spill in the block, but
     739             :   // other ranges need moves inserted by ResolveControlFlow in the predecessors,
     740             :   // which may clobber the register of this range.
     741           0 :   for (const InstructionBlock* block : instruction_blocks()) {
     742           0 :     if (!block->IsDeferred() || block->PredecessorCount() <= 1) continue;
     743           0 :     for (RpoNumber predecessor_id : block->predecessors()) {
     744           0 :       CHECK(InstructionBlockAt(predecessor_id)->IsDeferred());
     745             :     }
     746             :   }
     747           0 : }
     748             : 
     749           0 : void InstructionSequence::ValidateSSA() const {
     750             :   // TODO(mtrofin): We could use a local zone here instead.
     751           0 :   BitVector definitions(VirtualRegisterCount(), zone());
     752           0 :   for (const Instruction* instruction : *this) {
     753           0 :     for (size_t i = 0; i < instruction->OutputCount(); ++i) {
     754             :       const InstructionOperand* output = instruction->OutputAt(i);
     755             :       int vreg = (output->IsConstant())
     756             :                      ? ConstantOperand::cast(output)->virtual_register()
     757           0 :                      : UnallocatedOperand::cast(output)->virtual_register();
     758           0 :       CHECK(!definitions.Contains(vreg));
     759             :       definitions.Add(vreg);
     760             :     }
     761             :   }
     762           0 : }
     763             : 
     764     2517433 : void InstructionSequence::ComputeAssemblyOrder() {
     765             :   int ao = 0;
     766             :   RpoNumber invalid = RpoNumber::Invalid();
     767             : 
     768     2517555 :   ao_blocks_ = zone()->NewArray<InstructionBlocks>(1);
     769     2517555 :   new (ao_blocks_) InstructionBlocks(zone());
     770     5035110 :   ao_blocks_->reserve(instruction_blocks_->size());
     771             : 
     772             :   // Place non-deferred blocks.
     773    25348413 :   for (InstructionBlock* const block : *instruction_blocks_) {
     774             :     DCHECK_NOT_NULL(block);
     775    20310466 :     if (block->IsDeferred()) continue;            // skip deferred blocks.
     776    15470986 :     if (block->ao_number() != invalid) continue;  // loop rotated.
     777    15275918 :     if (block->IsLoopHeader()) {
     778             :       bool header_align = true;
     779      205951 :       if (FLAG_turbo_loop_rotation) {
     780             :         // Perform loop rotation for non-deferred loops.
     781             :         InstructionBlock* loop_end =
     782      411902 :             instruction_blocks_->at(block->loop_end().ToSize() - 1);
     783      205951 :         if (loop_end->SuccessorCount() == 1 && /* ends with goto */
     784             :             loop_end != block /* not a degenerate infinite loop */) {
     785             :           // If the last block has an unconditional jump back to the header,
     786             :           // then move it to be in front of the header in the assembly order.
     787             :           DCHECK_EQ(block->rpo_number(), loop_end->successors()[0]);
     788      205931 :           loop_end->set_ao_number(RpoNumber::FromInt(ao++));
     789      205931 :           ao_blocks_->push_back(loop_end);
     790             :           // This block will be the new machine-level loop header, so align
     791             :           // this block instead of the loop header block.
     792      205931 :           loop_end->set_alignment(true);
     793             :           header_align = false;
     794             :         }
     795             :       }
     796      205951 :       block->set_alignment(header_align);
     797             :     }
     798    15275918 :     if (block->loop_header().IsValid() && block->IsSwitchTarget()) {
     799             :       block->set_alignment(true);
     800             :     }
     801    15275918 :     block->set_ao_number(RpoNumber::FromInt(ao++));
     802    15275918 :     ao_blocks_->push_back(block);
     803             :   }
     804             :   // Add all leftover (deferred) blocks.
     805    25349848 :   for (InstructionBlock* const block : *instruction_blocks_) {
     806    20311612 :     if (block->ao_number() == invalid) {
     807     4829168 :       block->set_ao_number(RpoNumber::FromInt(ao++));
     808     4829168 :       ao_blocks_->push_back(block);
     809             :     }
     810             :   }
     811             :   DCHECK_EQ(instruction_blocks_->size(), ao);
     812     2519156 : }
     813             : 
     814          35 : void InstructionSequence::RecomputeAssemblyOrderForTesting() {
     815             :   RpoNumber invalid = RpoNumber::Invalid();
     816         225 :   for (InstructionBlock* block : *instruction_blocks_) {
     817             :     block->set_ao_number(invalid);
     818             :   }
     819          35 :   ComputeAssemblyOrder();
     820          35 : }
     821             : 
     822     2516453 : InstructionSequence::InstructionSequence(Isolate* isolate,
     823             :                                          Zone* instruction_zone,
     824             :                                          InstructionBlocks* instruction_blocks)
     825             :     : isolate_(isolate),
     826             :       zone_(instruction_zone),
     827             :       instruction_blocks_(instruction_blocks),
     828             :       ao_blocks_(nullptr),
     829             :       source_positions_(zone()),
     830             :       constants_(ConstantMap::key_compare(),
     831             :                  ConstantMap::allocator_type(zone())),
     832             :       immediates_(zone()),
     833             :       instructions_(zone()),
     834             :       next_virtual_register_(0),
     835             :       reference_maps_(zone()),
     836             :       representations_(zone()),
     837             :       representation_mask_(0),
     838             :       deoptimization_entries_(zone()),
     839    10071320 :       current_block_(nullptr) {
     840     2518533 :   ComputeAssemblyOrder();
     841     2519116 : }
     842             : 
     843    46323364 : int InstructionSequence::NextVirtualRegister() {
     844    46323364 :   int virtual_register = next_virtual_register_++;
     845    46323364 :   CHECK_NE(virtual_register, InstructionOperand::kInvalidVirtualRegister);
     846    46323364 :   return virtual_register;
     847             : }
     848             : 
     849           0 : Instruction* InstructionSequence::GetBlockStart(RpoNumber rpo) const {
     850           0 :   const InstructionBlock* block = InstructionBlockAt(rpo);
     851           0 :   return InstructionAt(block->code_start());
     852             : }
     853             : 
     854    20316631 : void InstructionSequence::StartBlock(RpoNumber rpo) {
     855             :   DCHECK_NULL(current_block_);
     856    20316631 :   current_block_ = InstructionBlockAt(rpo);
     857    20316762 :   int code_start = static_cast<int>(instructions_.size());
     858             :   current_block_->set_code_start(code_start);
     859    20316762 : }
     860             : 
     861    20318277 : void InstructionSequence::EndBlock(RpoNumber rpo) {
     862    20318277 :   int end = static_cast<int>(instructions_.size());
     863             :   DCHECK_EQ(current_block_->rpo_number(), rpo);
     864    20318277 :   CHECK(current_block_->code_start() >= 0 &&
     865             :         current_block_->code_start() < end);
     866             :   current_block_->set_code_end(end);
     867    20318277 :   current_block_ = nullptr;
     868    20318277 : }
     869             : 
     870    69649433 : int InstructionSequence::AddInstruction(Instruction* instr) {
     871             :   DCHECK_NOT_NULL(current_block_);
     872    69649433 :   int index = static_cast<int>(instructions_.size());
     873    69649433 :   instr->set_block(current_block_);
     874    69649433 :   instructions_.push_back(instr);
     875   139298754 :   if (instr->NeedsReferenceMap()) {
     876             :     DCHECK_NULL(instr->reference_map());
     877     6164415 :     ReferenceMap* reference_map = new (zone()) ReferenceMap(zone());
     878             :     reference_map->set_instruction_position(index);
     879     6164415 :     instr->set_reference_map(reference_map);
     880     6164415 :     reference_maps_.push_back(reference_map);
     881             :   }
     882    69649320 :   return index;
     883             : }
     884             : 
     885   174299667 : InstructionBlock* InstructionSequence::GetInstructionBlock(
     886             :     int instruction_index) const {
     887   174302719 :   return instructions()[instruction_index]->block();
     888             : }
     889             : 
     890             : static MachineRepresentation FilterRepresentation(MachineRepresentation rep) {
     891    34548860 :   switch (rep) {
     892             :     case MachineRepresentation::kBit:
     893             :     case MachineRepresentation::kWord8:
     894             :     case MachineRepresentation::kWord16:
     895             :       return InstructionSequence::DefaultRepresentation();
     896             :     case MachineRepresentation::kWord32:
     897             :     case MachineRepresentation::kWord64:
     898             :     case MachineRepresentation::kTaggedSigned:
     899             :     case MachineRepresentation::kTaggedPointer:
     900             :     case MachineRepresentation::kTagged:
     901             :     case MachineRepresentation::kFloat32:
     902             :     case MachineRepresentation::kFloat64:
     903             :     case MachineRepresentation::kSimd128:
     904             :     case MachineRepresentation::kCompressedSigned:
     905             :     case MachineRepresentation::kCompressedPointer:
     906             :     case MachineRepresentation::kCompressed:
     907             :       return rep;
     908             :     case MachineRepresentation::kNone:
     909             :       break;
     910             :   }
     911             : 
     912           0 :   UNREACHABLE();
     913             : }
     914             : 
     915   171302507 : MachineRepresentation InstructionSequence::GetRepresentation(
     916             :     int virtual_register) const {
     917             :   DCHECK_LE(0, virtual_register);
     918             :   DCHECK_LT(virtual_register, VirtualRegisterCount());
     919   171302507 :   if (virtual_register >= static_cast<int>(representations_.size())) {
     920             :     return DefaultRepresentation();
     921             :   }
     922   330846798 :   return representations_[virtual_register];
     923             : }
     924             : 
     925    34548427 : void InstructionSequence::MarkAsRepresentation(MachineRepresentation rep,
     926             :                                                int virtual_register) {
     927             :   DCHECK_LE(0, virtual_register);
     928             :   DCHECK_LT(virtual_register, VirtualRegisterCount());
     929    34548427 :   if (virtual_register >= static_cast<int>(representations_.size())) {
     930    21126684 :     representations_.resize(VirtualRegisterCount(), DefaultRepresentation());
     931             :   }
     932             :   rep = FilterRepresentation(rep);
     933             :   DCHECK_IMPLIES(representations_[virtual_register] != rep,
     934             :                  representations_[virtual_register] == DefaultRepresentation());
     935    69097720 :   representations_[virtual_register] = rep;
     936    34548860 :   representation_mask_ |= RepresentationBit(rep);
     937    34548860 : }
     938             : 
     939     3600467 : int InstructionSequence::AddDeoptimizationEntry(
     940             :     FrameStateDescriptor* descriptor, DeoptimizeKind kind,
     941             :     DeoptimizeReason reason, VectorSlotPair const& feedback) {
     942     3600467 :   int deoptimization_id = static_cast<int>(deoptimization_entries_.size());
     943     7200951 :   deoptimization_entries_.push_back(
     944             :       DeoptimizationEntry(descriptor, kind, reason, feedback));
     945     3600484 :   return deoptimization_id;
     946             : }
     947             : 
     948     6825234 : DeoptimizationEntry const& InstructionSequence::GetDeoptimizationEntry(
     949             :     int state_id) {
     950    13650468 :   return deoptimization_entries_[state_id];
     951             : }
     952             : 
     953     6767969 : RpoNumber InstructionSequence::InputRpo(Instruction* instr, size_t index) {
     954             :   InstructionOperand* operand = instr->InputAt(index);
     955             :   Constant constant =
     956             :       operand->IsImmediate()
     957             :           ? GetImmediate(ImmediateOperand::cast(operand))
     958     6767969 :           : GetConstant(ConstantOperand::cast(operand)->virtual_register());
     959     6767990 :   return constant.ToRpoNumber();
     960             : }
     961             : 
     962    44301287 : bool InstructionSequence::GetSourcePosition(const Instruction* instr,
     963             :                                             SourcePosition* result) const {
     964             :   auto it = source_positions_.find(instr);
     965    44301287 :   if (it == source_positions_.end()) return false;
     966     4690148 :   *result = it->second;
     967     4690148 :   return true;
     968             : }
     969             : 
     970     4835522 : void InstructionSequence::SetSourcePosition(const Instruction* instr,
     971             :                                             SourcePosition value) {
     972     9671191 :   source_positions_.insert(std::make_pair(instr, value));
     973     4835669 : }
     974             : 
     975           0 : void InstructionSequence::Print() const {
     976           0 :   StdoutStream{} << *this << std::endl;
     977           0 : }
     978             : 
     979           0 : void InstructionSequence::PrintBlock(int block_id) const {
     980             :   RpoNumber rpo = RpoNumber::FromInt(block_id);
     981           0 :   const InstructionBlock* block = InstructionBlockAt(rpo);
     982           0 :   CHECK(block->rpo_number() == rpo);
     983           0 :   StdoutStream{} << PrintableInstructionBlock{block, this} << std::endl;
     984           0 : }
     985             : 
     986             : const RegisterConfiguration*
     987             :     InstructionSequence::registerConfigurationForTesting_ = nullptr;
     988             : 
     989             : const RegisterConfiguration*
     990           0 : InstructionSequence::RegisterConfigurationForTesting() {
     991             :   DCHECK_NOT_NULL(registerConfigurationForTesting_);
     992           0 :   return registerConfigurationForTesting_;
     993             : }
     994             : 
     995          52 : void InstructionSequence::SetRegisterConfigurationForTesting(
     996             :     const RegisterConfiguration* regConfig) {
     997          52 :   registerConfigurationForTesting_ = regConfig;
     998          52 :   GetRegConfig = InstructionSequence::RegisterConfigurationForTesting;
     999          52 : }
    1000             : 
    1001     3955882 : FrameStateDescriptor::FrameStateDescriptor(
    1002             :     Zone* zone, FrameStateType type, BailoutId bailout_id,
    1003             :     OutputFrameStateCombine state_combine, size_t parameters_count,
    1004             :     size_t locals_count, size_t stack_count,
    1005             :     MaybeHandle<SharedFunctionInfo> shared_info,
    1006             :     FrameStateDescriptor* outer_state)
    1007             :     : type_(type),
    1008             :       bailout_id_(bailout_id),
    1009             :       frame_state_combine_(state_combine),
    1010             :       parameters_count_(parameters_count),
    1011             :       locals_count_(locals_count),
    1012             :       stack_count_(stack_count),
    1013             :       values_(zone),
    1014             :       shared_info_(shared_info),
    1015     7911764 :       outer_state_(outer_state) {}
    1016             : 
    1017     7313467 : size_t FrameStateDescriptor::GetSize() const {
    1018    14626934 :   return 1 + parameters_count() + locals_count() + stack_count() +
    1019     7313467 :          (HasContext() ? 1 : 0);
    1020             : }
    1021             : 
    1022     3224791 : size_t FrameStateDescriptor::GetTotalSize() const {
    1023             :   size_t total_size = 0;
    1024     9940039 :   for (const FrameStateDescriptor* iter = this; iter != nullptr;
    1025             :        iter = iter->outer_state_) {
    1026     3357624 :     total_size += iter->GetSize();
    1027             :   }
    1028     3224791 :   return total_size;
    1029             : }
    1030             : 
    1031     3600466 : size_t FrameStateDescriptor::GetFrameCount() const {
    1032             :   size_t count = 0;
    1033    11512196 :   for (const FrameStateDescriptor* iter = this; iter != nullptr;
    1034             :        iter = iter->outer_state_) {
    1035     3955865 :     ++count;
    1036             :   }
    1037     3600466 :   return count;
    1038             : }
    1039             : 
    1040     3600464 : size_t FrameStateDescriptor::GetJSFrameCount() const {
    1041             :   size_t count = 0;
    1042    11512136 :   for (const FrameStateDescriptor* iter = this; iter != nullptr;
    1043             :        iter = iter->outer_state_) {
    1044     7911672 :     if (FrameStateFunctionInfo::IsJSFunctionType(iter->type_)) {
    1045     3843055 :       ++count;
    1046             :     }
    1047             :   }
    1048     3600464 :   return count;
    1049             : }
    1050             : 
    1051          30 : std::ostream& operator<<(std::ostream& os, const RpoNumber& rpo) {
    1052          30 :   return os << rpo.ToSize();
    1053             : }
    1054             : 
    1055           2 : std::ostream& operator<<(std::ostream& os, const InstructionSequence& code) {
    1056         106 :   for (size_t i = 0; i < code.immediates_.size(); ++i) {
    1057          52 :     Constant constant = code.immediates_[i];
    1058          52 :     os << "IMM#" << i << ": " << constant << "\n";
    1059             :   }
    1060             :   int i = 0;
    1061          30 :   for (ConstantMap::const_iterator it = code.constants_.begin();
    1062             :        it != code.constants_.end(); ++i, ++it) {
    1063          56 :     os << "CST#" << i << ": v" << it->first << " = " << it->second << "\n";
    1064             :   }
    1065          42 :   for (int i = 0; i < code.InstructionBlockCount(); i++) {
    1066          20 :     auto* block = code.InstructionBlockAt(RpoNumber::FromInt(i));
    1067          20 :     os << PrintableInstructionBlock{block, &code};
    1068             :   }
    1069           2 :   return os;
    1070             : }
    1071             : 
    1072             : }  // namespace compiler
    1073             : }  // namespace internal
    1074      120216 : }  // namespace v8

Generated by: LCOV version 1.10