LCOV - code coverage report
Current view: top level - src/crankshaft - lithium.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 175 267 65.5 %
Date: 2017-04-26 Functions: 32 41 78.0 %

          Line data    Source code
       1             : // Copyright 2012 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/crankshaft/lithium.h"
       6             : 
       7             : #include "src/ast/scopes.h"
       8             : #include "src/codegen.h"
       9             : #include "src/objects-inl.h"
      10             : 
      11             : #if V8_TARGET_ARCH_IA32
      12             : #include "src/crankshaft/ia32/lithium-ia32.h"  // NOLINT
      13             : #include "src/crankshaft/ia32/lithium-codegen-ia32.h"  // NOLINT
      14             : #elif V8_TARGET_ARCH_X64
      15             : #include "src/crankshaft/x64/lithium-x64.h"  // NOLINT
      16             : #include "src/crankshaft/x64/lithium-codegen-x64.h"  // NOLINT
      17             : #elif V8_TARGET_ARCH_ARM
      18             : #include "src/crankshaft/arm/lithium-arm.h"  // NOLINT
      19             : #include "src/crankshaft/arm/lithium-codegen-arm.h"  // NOLINT
      20             : #elif V8_TARGET_ARCH_PPC
      21             : #include "src/crankshaft/ppc/lithium-ppc.h"          // NOLINT
      22             : #include "src/crankshaft/ppc/lithium-codegen-ppc.h"  // NOLINT
      23             : #elif V8_TARGET_ARCH_MIPS
      24             : #include "src/crankshaft/mips/lithium-mips.h"  // NOLINT
      25             : #include "src/crankshaft/mips/lithium-codegen-mips.h"  // NOLINT
      26             : #elif V8_TARGET_ARCH_ARM64
      27             : #include "src/crankshaft/arm64/lithium-arm64.h"  // NOLINT
      28             : #include "src/crankshaft/arm64/lithium-codegen-arm64.h"  // NOLINT
      29             : #elif V8_TARGET_ARCH_MIPS64
      30             : #include "src/crankshaft/mips64/lithium-mips64.h"  // NOLINT
      31             : #include "src/crankshaft/mips64/lithium-codegen-mips64.h"  // NOLINT
      32             : #elif V8_TARGET_ARCH_X87
      33             : #include "src/crankshaft/x87/lithium-x87.h"  // NOLINT
      34             : #include "src/crankshaft/x87/lithium-codegen-x87.h"  // NOLINT
      35             : #elif V8_TARGET_ARCH_S390
      36             : #include "src/crankshaft/s390/lithium-s390.h"          // NOLINT
      37             : #include "src/crankshaft/s390/lithium-codegen-s390.h"  // NOLINT
      38             : #else
      39             : #error "Unknown architecture."
      40             : #endif
      41             : 
      42             : namespace v8 {
      43             : namespace internal {
      44             : 
      45             : const auto GetRegConfig = RegisterConfiguration::Crankshaft;
      46             : 
      47           0 : void LOperand::PrintTo(StringStream* stream) {
      48             :   LUnallocated* unalloc = NULL;
      49           0 :   switch (kind()) {
      50             :     case INVALID:
      51           0 :       stream->Add("(0)");
      52           0 :       break;
      53             :     case UNALLOCATED:
      54             :       unalloc = LUnallocated::cast(this);
      55           0 :       stream->Add("v%d", unalloc->virtual_register());
      56           0 :       if (unalloc->basic_policy() == LUnallocated::FIXED_SLOT) {
      57           0 :         stream->Add("(=%dS)", unalloc->fixed_slot_index());
      58           0 :         break;
      59             :       }
      60           0 :       switch (unalloc->extended_policy()) {
      61             :         case LUnallocated::NONE:
      62             :           break;
      63             :         case LUnallocated::FIXED_REGISTER: {
      64             :           int reg_index = unalloc->fixed_register_index();
      65           0 :           if (reg_index < 0 || reg_index >= Register::kNumRegisters) {
      66           0 :             stream->Add("(=invalid_reg#%d)", reg_index);
      67             :           } else {
      68             :             const char* register_name =
      69           0 :                 GetRegConfig()->GetGeneralRegisterName(reg_index);
      70           0 :             stream->Add("(=%s)", register_name);
      71             :           }
      72             :           break;
      73             :         }
      74             :         case LUnallocated::FIXED_DOUBLE_REGISTER: {
      75             :           int reg_index = unalloc->fixed_register_index();
      76           0 :           if (reg_index < 0 || reg_index >= DoubleRegister::kMaxNumRegisters) {
      77           0 :             stream->Add("(=invalid_double_reg#%d)", reg_index);
      78             :           } else {
      79             :             const char* double_register_name =
      80           0 :                 GetRegConfig()->GetDoubleRegisterName(reg_index);
      81           0 :             stream->Add("(=%s)", double_register_name);
      82             :           }
      83             :           break;
      84             :         }
      85             :         case LUnallocated::MUST_HAVE_REGISTER:
      86           0 :           stream->Add("(R)");
      87           0 :           break;
      88             :         case LUnallocated::MUST_HAVE_DOUBLE_REGISTER:
      89           0 :           stream->Add("(D)");
      90           0 :           break;
      91             :         case LUnallocated::WRITABLE_REGISTER:
      92           0 :           stream->Add("(WR)");
      93           0 :           break;
      94             :         case LUnallocated::SAME_AS_FIRST_INPUT:
      95           0 :           stream->Add("(1)");
      96           0 :           break;
      97             :         case LUnallocated::ANY:
      98           0 :           stream->Add("(-)");
      99           0 :           break;
     100             :       }
     101             :       break;
     102             :     case CONSTANT_OPERAND:
     103           0 :       stream->Add("[constant:%d]", index());
     104           0 :       break;
     105             :     case STACK_SLOT:
     106           0 :       stream->Add("[stack:%d]", index());
     107           0 :       break;
     108             :     case DOUBLE_STACK_SLOT:
     109           0 :       stream->Add("[double_stack:%d]", index());
     110           0 :       break;
     111             :     case REGISTER: {
     112             :       int reg_index = index();
     113           0 :       if (reg_index < 0 || reg_index >= Register::kNumRegisters) {
     114           0 :         stream->Add("(=invalid_reg#%d|R)", reg_index);
     115             :       } else {
     116             :         stream->Add("[%s|R]",
     117           0 :                     GetRegConfig()->GetGeneralRegisterName(reg_index));
     118             :       }
     119             :       break;
     120             :     }
     121             :     case DOUBLE_REGISTER: {
     122             :       int reg_index = index();
     123           0 :       if (reg_index < 0 || reg_index >= DoubleRegister::kMaxNumRegisters) {
     124           0 :         stream->Add("(=invalid_double_reg#%d|R)", reg_index);
     125             :       } else {
     126           0 :         stream->Add("[%s|R]", GetRegConfig()->GetDoubleRegisterName(reg_index));
     127             :       }
     128             :       break;
     129             :     }
     130             :   }
     131           0 : }
     132             : 
     133             : 
     134             : template<LOperand::Kind kOperandKind, int kNumCachedOperands>
     135             : LSubKindOperand<kOperandKind, kNumCachedOperands>*
     136             : LSubKindOperand<kOperandKind, kNumCachedOperands>::cache = NULL;
     137             : 
     138             : 
     139             : template<LOperand::Kind kOperandKind, int kNumCachedOperands>
     140      297305 : void LSubKindOperand<kOperandKind, kNumCachedOperands>::SetUpCache() {
     141      594610 :   if (cache) return;
     142    25033081 :   cache = new LSubKindOperand[kNumCachedOperands];
     143    25033081 :   for (int i = 0; i < kNumCachedOperands; i++) {
     144    24735776 :     cache[i].ConvertTo(kOperandKind, i);
     145             :   }
     146             : }
     147             : 
     148             : 
     149             : template<LOperand::Kind kOperandKind, int kNumCachedOperands>
     150             : void LSubKindOperand<kOperandKind, kNumCachedOperands>::TearDownCache() {
     151      162480 :   delete[] cache;
     152      162480 :   cache = NULL;
     153             : }
     154             : 
     155             : 
     156       59461 : void LOperand::SetUpCaches() {
     157             : #define LITHIUM_OPERAND_SETUP(name, type, number) L##name::SetUpCache();
     158       59461 :   LITHIUM_OPERAND_LIST(LITHIUM_OPERAND_SETUP)
     159             : #undef LITHIUM_OPERAND_SETUP
     160       59461 : }
     161             : 
     162             : 
     163       32496 : void LOperand::TearDownCaches() {
     164             : #define LITHIUM_OPERAND_TEARDOWN(name, type, number) L##name::TearDownCache();
     165             :   LITHIUM_OPERAND_LIST(LITHIUM_OPERAND_TEARDOWN)
     166             : #undef LITHIUM_OPERAND_TEARDOWN
     167       32496 : }
     168             : 
     169             : 
     170     8423519 : bool LParallelMove::IsRedundant() const {
     171    17151496 :   for (int i = 0; i < move_operands_.length(); ++i) {
     172     9572570 :     if (!move_operands_[i].IsRedundant()) return false;
     173             :   }
     174             :   return true;
     175             : }
     176             : 
     177             : 
     178           0 : void LParallelMove::PrintDataTo(StringStream* stream) const {
     179             :   bool first = true;
     180           0 :   for (int i = 0; i < move_operands_.length(); ++i) {
     181           0 :     if (!move_operands_[i].IsEliminated()) {
     182             :       LOperand* source = move_operands_[i].source();
     183           0 :       LOperand* destination = move_operands_[i].destination();
     184           0 :       if (!first) stream->Add(" ");
     185             :       first = false;
     186           0 :       if (source->Equals(destination)) {
     187           0 :         destination->PrintTo(stream);
     188             :       } else {
     189           0 :         destination->PrintTo(stream);
     190           0 :         stream->Add(" = ");
     191           0 :         source->PrintTo(stream);
     192             :       }
     193           0 :       stream->Add(";");
     194             :     }
     195             :   }
     196           0 : }
     197             : 
     198             : 
     199           0 : void LEnvironment::PrintTo(StringStream* stream) {
     200           0 :   stream->Add("[id=%d|", ast_id().ToInt());
     201           0 :   if (deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
     202           0 :     stream->Add("deopt_id=%d|", deoptimization_index());
     203             :   }
     204           0 :   stream->Add("parameters=%d|", parameter_count());
     205           0 :   stream->Add("arguments_stack_height=%d|", arguments_stack_height());
     206           0 :   for (int i = 0; i < values_.length(); ++i) {
     207           0 :     if (i != 0) stream->Add(";");
     208           0 :     if (values_[i] == NULL) {
     209           0 :       stream->Add("[hole]");
     210             :     } else {
     211           0 :       values_[i]->PrintTo(stream);
     212             :     }
     213             :   }
     214           0 :   stream->Add("]");
     215           0 : }
     216             : 
     217             : 
     218    13423120 : void LPointerMap::RecordPointer(LOperand* op, Zone* zone) {
     219             :   // Do not record arguments as pointers.
     220    35657359 :   if (op->IsStackSlot() && op->index() < 0) return;
     221             :   DCHECK(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
     222             :   pointer_operands_.Add(op, zone);
     223             : }
     224             : 
     225             : 
     226           0 : void LPointerMap::RemovePointer(LOperand* op) {
     227             :   // Do not record arguments as pointers.
     228           0 :   if (op->IsStackSlot() && op->index() < 0) return;
     229             :   DCHECK(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
     230           0 :   for (int i = 0; i < pointer_operands_.length(); ++i) {
     231           0 :     if (pointer_operands_[i]->Equals(op)) {
     232           0 :       pointer_operands_.Remove(i);
     233           0 :       --i;
     234             :     }
     235             :   }
     236             : }
     237             : 
     238             : 
     239           0 : void LPointerMap::RecordUntagged(LOperand* op, Zone* zone) {
     240             :   // Do not record arguments as pointers.
     241           0 :   if (op->IsStackSlot() && op->index() < 0) return;
     242             :   DCHECK(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
     243             :   untagged_operands_.Add(op, zone);
     244             : }
     245             : 
     246             : 
     247           0 : void LPointerMap::PrintTo(StringStream* stream) {
     248           0 :   stream->Add("{");
     249           0 :   for (int i = 0; i < pointer_operands_.length(); ++i) {
     250           0 :     if (i != 0) stream->Add(";");
     251           0 :     pointer_operands_[i]->PrintTo(stream);
     252             :   }
     253           0 :   stream->Add("}");
     254           0 : }
     255             : 
     256     1418630 : LChunk::LChunk(CompilationInfo* info, HGraph* graph)
     257             :     : base_frame_slots_(info->IsStub()
     258             :                             ? TypedFrameConstants::kFixedSlotCount
     259             :                             : StandardFrameConstants::kFixedSlotCount),
     260             :       current_frame_slots_(base_frame_slots_),
     261             :       info_(info),
     262             :       graph_(graph),
     263             :       instructions_(32, info->zone()),
     264             :       pointer_maps_(8, info->zone()),
     265             :       deprecation_dependencies_(32, info->zone()),
     266     1418630 :       stability_dependencies_(8, info->zone()) {}
     267             : 
     268     3022541 : LLabel* LChunk::GetLabel(int block_id) const {
     269    17528494 :   HBasicBlock* block = graph_->blocks()->at(block_id);
     270             :   int first_instruction = block->first_instruction_index();
     271    17528494 :   return LLabel::cast(instructions_[first_instruction]);
     272             : }
     273             : 
     274             : 
     275     2671547 : int LChunk::LookupDestination(int block_id) const {
     276     4862883 :   LLabel* cur = GetLabel(block_id);
     277     7534430 :   while (cur->replacement() != NULL) {
     278             :     cur = cur->replacement();
     279             :   }
     280     2671547 :   return cur->block_id();
     281             : }
     282             : 
     283     1075272 : Label* LChunk::GetAssemblyLabel(int block_id) const {
     284             :   LLabel* label = GetLabel(block_id);
     285             :   DCHECK(!label->HasReplacement());
     286     1075272 :   return label->label();
     287             : }
     288             : 
     289             : 
     290     5001548 : void LChunk::MarkEmptyBlocks() {
     291             :   LPhase phase("L_Mark empty blocks", this);
     292     9444926 :   for (int i = 0; i < graph()->blocks()->length(); ++i) {
     293     4443378 :     HBasicBlock* block = graph()->blocks()->at(i);
     294             :     int first = block->first_instruction_index();
     295             :     int last = block->last_instruction_index();
     296     4443378 :     LInstruction* first_instr = instructions()->at(first);
     297     4443378 :     LInstruction* last_instr = instructions()->at(last);
     298             : 
     299             :     LLabel* label = LLabel::cast(first_instr);
     300     4443375 :     if (last_instr->IsGoto()) {
     301     1994887 :       LGoto* goto_instr = LGoto::cast(last_instr);
     302     6161463 :       if (label->IsRedundant() &&
     303             :           !label->is_loop_header()) {
     304             :         bool can_eliminate = true;
     305     9115430 :         for (int i = first + 1; i < last && can_eliminate; ++i) {
     306     6050639 :           LInstruction* cur = instructions()->at(i);
     307     6050639 :           if (cur->IsGap()) {
     308             :             LGap* gap = LGap::cast(cur);
     309     5298624 :             if (!gap->IsRedundant()) {
     310             :               can_eliminate = false;
     311             :             }
     312             :           } else {
     313             :             can_eliminate = false;
     314             :           }
     315             :         }
     316     3064791 :         if (can_eliminate) {
     317             :           label->set_replacement(GetLabel(goto_instr->block_id()));
     318             :         }
     319             :       }
     320             :     }
     321      279085 :   }
     322      279085 : }
     323             : 
     324             : 
     325    68725632 : void LChunk::AddInstruction(LInstruction* instr, HBasicBlock* block) {
     326             :   LInstructionGap* gap = new (zone()) LInstructionGap(block);
     327    22308532 :   gap->set_hydrogen_value(instr->hydrogen_value());
     328             :   int index = -1;
     329    22308532 :   if (instr->IsControl()) {
     330             :     instructions_.Add(gap, zone());
     331    22308696 :     index = instructions_.length();
     332             :     instructions_.Add(instr, zone());
     333             :   } else {
     334             :     index = instructions_.length();
     335             :     instructions_.Add(instr, zone());
     336             :     instructions_.Add(gap, zone());
     337             :   }
     338    22308308 :   if (instr->HasPointerMap()) {
     339             :     pointer_maps_.Add(instr->pointer_map(), zone());
     340             :     instr->pointer_map()->set_lithium_position(index);
     341             :   }
     342    22308302 : }
     343             : 
     344    20602272 : LConstantOperand* LChunk::DefineConstantOperand(HConstant* constant) {
     345    20602272 :   return LConstantOperand::Create(constant->id(), zone());
     346             : }
     347             : 
     348             : 
     349      426518 : int LChunk::GetParameterStackSlot(int index) const {
     350             :   // The receiver is at index 0, the first parameter at index 1, so we
     351             :   // shift all parameter indexes down by the number of parameters, and
     352             :   // make sure they end up negative so they are distinguishable from
     353             :   // spill slots.
     354      426518 :   int result = index - info()->num_parameters() - 1;
     355             : 
     356             :   DCHECK(result < 0);
     357      426529 :   return result;
     358             : }
     359             : 
     360             : 
     361             : // A parameter relative to ebp in the arguments stub.
     362           0 : int LChunk::ParameterAt(int index) {
     363             :   DCHECK(-1 <= index);  // -1 is the receiver.
     364           0 :   return (1 + info()->scope()->num_parameters() - index) *
     365           0 :       kPointerSize;
     366             : }
     367             : 
     368             : 
     369    42619323 : LGap* LChunk::GetGapAt(int index) const {
     370    90284276 :   return LGap::cast(instructions_[index]);
     371             : }
     372             : 
     373             : 
     374    90105726 : bool LChunk::IsGapAt(int index) const {
     375   185056632 :   return instructions_[index]->IsGap();
     376             : }
     377             : 
     378             : 
     379     1561565 : int LChunk::NearestGapPos(int index) const {
     380     3984157 :   while (!IsGapAt(index)) index--;
     381     1561567 :   return index;
     382             : }
     383             : 
     384             : 
     385     2522815 : void LChunk::AddGapMove(int index, LOperand* from, LOperand* to) {
     386             :   GetGapAt(index)->GetOrCreateParallelMove(
     387     2522815 :       LGap::START, zone())->AddMove(from, to, zone());
     388     2522813 : }
     389             : 
     390             : 
     391    15870830 : HConstant* LChunk::LookupConstant(LConstantOperand* operand) const {
     392    31741660 :   return HConstant::cast(graph_->LookupValue(operand->index()));
     393             : }
     394             : 
     395             : 
     396      481811 : Representation LChunk::LookupLiteralRepresentation(
     397             :     LConstantOperand* operand) const {
     398      963622 :   return graph_->LookupValue(operand->index())->representation();
     399             : }
     400             : 
     401             : 
     402      534563 : void LChunk::CommitDependencies(Handle<Code> code) const {
     403      558096 :   if (!code->is_optimized_code()) return;
     404             :   HandleScope scope(isolate());
     405             : 
     406      520444 :   for (Handle<Map> map : deprecation_dependencies_) {
     407             :     DCHECK(!map->is_deprecated());
     408             :     DCHECK(map->CanBeDeprecated());
     409        9414 :     Map::AddDependentCode(map, DependentCode::kTransitionGroup, code);
     410             :   }
     411             : 
     412      621627 :   for (Handle<Map> map : stability_dependencies_) {
     413             :     DCHECK(map->is_stable());
     414             :     DCHECK(map->CanTransition());
     415      110597 :     Map::AddDependentCode(map, DependentCode::kPrototypeCheckGroup, code);
     416             :   }
     417             : 
     418      255515 :   info_->dependencies()->Commit(code);
     419             : }
     420             : 
     421             : 
     422      567452 : LChunk* LChunk::NewChunk(HGraph* graph) {
     423             :   DisallowHandleAllocation no_handles;
     424             :   DisallowHeapAllocation no_gc;
     425             :   graph->DisallowAddingNewValues();
     426             :   int values = graph->GetMaximumValueID();
     427             :   CompilationInfo* info = graph->info();
     428      283726 :   if (values > LUnallocated::kMaxVirtualRegisters) {
     429             :     info->AbortOptimization(kNotEnoughVirtualRegistersForValues);
     430           0 :     return NULL;
     431             :   }
     432      283726 :   LAllocator allocator(values, graph);
     433             :   LChunkBuilder builder(info, graph, &allocator);
     434      283730 :   LChunk* chunk = builder.Build();
     435      283730 :   if (chunk == NULL) return NULL;
     436             : 
     437      283730 :   if (!allocator.Allocate(chunk)) {
     438             :     info->AbortOptimization(kNotEnoughVirtualRegistersRegalloc);
     439           0 :     return NULL;
     440             :   }
     441             : 
     442             :   chunk->set_allocated_double_registers(
     443      283730 :       allocator.assigned_double_registers());
     444             : 
     445      283728 :   return chunk;
     446             : }
     447             : 
     448             : 
     449     1674362 : Handle<Code> LChunk::Codegen() {
     450             :   MacroAssembler assembler(info()->isolate(), NULL, 0,
     451      279085 :                            CodeObjectRequired::kYes);
     452             :   // Code serializer only takes unoptimized code.
     453             :   DCHECK(!info()->will_serialize());
     454      279085 :   LCodeGen generator(this, &assembler, info());
     455             : 
     456      279085 :   MarkEmptyBlocks();
     457             : 
     458      279085 :   if (generator.GenerateCode()) {
     459      279048 :     generator.CheckEnvironmentUsage();
     460      279048 :     CodeGenerator::MakeCodePrologue(info(), "optimized");
     461             :     Handle<Code> code = CodeGenerator::MakeCodeEpilogue(
     462      279048 :         &assembler, nullptr, info(), assembler.CodeObject());
     463      279048 :     generator.FinishCode(code);
     464      279048 :     CommitDependencies(code);
     465             :     Handle<ByteArray> source_positions =
     466             :         generator.source_position_table_builder()->ToSourcePositionTable(
     467      279048 :             info()->isolate(), Handle<AbstractCode>::cast(code));
     468      279048 :     code->set_source_position_table(*source_positions);
     469             :     code->set_is_crankshafted(true);
     470             : 
     471      279048 :     CodeGenerator::PrintCode(code, info());
     472      279048 :     return code;
     473             :   }
     474             :   assembler.AbortedCodeGeneration();
     475             :   return Handle<Code>::null();
     476             : }
     477             : 
     478             : 
     479     4209447 : void LChunk::set_allocated_double_registers(BitVector* allocated_registers) {
     480      283728 :   allocated_double_registers_ = allocated_registers;
     481             :   BitVector* doubles = allocated_double_registers();
     482             :   BitVector::Iterator iterator(doubles);
     483     8418894 :   while (!iterator.Done()) {
     484     3925719 :     if (info()->saves_caller_doubles()) {
     485             :       if (kDoubleSize == kPointerSize * 2) {
     486             :         current_frame_slots_ += 2;
     487             :       } else {
     488          78 :         current_frame_slots_++;
     489             :       }
     490             :     }
     491     3925719 :     iterator.Advance();
     492             :   }
     493      283728 : }
     494             : 
     495             : 
     496           0 : void LChunkBuilderBase::Abort(BailoutReason reason) {
     497             :   info()->AbortOptimization(reason);
     498           0 :   status_ = ABORTED;
     499           0 : }
     500             : 
     501             : 
     502           0 : void LChunkBuilderBase::Retry(BailoutReason reason) {
     503             :   info()->RetryOptimization(reason);
     504           0 :   status_ = ABORTED;
     505           0 : }
     506             : 
     507    21102532 : void LChunkBuilderBase::CreateLazyBailoutForCall(HBasicBlock* current_block,
     508    19407422 :                                                  LInstruction* instr,
     509     2986384 :                                                  HInstruction* hydrogen_val) {
     510    38814858 :   if (!instr->IsCall()) return;
     511             : 
     512         602 :   HEnvironment* hydrogen_env = current_block->last_environment();
     513             :   HValue* hydrogen_value_for_lazy_bailout = hydrogen_val;
     514             :   DCHECK_NOT_NULL(hydrogen_env);
     515     1695110 :   if (instr->IsSyntacticTailCall()) {
     516             :     // If it was a syntactic tail call we need to drop the current frame and
     517             :     // all the frames on top of it that are either an arguments adaptor frame
     518             :     // or a tail caller frame.
     519             :     hydrogen_env = hydrogen_env->outer();
     520        1020 :     while (hydrogen_env != nullptr &&
     521         127 :            (hydrogen_env->frame_type() == ARGUMENTS_ADAPTOR ||
     522             :             hydrogen_env->frame_type() == TAIL_CALLER_FUNCTION)) {
     523             :       hydrogen_env = hydrogen_env->outer();
     524             :     }
     525         214 :     if (hydrogen_env != nullptr) {
     526         102 :       if (hydrogen_env->frame_type() == JS_FUNCTION) {
     527             :         // In case an outer frame is a function frame we have to replay
     528             :         // environment manually because
     529             :         // 1) it does not contain a result of inlined function yet,
     530             :         // 2) we can't find the proper simulate that corresponds to the point
     531             :         //    after inlined call to do a ReplayEnvironment() on.
     532             :         // So we push return value on top of outer environment.
     533             :         // As for JS_GETTER/JS_SETTER/JS_CONSTRUCT nothing has to be done here,
     534             :         // the deoptimizer ensures that the result of the callee is correctly
     535             :         // propagated to result register during deoptimization.
     536          66 :         hydrogen_env = hydrogen_env->Copy();
     537             :         hydrogen_env->Push(hydrogen_val);
     538             :       }
     539             :     } else {
     540             :       // Although we don't need this lazy bailout for normal execution
     541             :       // (because when we tail call from the outermost function we should pop
     542             :       // its frame) we still need it when debugger is on.
     543             :       hydrogen_env = current_block->last_environment();
     544             :     }
     545             :   } else {
     546     1694896 :     if (hydrogen_val->HasObservableSideEffects()) {
     547             :       HSimulate* sim = HSimulate::cast(hydrogen_val->next());
     548     1291270 :       sim->ReplayEnvironment(hydrogen_env);
     549             :       hydrogen_value_for_lazy_bailout = sim;
     550             :     }
     551             :   }
     552             :   LInstruction* bailout = LChunkBuilderBase::AssignEnvironment(
     553     1695113 :       new (zone()) LLazyBailout(), hydrogen_env);
     554             :   bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
     555     1695127 :   chunk_->AddInstruction(bailout, current_block);
     556             : }
     557             : 
     558     2934410 : LInstruction* LChunkBuilderBase::AssignEnvironment(LInstruction* instr,
     559     2934410 :                                                    HEnvironment* hydrogen_env) {
     560     2934410 :   int argument_index_accumulator = 0;
     561     2934410 :   ZoneList<HValue*> objects_to_materialize(0, zone());
     562             :   DCHECK_NE(TAIL_CALLER_FUNCTION, hydrogen_env->frame_type());
     563             :   instr->set_environment(CreateEnvironment(
     564     2934411 :       hydrogen_env, &argument_index_accumulator, &objects_to_materialize));
     565     2934432 :   return instr;
     566             : }
     567             : 
     568     8759182 : LEnvironment* LChunkBuilderBase::CreateEnvironment(
     569    35018251 :     HEnvironment* hydrogen_env, int* argument_index_accumulator,
     570     5824761 :     ZoneList<HValue*>* objects_to_materialize) {
     571     8759182 :   if (hydrogen_env == NULL) return NULL;
     572             : 
     573             :   BailoutId ast_id = hydrogen_env->ast_id();
     574             :   DCHECK(!ast_id.IsNone() ||
     575             :          (hydrogen_env->frame_type() != JS_FUNCTION &&
     576             :           hydrogen_env->frame_type() != TAIL_CALLER_FUNCTION));
     577             : 
     578     5824785 :   if (hydrogen_env->frame_type() == TAIL_CALLER_FUNCTION) {
     579             :     // Skip potential outer arguments adaptor frame.
     580         164 :     HEnvironment* outer_hydrogen_env = hydrogen_env->outer();
     581         251 :     if (outer_hydrogen_env != nullptr &&
     582             :         outer_hydrogen_env->frame_type() == ARGUMENTS_ADAPTOR) {
     583             :       outer_hydrogen_env = outer_hydrogen_env->outer();
     584             :     }
     585             :     LEnvironment* outer = CreateEnvironment(
     586         159 :         outer_hydrogen_env, argument_index_accumulator, objects_to_materialize);
     587             :     return new (zone())
     588             :         LEnvironment(hydrogen_env->closure(), hydrogen_env->frame_type(),
     589         477 :                      ast_id, 0, 0, 0, outer, hydrogen_env->entry(), zone());
     590             :   }
     591             : 
     592             :   LEnvironment* outer =
     593             :       CreateEnvironment(hydrogen_env->outer(), argument_index_accumulator,
     594     5824626 :                         objects_to_materialize);
     595             : 
     596             :   int omitted_count = (hydrogen_env->frame_type() == JS_FUNCTION)
     597             :                           ? 0
     598     5824602 :                           : hydrogen_env->specials_count();
     599             : 
     600     5824602 :   int value_count = hydrogen_env->length() - omitted_count;
     601             :   LEnvironment* result =
     602             :       new(zone()) LEnvironment(hydrogen_env->closure(),
     603             :                                hydrogen_env->frame_type(),
     604             :                                ast_id,
     605             :                                hydrogen_env->parameter_count(),
     606             :                                argument_count_,
     607             :                                value_count,
     608             :                                outer,
     609             :                                hydrogen_env->entry(),
     610    11649207 :                                zone());
     611     5824548 :   int argument_index = *argument_index_accumulator;
     612             : 
     613             :   // Store the environment description into the environment
     614             :   // (with holes for nested objects)
     615    83561366 :   for (int i = 0; i < hydrogen_env->length(); ++i) {
     616    41077735 :     if (hydrogen_env->is_special_index(i) &&
     617             :         hydrogen_env->frame_type() != JS_FUNCTION) {
     618             :       continue;
     619             :     }
     620             :     LOperand* op;
     621    71771626 :     HValue* value = hydrogen_env->values()->at(i);
     622    35885862 :     CHECK(!value->IsPushArguments());  // Do not deopt outgoing arguments
     623    71762413 :     if (value->IsArgumentsObject() || value->IsCapturedObject()) {
     624             :       op = LEnvironment::materialization_marker();
     625             :     } else {
     626    35859241 :       op = UseAny(value);
     627             :     }
     628             :     result->AddValue(op,
     629             :                      value->representation(),
     630    35885886 :                      value->CheckFlag(HInstruction::kUint32));
     631             :   }
     632             : 
     633             :   // Recursively store the nested objects into the environment
     634    77738975 :   for (int i = 0; i < hydrogen_env->length(); ++i) {
     635    35957212 :     if (hydrogen_env->is_special_index(i)) continue;
     636             : 
     637    30835652 :     HValue* value = hydrogen_env->values()->at(i);
     638    61662257 :     if (value->IsArgumentsObject() || value->IsCapturedObject()) {
     639       26489 :       AddObjectToMaterialize(value, objects_to_materialize, result);
     640             :     }
     641             :   }
     642             : 
     643     5824582 :   if (hydrogen_env->frame_type() == JS_FUNCTION) {
     644     5051677 :     *argument_index_accumulator = argument_index;
     645             :   }
     646             : 
     647     5824582 :   return result;
     648             : }
     649             : 
     650             : 
     651             : // Add an object to the supplied environment and object materialization list.
     652             : //
     653             : // Notes:
     654             : //
     655             : // We are building three lists here:
     656             : //
     657             : // 1. In the result->object_mapping_ list (added to by the
     658             : //    LEnvironment::Add*Object methods), we store the lengths (number
     659             : //    of fields) of the captured objects in depth-first traversal order, or
     660             : //    in case of duplicated objects, we store the index to the duplicate object
     661             : //    (with a tag to differentiate between captured and duplicated objects).
     662             : //
     663             : // 2. The object fields are stored in the result->values_ list
     664             : //    (added to by the LEnvironment.AddValue method) sequentially as lists
     665             : //    of fields with holes for nested objects (the holes will be expanded
     666             : //    later by LCodegen::AddToTranslation according to the
     667             : //    LEnvironment.object_mapping_ list).
     668             : //
     669             : // 3. The auxiliary objects_to_materialize array stores the hydrogen values
     670             : //    in the same order as result->object_mapping_ list. This is used
     671             : //    to detect duplicate values and calculate the corresponding object index.
     672       26501 : void LChunkBuilderBase::AddObjectToMaterialize(HValue* value,
     673       26501 :     ZoneList<HValue*>* objects_to_materialize, LEnvironment* result) {
     674       26501 :   int object_index = objects_to_materialize->length();
     675             :   // Store the hydrogen value into the de-duplication array
     676             :   objects_to_materialize->Add(value, zone());
     677             :   // Find out whether we are storing a duplicated value
     678             :   int previously_materialized_object = -1;
     679       32761 :   for (int prev = 0; prev < object_index; ++prev) {
     680        8544 :     if (objects_to_materialize->at(prev) == value) {
     681             :       previously_materialized_object = prev;
     682             :       break;
     683             :     }
     684             :   }
     685             :   // Store the captured object length (or duplicated object index)
     686             :   // into the environment. For duplicated objects, we stop here.
     687       26501 :   int length = value->OperandCount();
     688             :   bool is_arguments = value->IsArgumentsObject();
     689       26501 :   if (previously_materialized_object >= 0) {
     690             :     result->AddDuplicateObject(previously_materialized_object);
     691       26501 :     return;
     692             :   } else {
     693       24217 :     result->AddNewObject(is_arguments ? length - 1 : length, is_arguments);
     694             :   }
     695             :   // Store the captured object's fields into the environment
     696      122244 :   for (int i = is_arguments ? 1 : 0; i < length; ++i) {
     697             :     LOperand* op;
     698      196054 :     HValue* arg_value = value->OperandAt(i);
     699      196054 :     if (arg_value->IsArgumentsObject() || arg_value->IsCapturedObject()) {
     700             :       // Insert a hole for nested objects
     701             :       op = LEnvironment::materialization_marker();
     702             :     } else {
     703             :       DCHECK(!arg_value->IsPushArguments());
     704             :       // For ordinary values, tell the register allocator we need the value
     705             :       // to be alive here
     706       98015 :       op = UseAny(arg_value);
     707             :     }
     708             :     result->AddValue(op,
     709             :                      arg_value->representation(),
     710       98027 :                      arg_value->CheckFlag(HInstruction::kUint32));
     711             :   }
     712             :   // Recursively store all the nested captured objects into the environment
     713      122244 :   for (int i = is_arguments ? 1 : 0; i < length; ++i) {
     714       98027 :     HValue* arg_value = value->OperandAt(i);
     715      196054 :     if (arg_value->IsArgumentsObject() || arg_value->IsCapturedObject()) {
     716          12 :       AddObjectToMaterialize(arg_value, objects_to_materialize, result);
     717             :     }
     718             :   }
     719             : }
     720             : 
     721             : 
     722     1683793 : LPhase::~LPhase() {
     723      841896 :   if (ShouldProduceTraceOutput()) {
     724           0 :     isolate()->GetHTracer()->TraceLithium(name(), chunk_);
     725             :   }
     726      841899 : }
     727             : 
     728             : 
     729             : }  // namespace internal
     730             : }  // namespace v8

Generated by: LCOV version 1.10