Home | History | Annotate | Download | only in compiler
      1 // Copyright 2013 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/compiler/code-generator.h"
      6 
      7 #include "src/address-map.h"
      8 #include "src/base/adapters.h"
      9 #include "src/compilation-info.h"
     10 #include "src/compiler/code-generator-impl.h"
     11 #include "src/compiler/linkage.h"
     12 #include "src/compiler/pipeline.h"
     13 #include "src/frames-inl.h"
     14 
     15 namespace v8 {
     16 namespace internal {
     17 namespace compiler {
     18 
     19 class CodeGenerator::JumpTable final : public ZoneObject {
     20  public:
     21   JumpTable(JumpTable* next, Label** targets, size_t target_count)
     22       : next_(next), targets_(targets), target_count_(target_count) {}
     23 
     24   Label* label() { return &label_; }
     25   JumpTable* next() const { return next_; }
     26   Label** targets() const { return targets_; }
     27   size_t target_count() const { return target_count_; }
     28 
     29  private:
     30   Label label_;
     31   JumpTable* const next_;
     32   Label** const targets_;
     33   size_t const target_count_;
     34 };
     35 
     36 CodeGenerator::CodeGenerator(Frame* frame, Linkage* linkage,
     37                              InstructionSequence* code, CompilationInfo* info)
     38     : frame_access_state_(nullptr),
     39       linkage_(linkage),
     40       code_(code),
     41       unwinding_info_writer_(zone()),
     42       info_(info),
     43       labels_(zone()->NewArray<Label>(code->InstructionBlockCount())),
     44       current_block_(RpoNumber::Invalid()),
     45       current_source_position_(SourcePosition::Unknown()),
     46       masm_(info->isolate(), nullptr, 0, CodeObjectRequired::kNo),
     47       resolver_(this),
     48       safepoints_(code->zone()),
     49       handlers_(code->zone()),
     50       deoptimization_exits_(code->zone()),
     51       deoptimization_states_(code->zone()),
     52       deoptimization_literals_(code->zone()),
     53       inlined_function_count_(0),
     54       translations_(code->zone()),
     55       last_lazy_deopt_pc_(0),
     56       jump_tables_(nullptr),
     57       ools_(nullptr),
     58       osr_pc_offset_(-1),
     59       optimized_out_literal_id_(-1),
     60       source_position_table_builder_(code->zone(),
     61                                      info->SourcePositionRecordingMode()) {
     62   for (int i = 0; i < code->InstructionBlockCount(); ++i) {
     63     new (&labels_[i]) Label;
     64   }
     65   CreateFrameAccessState(frame);
     66 }
     67 
     68 Isolate* CodeGenerator::isolate() const { return info_->isolate(); }
     69 
     70 void CodeGenerator::CreateFrameAccessState(Frame* frame) {
     71   FinishFrame(frame);
     72   frame_access_state_ = new (code()->zone()) FrameAccessState(frame);
     73 }
     74 
     75 
     76 Handle<Code> CodeGenerator::GenerateCode() {
     77   CompilationInfo* info = this->info();
     78 
     79   // Open a frame scope to indicate that there is a frame on the stack.  The
     80   // MANUAL indicates that the scope shouldn't actually generate code to set up
     81   // the frame (that is done in AssemblePrologue).
     82   FrameScope frame_scope(masm(), StackFrame::MANUAL);
     83 
     84   if (info->is_source_positions_enabled()) {
     85     SourcePosition source_position(info->shared_info()->start_position());
     86     AssembleSourcePosition(source_position);
     87   }
     88 
     89   // Place function entry hook if requested to do so.
     90   if (linkage()->GetIncomingDescriptor()->IsJSFunctionCall()) {
     91     ProfileEntryHookStub::MaybeCallEntryHook(masm());
     92   }
     93   // Architecture-specific, linkage-specific prologue.
     94   info->set_prologue_offset(masm()->pc_offset());
     95 
     96   // Define deoptimization literals for all inlined functions.
     97   DCHECK_EQ(0u, deoptimization_literals_.size());
     98   for (CompilationInfo::InlinedFunctionHolder& inlined :
     99        info->inlined_functions()) {
    100     if (!inlined.shared_info.is_identical_to(info->shared_info())) {
    101       int index = DefineDeoptimizationLiteral(inlined.shared_info);
    102       inlined.RegisterInlinedFunctionId(index);
    103     }
    104   }
    105   inlined_function_count_ = deoptimization_literals_.size();
    106 
    107   // Define deoptimization literals for all unoptimized code objects of inlined
    108   // functions. This ensures unoptimized code is kept alive by optimized code.
    109   for (const CompilationInfo::InlinedFunctionHolder& inlined :
    110        info->inlined_functions()) {
    111     if (!inlined.shared_info.is_identical_to(info->shared_info())) {
    112       DefineDeoptimizationLiteral(inlined.inlined_code_object_root);
    113     }
    114   }
    115 
    116   unwinding_info_writer_.SetNumberOfInstructionBlocks(
    117       code()->InstructionBlockCount());
    118 
    119   // Assemble all non-deferred blocks, followed by deferred ones.
    120   for (int deferred = 0; deferred < 2; ++deferred) {
    121     for (const InstructionBlock* block : code()->instruction_blocks()) {
    122       if (block->IsDeferred() == (deferred == 0)) {
    123         continue;
    124       }
    125       // Align loop headers on 16-byte boundaries.
    126       if (block->IsLoopHeader()) masm()->Align(16);
    127       // Ensure lazy deopt doesn't patch handler entry points.
    128       if (block->IsHandler()) EnsureSpaceForLazyDeopt();
    129       // Bind a label for a block.
    130       current_block_ = block->rpo_number();
    131       unwinding_info_writer_.BeginInstructionBlock(masm()->pc_offset(), block);
    132       if (FLAG_code_comments) {
    133         // TODO(titzer): these code comments are a giant memory leak.
    134         Vector<char> buffer = Vector<char>::New(200);
    135         char* buffer_start = buffer.start();
    136 
    137         int next = SNPrintF(
    138             buffer, "-- B%d start%s%s%s%s", block->rpo_number().ToInt(),
    139             block->IsDeferred() ? " (deferred)" : "",
    140             block->needs_frame() ? "" : " (no frame)",
    141             block->must_construct_frame() ? " (construct frame)" : "",
    142             block->must_deconstruct_frame() ? " (deconstruct frame)" : "");
    143 
    144         buffer = buffer.SubVector(next, buffer.length());
    145 
    146         if (block->IsLoopHeader()) {
    147           next =
    148               SNPrintF(buffer, " (loop up to %d)", block->loop_end().ToInt());
    149           buffer = buffer.SubVector(next, buffer.length());
    150         }
    151         if (block->loop_header().IsValid()) {
    152           next =
    153               SNPrintF(buffer, " (in loop %d)", block->loop_header().ToInt());
    154           buffer = buffer.SubVector(next, buffer.length());
    155         }
    156         SNPrintF(buffer, " --");
    157         masm()->RecordComment(buffer_start);
    158       }
    159 
    160       frame_access_state()->MarkHasFrame(block->needs_frame());
    161 
    162       masm()->bind(GetLabel(current_block_));
    163       if (block->must_construct_frame()) {
    164         AssembleConstructFrame();
    165         // We need to setup the root register after we assemble the prologue, to
    166         // avoid clobbering callee saved registers in case of C linkage and
    167         // using the roots.
    168         // TODO(mtrofin): investigate how we can avoid doing this repeatedly.
    169         if (linkage()->GetIncomingDescriptor()->InitializeRootRegister()) {
    170           masm()->InitializeRootRegister();
    171         }
    172       }
    173 
    174       CodeGenResult result;
    175       if (FLAG_enable_embedded_constant_pool && !block->needs_frame()) {
    176         ConstantPoolUnavailableScope constant_pool_unavailable(masm());
    177         result = AssembleBlock(block);
    178       } else {
    179         result = AssembleBlock(block);
    180       }
    181       if (result != kSuccess) return Handle<Code>();
    182       unwinding_info_writer_.EndInstructionBlock(block);
    183     }
    184   }
    185 
    186   // Assemble all out-of-line code.
    187   if (ools_) {
    188     masm()->RecordComment("-- Out of line code --");
    189     for (OutOfLineCode* ool = ools_; ool; ool = ool->next()) {
    190       masm()->bind(ool->entry());
    191       ool->Generate();
    192       if (ool->exit()->is_bound()) masm()->jmp(ool->exit());
    193     }
    194   }
    195 
    196   // Assemble all eager deoptimization exits.
    197   for (DeoptimizationExit* exit : deoptimization_exits_) {
    198     masm()->bind(exit->label());
    199     AssembleDeoptimizerCall(exit->deoptimization_id(), exit->pos());
    200   }
    201 
    202   // Ensure there is space for lazy deoptimization in the code.
    203   if (info->ShouldEnsureSpaceForLazyDeopt()) {
    204     int target_offset = masm()->pc_offset() + Deoptimizer::patch_size();
    205     while (masm()->pc_offset() < target_offset) {
    206       masm()->nop();
    207     }
    208   }
    209 
    210   FinishCode(masm());
    211 
    212   // Emit the jump tables.
    213   if (jump_tables_) {
    214     masm()->Align(kPointerSize);
    215     for (JumpTable* table = jump_tables_; table; table = table->next()) {
    216       masm()->bind(table->label());
    217       AssembleJumpTable(table->targets(), table->target_count());
    218     }
    219   }
    220 
    221   safepoints()->Emit(masm(), frame()->GetTotalFrameSlotCount());
    222 
    223   unwinding_info_writer_.Finish(masm()->pc_offset());
    224 
    225   Handle<Code> result = v8::internal::CodeGenerator::MakeCodeEpilogue(
    226       masm(), unwinding_info_writer_.eh_frame_writer(), info, Handle<Object>());
    227   result->set_is_turbofanned(true);
    228   result->set_stack_slots(frame()->GetTotalFrameSlotCount());
    229   result->set_safepoint_table_offset(safepoints()->GetCodeOffset());
    230   Handle<ByteArray> source_positions =
    231       source_position_table_builder_.ToSourcePositionTable(
    232           isolate(), Handle<AbstractCode>::cast(result));
    233   result->set_source_position_table(*source_positions);
    234 
    235   // Emit exception handler table.
    236   if (!handlers_.empty()) {
    237     Handle<HandlerTable> table =
    238         Handle<HandlerTable>::cast(isolate()->factory()->NewFixedArray(
    239             HandlerTable::LengthForReturn(static_cast<int>(handlers_.size())),
    240             TENURED));
    241     for (size_t i = 0; i < handlers_.size(); ++i) {
    242       table->SetReturnOffset(static_cast<int>(i), handlers_[i].pc_offset);
    243       table->SetReturnHandler(static_cast<int>(i), handlers_[i].handler->pos());
    244     }
    245     result->set_handler_table(*table);
    246   }
    247 
    248   PopulateDeoptimizationData(result);
    249 
    250   // Ensure there is space for lazy deoptimization in the relocation info.
    251   if (info->ShouldEnsureSpaceForLazyDeopt()) {
    252     Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(result);
    253   }
    254 
    255   return result;
    256 }
    257 
    258 
    259 bool CodeGenerator::IsNextInAssemblyOrder(RpoNumber block) const {
    260   return code()
    261       ->InstructionBlockAt(current_block_)
    262       ->ao_number()
    263       .IsNext(code()->InstructionBlockAt(block)->ao_number());
    264 }
    265 
    266 
    267 void CodeGenerator::RecordSafepoint(ReferenceMap* references,
    268                                     Safepoint::Kind kind, int arguments,
    269                                     Safepoint::DeoptMode deopt_mode) {
    270   Safepoint safepoint =
    271       safepoints()->DefineSafepoint(masm(), kind, arguments, deopt_mode);
    272   int stackSlotToSpillSlotDelta =
    273       frame()->GetTotalFrameSlotCount() - frame()->GetSpillSlotCount();
    274   for (const InstructionOperand& operand : references->reference_operands()) {
    275     if (operand.IsStackSlot()) {
    276       int index = LocationOperand::cast(operand).index();
    277       DCHECK(index >= 0);
    278       // We might index values in the fixed part of the frame (i.e. the
    279       // closure pointer or the context pointer); these are not spill slots
    280       // and therefore don't work with the SafepointTable currently, but
    281       // we also don't need to worry about them, since the GC has special
    282       // knowledge about those fields anyway.
    283       if (index < stackSlotToSpillSlotDelta) continue;
    284       safepoint.DefinePointerSlot(index, zone());
    285     } else if (operand.IsRegister() && (kind & Safepoint::kWithRegisters)) {
    286       Register reg = LocationOperand::cast(operand).GetRegister();
    287       safepoint.DefinePointerRegister(reg, zone());
    288     }
    289   }
    290 }
    291 
    292 bool CodeGenerator::IsMaterializableFromRoot(
    293     Handle<HeapObject> object, Heap::RootListIndex* index_return) {
    294   const CallDescriptor* incoming_descriptor =
    295       linkage()->GetIncomingDescriptor();
    296   if (incoming_descriptor->flags() & CallDescriptor::kCanUseRoots) {
    297     RootIndexMap map(isolate());
    298     int root_index = map.Lookup(*object);
    299     if (root_index != RootIndexMap::kInvalidRootIndex) {
    300       *index_return = static_cast<Heap::RootListIndex>(root_index);
    301       return true;
    302     }
    303   }
    304   return false;
    305 }
    306 
    307 CodeGenerator::CodeGenResult CodeGenerator::AssembleBlock(
    308     const InstructionBlock* block) {
    309   for (int i = block->code_start(); i < block->code_end(); ++i) {
    310     Instruction* instr = code()->InstructionAt(i);
    311     CodeGenResult result = AssembleInstruction(instr, block);
    312     if (result != kSuccess) return result;
    313   }
    314   return kSuccess;
    315 }
    316 
    317 bool CodeGenerator::IsValidPush(InstructionOperand source,
    318                                 CodeGenerator::PushTypeFlags push_type) {
    319   if (source.IsImmediate() &&
    320       ((push_type & CodeGenerator::kImmediatePush) != 0)) {
    321     return true;
    322   }
    323   if ((source.IsRegister() || source.IsStackSlot()) &&
    324       ((push_type & CodeGenerator::kScalarPush) != 0)) {
    325     return true;
    326   }
    327   if ((source.IsFloatRegister() || source.IsFloatStackSlot()) &&
    328       ((push_type & CodeGenerator::kFloat32Push) != 0)) {
    329     return true;
    330   }
    331   if ((source.IsDoubleRegister() || source.IsFloatStackSlot()) &&
    332       ((push_type & CodeGenerator::kFloat64Push) != 0)) {
    333     return true;
    334   }
    335   return false;
    336 }
    337 
    338 void CodeGenerator::GetPushCompatibleMoves(Instruction* instr,
    339                                            PushTypeFlags push_type,
    340                                            ZoneVector<MoveOperands*>* pushes) {
    341   pushes->clear();
    342   for (int i = Instruction::FIRST_GAP_POSITION;
    343        i <= Instruction::LAST_GAP_POSITION; ++i) {
    344     Instruction::GapPosition inner_pos =
    345         static_cast<Instruction::GapPosition>(i);
    346     ParallelMove* parallel_move = instr->GetParallelMove(inner_pos);
    347     if (parallel_move != nullptr) {
    348       for (auto move : *parallel_move) {
    349         InstructionOperand source = move->source();
    350         InstructionOperand destination = move->destination();
    351         int first_push_compatible_index =
    352             V8_TARGET_ARCH_STORES_RETURN_ADDRESS_ON_STACK ? 1 : 0;
    353         // If there are any moves from slots that will be overridden by pushes,
    354         // then the full gap resolver must be used since optimization with
    355         // pushes don't participate in the parallel move and might clobber
    356         // values needed for the gap resolve.
    357         if (source.IsStackSlot() &&
    358             LocationOperand::cast(source).index() >=
    359                 first_push_compatible_index) {
    360           pushes->clear();
    361           return;
    362         }
    363         // TODO(danno): Right now, only consider moves from the FIRST gap for
    364         // pushes. Theoretically, we could extract pushes for both gaps (there
    365         // are cases where this happens), but the logic for that would also have
    366         // to check to make sure that non-memory inputs to the pushes from the
    367         // LAST gap don't get clobbered in the FIRST gap.
    368         if (i == Instruction::FIRST_GAP_POSITION) {
    369           if (destination.IsStackSlot() &&
    370               LocationOperand::cast(destination).index() >=
    371                   first_push_compatible_index) {
    372             int index = LocationOperand::cast(destination).index();
    373             if (IsValidPush(source, push_type)) {
    374               if (index >= static_cast<int>(pushes->size())) {
    375                 pushes->resize(index + 1);
    376               }
    377               (*pushes)[index] = move;
    378             }
    379           }
    380         }
    381       }
    382     }
    383   }
    384 
    385   // For now, only support a set of continuous pushes at the end of the list.
    386   size_t push_count_upper_bound = pushes->size();
    387   size_t push_begin = push_count_upper_bound;
    388   for (auto move : base::Reversed(*pushes)) {
    389     if (move == nullptr) break;
    390     push_begin--;
    391   }
    392   size_t push_count = pushes->size() - push_begin;
    393   std::copy(pushes->begin() + push_begin,
    394             pushes->begin() + push_begin + push_count, pushes->begin());
    395   pushes->resize(push_count);
    396 }
    397 
    398 CodeGenerator::CodeGenResult CodeGenerator::AssembleInstruction(
    399     Instruction* instr, const InstructionBlock* block) {
    400   int first_unused_stack_slot;
    401   FlagsMode mode = FlagsModeField::decode(instr->opcode());
    402   if (mode != kFlags_trap) {
    403     AssembleSourcePosition(instr);
    404   }
    405   bool adjust_stack =
    406       GetSlotAboveSPBeforeTailCall(instr, &first_unused_stack_slot);
    407   if (adjust_stack) AssembleTailCallBeforeGap(instr, first_unused_stack_slot);
    408   AssembleGaps(instr);
    409   if (adjust_stack) AssembleTailCallAfterGap(instr, first_unused_stack_slot);
    410   DCHECK_IMPLIES(
    411       block->must_deconstruct_frame(),
    412       instr != code()->InstructionAt(block->last_instruction_index()) ||
    413           instr->IsRet() || instr->IsJump());
    414   if (instr->IsJump() && block->must_deconstruct_frame()) {
    415     AssembleDeconstructFrame();
    416   }
    417   // Assemble architecture-specific code for the instruction.
    418   CodeGenResult result = AssembleArchInstruction(instr);
    419   if (result != kSuccess) return result;
    420 
    421   FlagsCondition condition = FlagsConditionField::decode(instr->opcode());
    422   switch (mode) {
    423     case kFlags_branch: {
    424       // Assemble a branch after this instruction.
    425       InstructionOperandConverter i(this, instr);
    426       RpoNumber true_rpo = i.InputRpo(instr->InputCount() - 2);
    427       RpoNumber false_rpo = i.InputRpo(instr->InputCount() - 1);
    428 
    429       if (true_rpo == false_rpo) {
    430         // redundant branch.
    431         if (!IsNextInAssemblyOrder(true_rpo)) {
    432           AssembleArchJump(true_rpo);
    433         }
    434         return kSuccess;
    435       }
    436       if (IsNextInAssemblyOrder(true_rpo)) {
    437         // true block is next, can fall through if condition negated.
    438         std::swap(true_rpo, false_rpo);
    439         condition = NegateFlagsCondition(condition);
    440       }
    441       BranchInfo branch;
    442       branch.condition = condition;
    443       branch.true_label = GetLabel(true_rpo);
    444       branch.false_label = GetLabel(false_rpo);
    445       branch.fallthru = IsNextInAssemblyOrder(false_rpo);
    446       // Assemble architecture-specific branch.
    447       AssembleArchBranch(instr, &branch);
    448       break;
    449     }
    450     case kFlags_deoptimize: {
    451       // Assemble a conditional eager deoptimization after this instruction.
    452       InstructionOperandConverter i(this, instr);
    453       size_t frame_state_offset = MiscField::decode(instr->opcode());
    454       DeoptimizationExit* const exit =
    455           AddDeoptimizationExit(instr, frame_state_offset);
    456       Label continue_label;
    457       BranchInfo branch;
    458       branch.condition = condition;
    459       branch.true_label = exit->label();
    460       branch.false_label = &continue_label;
    461       branch.fallthru = true;
    462       // Assemble architecture-specific branch.
    463       AssembleArchBranch(instr, &branch);
    464       masm()->bind(&continue_label);
    465       break;
    466     }
    467     case kFlags_set: {
    468       // Assemble a boolean materialization after this instruction.
    469       AssembleArchBoolean(instr, condition);
    470       break;
    471     }
    472     case kFlags_trap: {
    473       AssembleArchTrap(instr, condition);
    474       break;
    475     }
    476     case kFlags_none: {
    477       break;
    478     }
    479   }
    480   return kSuccess;
    481 }
    482 
    483 void CodeGenerator::AssembleSourcePosition(Instruction* instr) {
    484   SourcePosition source_position = SourcePosition::Unknown();
    485   if (instr->IsNop() && instr->AreMovesRedundant()) return;
    486   if (!code()->GetSourcePosition(instr, &source_position)) return;
    487   AssembleSourcePosition(source_position);
    488 }
    489 
    490 void CodeGenerator::AssembleSourcePosition(SourcePosition source_position) {
    491   if (source_position == current_source_position_) return;
    492   current_source_position_ = source_position;
    493   if (!source_position.IsKnown()) return;
    494   source_position_table_builder_.AddPosition(masm()->pc_offset(),
    495                                              source_position, false);
    496   if (FLAG_code_comments) {
    497     CompilationInfo* info = this->info();
    498     if (!info->parse_info()) return;
    499     std::ostringstream buffer;
    500     buffer << "-- ";
    501     if (FLAG_trace_turbo) {
    502       buffer << source_position;
    503     } else {
    504       buffer << source_position.InliningStack(info);
    505     }
    506     buffer << " --";
    507     masm()->RecordComment(StrDup(buffer.str().c_str()));
    508   }
    509 }
    510 
    511 bool CodeGenerator::GetSlotAboveSPBeforeTailCall(Instruction* instr,
    512                                                  int* slot) {
    513   if (instr->IsTailCall()) {
    514     InstructionOperandConverter g(this, instr);
    515     *slot = g.InputInt32(instr->InputCount() - 1);
    516     return true;
    517   } else {
    518     return false;
    519   }
    520 }
    521 
    522 void CodeGenerator::AssembleGaps(Instruction* instr) {
    523   for (int i = Instruction::FIRST_GAP_POSITION;
    524        i <= Instruction::LAST_GAP_POSITION; i++) {
    525     Instruction::GapPosition inner_pos =
    526         static_cast<Instruction::GapPosition>(i);
    527     ParallelMove* move = instr->GetParallelMove(inner_pos);
    528     if (move != nullptr) resolver()->Resolve(move);
    529   }
    530 }
    531 
    532 namespace {
    533 
    534 Handle<PodArray<InliningPosition>> CreateInliningPositions(
    535     CompilationInfo* info) {
    536   const CompilationInfo::InlinedFunctionList& inlined_functions =
    537       info->inlined_functions();
    538   if (inlined_functions.size() == 0) {
    539     return Handle<PodArray<InliningPosition>>::cast(
    540         info->isolate()->factory()->empty_byte_array());
    541   }
    542   Handle<PodArray<InliningPosition>> inl_positions =
    543       PodArray<InliningPosition>::New(
    544           info->isolate(), static_cast<int>(inlined_functions.size()), TENURED);
    545   for (size_t i = 0; i < inlined_functions.size(); ++i) {
    546     inl_positions->set(static_cast<int>(i), inlined_functions[i].position);
    547   }
    548   return inl_positions;
    549 }
    550 
    551 }  // namespace
    552 
    553 void CodeGenerator::PopulateDeoptimizationData(Handle<Code> code_object) {
    554   CompilationInfo* info = this->info();
    555   int deopt_count = static_cast<int>(deoptimization_states_.size());
    556   if (deopt_count == 0 && !info->is_osr()) return;
    557   Handle<DeoptimizationInputData> data =
    558       DeoptimizationInputData::New(isolate(), deopt_count, TENURED);
    559 
    560   Handle<ByteArray> translation_array =
    561       translations_.CreateByteArray(isolate()->factory());
    562 
    563   data->SetTranslationByteArray(*translation_array);
    564   data->SetInlinedFunctionCount(
    565       Smi::FromInt(static_cast<int>(inlined_function_count_)));
    566   data->SetOptimizationId(Smi::FromInt(info->optimization_id()));
    567 
    568   if (info->has_shared_info()) {
    569     data->SetSharedFunctionInfo(*info->shared_info());
    570   } else {
    571     data->SetSharedFunctionInfo(Smi::kZero);
    572   }
    573 
    574   Handle<FixedArray> literals = isolate()->factory()->NewFixedArray(
    575       static_cast<int>(deoptimization_literals_.size()), TENURED);
    576   {
    577     AllowDeferredHandleDereference copy_handles;
    578     for (unsigned i = 0; i < deoptimization_literals_.size(); i++) {
    579       literals->set(i, *deoptimization_literals_[i]);
    580     }
    581     data->SetLiteralArray(*literals);
    582   }
    583 
    584   Handle<PodArray<InliningPosition>> inl_pos = CreateInliningPositions(info);
    585   data->SetInliningPositions(*inl_pos);
    586 
    587   if (info->is_osr()) {
    588     DCHECK(osr_pc_offset_ >= 0);
    589     data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
    590     data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
    591   } else {
    592     BailoutId osr_ast_id = BailoutId::None();
    593     data->SetOsrAstId(Smi::FromInt(osr_ast_id.ToInt()));
    594     data->SetOsrPcOffset(Smi::FromInt(-1));
    595   }
    596 
    597   // Populate deoptimization entries.
    598   for (int i = 0; i < deopt_count; i++) {
    599     DeoptimizationState* deoptimization_state = deoptimization_states_[i];
    600     data->SetAstId(i, deoptimization_state->bailout_id());
    601     CHECK(deoptimization_states_[i]);
    602     data->SetTranslationIndex(
    603         i, Smi::FromInt(deoptimization_states_[i]->translation_id()));
    604     data->SetArgumentsStackHeight(i, Smi::kZero);
    605     data->SetPc(i, Smi::FromInt(deoptimization_state->pc_offset()));
    606   }
    607 
    608   code_object->set_deoptimization_data(*data);
    609 }
    610 
    611 
    612 Label* CodeGenerator::AddJumpTable(Label** targets, size_t target_count) {
    613   jump_tables_ = new (zone()) JumpTable(jump_tables_, targets, target_count);
    614   return jump_tables_->label();
    615 }
    616 
    617 
    618 void CodeGenerator::RecordCallPosition(Instruction* instr) {
    619   CallDescriptor::Flags flags(MiscField::decode(instr->opcode()));
    620 
    621   bool needs_frame_state = (flags & CallDescriptor::kNeedsFrameState);
    622 
    623   RecordSafepoint(
    624       instr->reference_map(), Safepoint::kSimple, 0,
    625       needs_frame_state ? Safepoint::kLazyDeopt : Safepoint::kNoLazyDeopt);
    626 
    627   if (flags & CallDescriptor::kHasExceptionHandler) {
    628     InstructionOperandConverter i(this, instr);
    629     RpoNumber handler_rpo = i.InputRpo(instr->InputCount() - 1);
    630     handlers_.push_back({GetLabel(handler_rpo), masm()->pc_offset()});
    631   }
    632 
    633   if (needs_frame_state) {
    634     MarkLazyDeoptSite();
    635     // If the frame state is present, it starts at argument 1 (just after the
    636     // code address).
    637     size_t frame_state_offset = 1;
    638     FrameStateDescriptor* descriptor =
    639         GetDeoptimizationEntry(instr, frame_state_offset).descriptor();
    640     int pc_offset = masm()->pc_offset();
    641     int deopt_state_id = BuildTranslation(instr, pc_offset, frame_state_offset,
    642                                           descriptor->state_combine());
    643     // If the pre-call frame state differs from the post-call one, produce the
    644     // pre-call frame state, too.
    645     // TODO(jarin) We might want to avoid building the pre-call frame state
    646     // because it is only used to get locals and arguments (by the debugger and
    647     // f.arguments), and those are the same in the pre-call and post-call
    648     // states.
    649     if (!descriptor->state_combine().IsOutputIgnored()) {
    650       deopt_state_id = BuildTranslation(instr, -1, frame_state_offset,
    651                                         OutputFrameStateCombine::Ignore());
    652     }
    653     safepoints()->RecordLazyDeoptimizationIndex(deopt_state_id);
    654   }
    655 }
    656 
    657 
    658 int CodeGenerator::DefineDeoptimizationLiteral(Handle<Object> literal) {
    659   int result = static_cast<int>(deoptimization_literals_.size());
    660   for (unsigned i = 0; i < deoptimization_literals_.size(); ++i) {
    661     if (deoptimization_literals_[i].is_identical_to(literal)) return i;
    662   }
    663   deoptimization_literals_.push_back(literal);
    664   return result;
    665 }
    666 
    667 DeoptimizationEntry const& CodeGenerator::GetDeoptimizationEntry(
    668     Instruction* instr, size_t frame_state_offset) {
    669   InstructionOperandConverter i(this, instr);
    670   int const state_id = i.InputInt32(frame_state_offset);
    671   return code()->GetDeoptimizationEntry(state_id);
    672 }
    673 
    674 DeoptimizeKind CodeGenerator::GetDeoptimizationKind(
    675     int deoptimization_id) const {
    676   size_t const index = static_cast<size_t>(deoptimization_id);
    677   DCHECK_LT(index, deoptimization_states_.size());
    678   return deoptimization_states_[index]->kind();
    679 }
    680 
    681 DeoptimizeReason CodeGenerator::GetDeoptimizationReason(
    682     int deoptimization_id) const {
    683   size_t const index = static_cast<size_t>(deoptimization_id);
    684   DCHECK_LT(index, deoptimization_states_.size());
    685   return deoptimization_states_[index]->reason();
    686 }
    687 
    688 void CodeGenerator::TranslateStateValueDescriptor(
    689     StateValueDescriptor* desc, StateValueList* nested,
    690     Translation* translation, InstructionOperandIterator* iter) {
    691   // Note:
    692   // If translation is null, we just skip the relevant instruction operands.
    693   if (desc->IsNested()) {
    694     if (translation != nullptr) {
    695       translation->BeginCapturedObject(static_cast<int>(nested->size()));
    696     }
    697     for (auto field : *nested) {
    698       TranslateStateValueDescriptor(field.desc, field.nested, translation,
    699                                     iter);
    700     }
    701   } else if (desc->IsArguments()) {
    702     if (translation != nullptr) {
    703       translation->BeginArgumentsObject(0);
    704     }
    705   } else if (desc->IsDuplicate()) {
    706     if (translation != nullptr) {
    707       translation->DuplicateObject(static_cast<int>(desc->id()));
    708     }
    709   } else if (desc->IsPlain()) {
    710     InstructionOperand* op = iter->Advance();
    711     if (translation != nullptr) {
    712       AddTranslationForOperand(translation, iter->instruction(), op,
    713                                desc->type());
    714     }
    715   } else {
    716     DCHECK(desc->IsOptimizedOut());
    717     if (translation != nullptr) {
    718       if (optimized_out_literal_id_ == -1) {
    719         optimized_out_literal_id_ =
    720             DefineDeoptimizationLiteral(isolate()->factory()->optimized_out());
    721       }
    722       translation->StoreLiteral(optimized_out_literal_id_);
    723     }
    724   }
    725 }
    726 
    727 
    728 void CodeGenerator::TranslateFrameStateDescriptorOperands(
    729     FrameStateDescriptor* desc, InstructionOperandIterator* iter,
    730     OutputFrameStateCombine combine, Translation* translation) {
    731   size_t index = 0;
    732   StateValueList* values = desc->GetStateValueDescriptors();
    733   for (StateValueList::iterator it = values->begin(); it != values->end();
    734        ++it, ++index) {
    735     StateValueDescriptor* value_desc = (*it).desc;
    736     if (combine.kind() == OutputFrameStateCombine::kPokeAt) {
    737       // The result of the call should be placed at position
    738       // [index_from_top] in the stack (overwriting whatever was
    739       // previously there).
    740       size_t index_from_top =
    741           desc->GetSize(combine) - 1 - combine.GetOffsetToPokeAt();
    742       if (index >= index_from_top &&
    743           index < index_from_top + iter->instruction()->OutputCount()) {
    744         DCHECK_NOT_NULL(translation);
    745         AddTranslationForOperand(
    746             translation, iter->instruction(),
    747             iter->instruction()->OutputAt(index - index_from_top),
    748             MachineType::AnyTagged());
    749         // Skip the instruction operands.
    750         TranslateStateValueDescriptor(value_desc, (*it).nested, nullptr, iter);
    751         continue;
    752       }
    753     }
    754     TranslateStateValueDescriptor(value_desc, (*it).nested, translation, iter);
    755   }
    756   DCHECK_EQ(desc->GetSize(OutputFrameStateCombine::Ignore()), index);
    757 
    758   if (combine.kind() == OutputFrameStateCombine::kPushOutput) {
    759     DCHECK(combine.GetPushCount() <= iter->instruction()->OutputCount());
    760     for (size_t output = 0; output < combine.GetPushCount(); output++) {
    761       // Materialize the result of the call instruction in this slot.
    762       AddTranslationForOperand(translation, iter->instruction(),
    763                                iter->instruction()->OutputAt(output),
    764                                MachineType::AnyTagged());
    765     }
    766   }
    767 }
    768 
    769 
    770 void CodeGenerator::BuildTranslationForFrameStateDescriptor(
    771     FrameStateDescriptor* descriptor, InstructionOperandIterator* iter,
    772     Translation* translation, OutputFrameStateCombine state_combine) {
    773   // Outer-most state must be added to translation first.
    774   if (descriptor->outer_state() != nullptr) {
    775     BuildTranslationForFrameStateDescriptor(descriptor->outer_state(), iter,
    776                                             translation,
    777                                             OutputFrameStateCombine::Ignore());
    778   }
    779 
    780   Handle<SharedFunctionInfo> shared_info;
    781   if (!descriptor->shared_info().ToHandle(&shared_info)) {
    782     if (!info()->has_shared_info()) {
    783       return;  // Stub with no SharedFunctionInfo.
    784     }
    785     shared_info = info()->shared_info();
    786   }
    787   int shared_info_id = DefineDeoptimizationLiteral(shared_info);
    788 
    789   switch (descriptor->type()) {
    790     case FrameStateType::kJavaScriptFunction:
    791       translation->BeginJSFrame(
    792           descriptor->bailout_id(), shared_info_id,
    793           static_cast<unsigned int>(descriptor->GetSize(state_combine) -
    794                                     (1 + descriptor->parameters_count())));
    795       break;
    796     case FrameStateType::kInterpretedFunction:
    797       translation->BeginInterpretedFrame(
    798           descriptor->bailout_id(), shared_info_id,
    799           static_cast<unsigned int>(descriptor->locals_count() + 1));
    800       break;
    801     case FrameStateType::kArgumentsAdaptor:
    802       translation->BeginArgumentsAdaptorFrame(
    803           shared_info_id,
    804           static_cast<unsigned int>(descriptor->parameters_count()));
    805       break;
    806     case FrameStateType::kTailCallerFunction:
    807       translation->BeginTailCallerFrame(shared_info_id);
    808       break;
    809     case FrameStateType::kConstructStub:
    810       DCHECK(descriptor->bailout_id().IsValidForConstructStub());
    811       translation->BeginConstructStubFrame(
    812           descriptor->bailout_id(), shared_info_id,
    813           static_cast<unsigned int>(descriptor->parameters_count()));
    814       break;
    815     case FrameStateType::kGetterStub:
    816       translation->BeginGetterStubFrame(shared_info_id);
    817       break;
    818     case FrameStateType::kSetterStub:
    819       translation->BeginSetterStubFrame(shared_info_id);
    820       break;
    821   }
    822 
    823   TranslateFrameStateDescriptorOperands(descriptor, iter, state_combine,
    824                                         translation);
    825 }
    826 
    827 
    828 int CodeGenerator::BuildTranslation(Instruction* instr, int pc_offset,
    829                                     size_t frame_state_offset,
    830                                     OutputFrameStateCombine state_combine) {
    831   DeoptimizationEntry const& entry =
    832       GetDeoptimizationEntry(instr, frame_state_offset);
    833   FrameStateDescriptor* const descriptor = entry.descriptor();
    834   frame_state_offset++;
    835 
    836   Translation translation(
    837       &translations_, static_cast<int>(descriptor->GetFrameCount()),
    838       static_cast<int>(descriptor->GetJSFrameCount()), zone());
    839   InstructionOperandIterator iter(instr, frame_state_offset);
    840   BuildTranslationForFrameStateDescriptor(descriptor, &iter, &translation,
    841                                           state_combine);
    842 
    843   int deoptimization_id = static_cast<int>(deoptimization_states_.size());
    844 
    845   deoptimization_states_.push_back(new (zone()) DeoptimizationState(
    846       descriptor->bailout_id(), translation.index(), pc_offset, entry.kind(),
    847       entry.reason()));
    848 
    849   return deoptimization_id;
    850 }
    851 
    852 
    853 void CodeGenerator::AddTranslationForOperand(Translation* translation,
    854                                              Instruction* instr,
    855                                              InstructionOperand* op,
    856                                              MachineType type) {
    857   if (op->IsStackSlot()) {
    858     if (type.representation() == MachineRepresentation::kBit) {
    859       translation->StoreBoolStackSlot(LocationOperand::cast(op)->index());
    860     } else if (type == MachineType::Int8() || type == MachineType::Int16() ||
    861                type == MachineType::Int32()) {
    862       translation->StoreInt32StackSlot(LocationOperand::cast(op)->index());
    863     } else if (type == MachineType::Uint8() || type == MachineType::Uint16() ||
    864                type == MachineType::Uint32()) {
    865       translation->StoreUint32StackSlot(LocationOperand::cast(op)->index());
    866     } else {
    867       CHECK_EQ(MachineRepresentation::kTagged, type.representation());
    868       translation->StoreStackSlot(LocationOperand::cast(op)->index());
    869     }
    870   } else if (op->IsFPStackSlot()) {
    871     if (type.representation() == MachineRepresentation::kFloat64) {
    872       translation->StoreDoubleStackSlot(LocationOperand::cast(op)->index());
    873     } else {
    874       CHECK_EQ(MachineRepresentation::kFloat32, type.representation());
    875       translation->StoreFloatStackSlot(LocationOperand::cast(op)->index());
    876     }
    877   } else if (op->IsRegister()) {
    878     InstructionOperandConverter converter(this, instr);
    879     if (type.representation() == MachineRepresentation::kBit) {
    880       translation->StoreBoolRegister(converter.ToRegister(op));
    881     } else if (type == MachineType::Int8() || type == MachineType::Int16() ||
    882                type == MachineType::Int32()) {
    883       translation->StoreInt32Register(converter.ToRegister(op));
    884     } else if (type == MachineType::Uint8() || type == MachineType::Uint16() ||
    885                type == MachineType::Uint32()) {
    886       translation->StoreUint32Register(converter.ToRegister(op));
    887     } else {
    888       CHECK_EQ(MachineRepresentation::kTagged, type.representation());
    889       translation->StoreRegister(converter.ToRegister(op));
    890     }
    891   } else if (op->IsFPRegister()) {
    892     InstructionOperandConverter converter(this, instr);
    893     if (type.representation() == MachineRepresentation::kFloat64) {
    894       translation->StoreDoubleRegister(converter.ToDoubleRegister(op));
    895     } else {
    896       CHECK_EQ(MachineRepresentation::kFloat32, type.representation());
    897       translation->StoreFloatRegister(converter.ToFloatRegister(op));
    898     }
    899   } else {
    900     CHECK(op->IsImmediate());
    901     InstructionOperandConverter converter(this, instr);
    902     Constant constant = converter.ToConstant(op);
    903     Handle<Object> constant_object;
    904     switch (constant.type()) {
    905       case Constant::kInt32:
    906         if (type.representation() == MachineRepresentation::kTagged) {
    907           // When pointers are 4 bytes, we can use int32 constants to represent
    908           // Smis.
    909           DCHECK_EQ(4, kPointerSize);
    910           constant_object =
    911               handle(reinterpret_cast<Smi*>(constant.ToInt32()), isolate());
    912           DCHECK(constant_object->IsSmi());
    913         } else if (type.representation() == MachineRepresentation::kBit) {
    914           if (constant.ToInt32() == 0) {
    915             constant_object = isolate()->factory()->false_value();
    916           } else {
    917             DCHECK_EQ(1, constant.ToInt32());
    918             constant_object = isolate()->factory()->true_value();
    919           }
    920         } else {
    921           // TODO(jarin,bmeurer): We currently pass in raw pointers to the
    922           // JSFunction::entry here. We should really consider fixing this.
    923           DCHECK(type == MachineType::Int32() ||
    924                  type == MachineType::Uint32() ||
    925                  type.representation() == MachineRepresentation::kWord32 ||
    926                  type.representation() == MachineRepresentation::kNone);
    927           DCHECK(type.representation() != MachineRepresentation::kNone ||
    928                  constant.ToInt32() == FrameStateDescriptor::kImpossibleValue);
    929           if (type == MachineType::Uint32()) {
    930             constant_object =
    931                 isolate()->factory()->NewNumberFromUint(constant.ToInt32());
    932           } else {
    933             constant_object =
    934                 isolate()->factory()->NewNumberFromInt(constant.ToInt32());
    935           }
    936         }
    937         break;
    938       case Constant::kInt64:
    939         // When pointers are 8 bytes, we can use int64 constants to represent
    940         // Smis.
    941         // TODO(jarin,bmeurer): We currently pass in raw pointers to the
    942         // JSFunction::entry here. We should really consider fixing this.
    943         DCHECK(type.representation() == MachineRepresentation::kWord64 ||
    944                type.representation() == MachineRepresentation::kTagged);
    945         DCHECK_EQ(8, kPointerSize);
    946         constant_object =
    947             handle(reinterpret_cast<Smi*>(constant.ToInt64()), isolate());
    948         DCHECK(constant_object->IsSmi());
    949         break;
    950       case Constant::kFloat32:
    951         DCHECK(type.representation() == MachineRepresentation::kFloat32 ||
    952                type.representation() == MachineRepresentation::kTagged);
    953         constant_object = isolate()->factory()->NewNumber(constant.ToFloat32());
    954         break;
    955       case Constant::kFloat64:
    956         DCHECK(type.representation() == MachineRepresentation::kFloat64 ||
    957                type.representation() == MachineRepresentation::kTagged);
    958         constant_object = isolate()->factory()->NewNumber(constant.ToFloat64());
    959         break;
    960       case Constant::kHeapObject:
    961         DCHECK_EQ(MachineRepresentation::kTagged, type.representation());
    962         constant_object = constant.ToHeapObject();
    963         break;
    964       default:
    965         UNREACHABLE();
    966     }
    967     if (constant_object.is_identical_to(info()->closure())) {
    968       translation->StoreJSFrameFunction();
    969     } else {
    970       int literal_id = DefineDeoptimizationLiteral(constant_object);
    971       translation->StoreLiteral(literal_id);
    972     }
    973   }
    974 }
    975 
    976 
    977 void CodeGenerator::MarkLazyDeoptSite() {
    978   last_lazy_deopt_pc_ = masm()->pc_offset();
    979 }
    980 
    981 DeoptimizationExit* CodeGenerator::AddDeoptimizationExit(
    982     Instruction* instr, size_t frame_state_offset) {
    983   int const deoptimization_id = BuildTranslation(
    984       instr, -1, frame_state_offset, OutputFrameStateCombine::Ignore());
    985   DeoptimizationExit* const exit = new (zone())
    986       DeoptimizationExit(deoptimization_id, current_source_position_);
    987   deoptimization_exits_.push_back(exit);
    988   return exit;
    989 }
    990 
    991 OutOfLineCode::OutOfLineCode(CodeGenerator* gen)
    992     : frame_(gen->frame()), masm_(gen->masm()), next_(gen->ools_) {
    993   gen->ools_ = this;
    994 }
    995 
    996 
    997 OutOfLineCode::~OutOfLineCode() {}
    998 
    999 }  // namespace compiler
   1000 }  // namespace internal
   1001 }  // namespace v8
   1002