LCOV - code coverage report
Current view: top level - src/compiler/backend - code-generator.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 527 551 95.6 %
Date: 2019-02-19 Functions: 47 48 97.9 %

          Line data    Source code
       1             : // Copyright 2013 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/compiler/backend/code-generator.h"
       6             : 
       7             : #include "src/address-map.h"
       8             : #include "src/assembler-inl.h"
       9             : #include "src/base/adapters.h"
      10             : #include "src/compiler/backend/code-generator-impl.h"
      11             : #include "src/compiler/linkage.h"
      12             : #include "src/compiler/pipeline.h"
      13             : #include "src/compiler/wasm-compiler.h"
      14             : #include "src/counters.h"
      15             : #include "src/eh-frame.h"
      16             : #include "src/frames.h"
      17             : #include "src/log.h"
      18             : #include "src/macro-assembler-inl.h"
      19             : #include "src/objects/smi.h"
      20             : #include "src/optimized-compilation-info.h"
      21             : #include "src/string-constants.h"
      22             : 
      23             : namespace v8 {
      24             : namespace internal {
      25             : namespace compiler {
      26             : 
      27             : class CodeGenerator::JumpTable final : public ZoneObject {
      28             :  public:
      29             :   JumpTable(JumpTable* next, Label** targets, size_t target_count)
      30         314 :       : next_(next), targets_(targets), target_count_(target_count) {}
      31             : 
      32             :   Label* label() { return &label_; }
      33             :   JumpTable* next() const { return next_; }
      34             :   Label** targets() const { return targets_; }
      35             :   size_t target_count() const { return target_count_; }
      36             : 
      37             :  private:
      38             :   Label label_;
      39             :   JumpTable* const next_;
      40             :   Label** const targets_;
      41             :   size_t const target_count_;
      42             : };
      43             : 
      44     2141438 : CodeGenerator::CodeGenerator(
      45             :     Zone* codegen_zone, Frame* frame, Linkage* linkage,
      46    25865183 :     InstructionSequence* instructions, OptimizedCompilationInfo* info,
      47             :     Isolate* isolate, base::Optional<OsrHelper> osr_helper,
      48             :     int start_source_position, JumpOptimizationInfo* jump_opt,
      49             :     PoisoningMitigationLevel poisoning_level, const AssemblerOptions& options,
      50    12848724 :     int32_t builtin_index, std::unique_ptr<AssemblerBuffer> buffer)
      51             :     : zone_(codegen_zone),
      52             :       isolate_(isolate),
      53             :       frame_access_state_(nullptr),
      54             :       linkage_(linkage),
      55             :       instructions_(instructions),
      56             :       unwinding_info_writer_(zone()),
      57             :       info_(info),
      58     2141224 :       labels_(zone()->NewArray<Label>(instructions->InstructionBlockCount())),
      59             :       current_block_(RpoNumber::Invalid()),
      60             :       start_source_position_(start_source_position),
      61             :       current_source_position_(SourcePosition::Unknown()),
      62             :       tasm_(isolate, options, CodeObjectRequired::kNo, std::move(buffer)),
      63             :       resolver_(this),
      64             :       safepoints_(zone()),
      65             :       handlers_(zone()),
      66             :       deoptimization_exits_(zone()),
      67             :       deoptimization_states_(zone()),
      68             :       deoptimization_literals_(zone()),
      69             :       translations_(zone()),
      70             :       caller_registers_saved_(false),
      71             :       jump_tables_(nullptr),
      72             :       ools_(nullptr),
      73             :       osr_helper_(std::move(osr_helper)),
      74             :       osr_pc_offset_(-1),
      75             :       optimized_out_literal_id_(-1),
      76             :       source_position_table_builder_(
      77             :           SourcePositionTableBuilder::RECORD_SOURCE_POSITIONS),
      78             :       protected_instructions_(zone()),
      79             :       result_(kSuccess),
      80             :       poisoning_level_(poisoning_level),
      81             :       block_starts_(zone()),
      82    17131334 :       instr_starts_(zone()) {
      83    43165170 :   for (int i = 0; i < instructions->InstructionBlockCount(); ++i) {
      84    19441091 :     new (&labels_[i]) Label;
      85             :   }
      86     2141494 :   CreateFrameAccessState(frame);
      87     2141374 :   CHECK_EQ(info->is_osr(), osr_helper_.has_value());
      88             :   tasm_.set_jump_optimization_info(jump_opt);
      89             :   Code::Kind code_kind = info->code_kind();
      90     4282748 :   if (code_kind == Code::WASM_FUNCTION ||
      91     2141374 :       code_kind == Code::WASM_TO_JS_FUNCTION ||
      92     5918029 :       code_kind == Code::WASM_INTERPRETER_ENTRY ||
      93      121632 :       (Builtins::IsBuiltinId(builtin_index) &&
      94      121632 :        Builtins::IsWasmRuntimeStub(builtin_index))) {
      95             :     tasm_.set_abort_hard(true);
      96             :   }
      97             :   tasm_.set_builtin_index(builtin_index);
      98     2141374 : }
      99             : 
     100      271589 : bool CodeGenerator::wasm_runtime_exception_support() const {
     101             :   DCHECK_NOT_NULL(info_);
     102      543178 :   return info_->wasm_runtime_exception_support();
     103             : }
     104             : 
     105      238149 : void CodeGenerator::AddProtectedInstructionLanding(uint32_t instr_offset,
     106             :                                                    uint32_t landing_offset) {
     107      476357 :   protected_instructions_.push_back({instr_offset, landing_offset});
     108      238208 : }
     109             : 
     110     4282903 : void CodeGenerator::CreateFrameAccessState(Frame* frame) {
     111     2141467 :   FinishFrame(frame);
     112     2141466 :   frame_access_state_ = new (zone()) FrameAccessState(frame);
     113     2141466 : }
     114             : 
     115     3306870 : CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall(
     116     3306868 :     int deoptimization_id, SourcePosition pos) {
     117     3306870 :   if (deoptimization_id > Deoptimizer::kMaxNumberOfEntries) {
     118             :     return kTooManyDeoptimizationBailouts;
     119             :   }
     120             : 
     121     3306860 :   DeoptimizeKind deopt_kind = GetDeoptimizationKind(deoptimization_id);
     122             :   DeoptimizeReason deoptimization_reason =
     123     3306861 :       GetDeoptimizationReason(deoptimization_id);
     124             :   Address deopt_entry =
     125     3306869 :       Deoptimizer::GetDeoptimizationEntry(tasm()->isolate(), deopt_kind);
     126     3306868 :   if (info()->is_source_positions_enabled()) {
     127       99479 :     tasm()->RecordDeoptReason(deoptimization_reason, pos, deoptimization_id);
     128             :   }
     129     3306868 :   tasm()->CallForDeoptimization(deopt_entry, deoptimization_id);
     130     3306867 :   return kSuccess;
     131             : }
     132             : 
     133          36 : void CodeGenerator::MaybeEmitOutOfLineConstantPool() {
     134             :   tasm()->MaybeEmitOutOfLineConstantPool();
     135          36 : }
     136             : 
     137    49598162 : void CodeGenerator::AssembleCode() {
     138         126 :   OptimizedCompilationInfo* info = this->info();
     139             : 
     140             :   // Open a frame scope to indicate that there is a frame on the stack.  The
     141             :   // MANUAL indicates that the scope shouldn't actually generate code to set up
     142             :   // the frame (that is done in AssemblePrologue).
     143     2141424 :   FrameScope frame_scope(tasm(), StackFrame::MANUAL);
     144             : 
     145     2141408 :   if (info->is_source_positions_enabled()) {
     146       11105 :     AssembleSourcePosition(start_source_position());
     147             :   }
     148             : 
     149             :   // Check that {kJavaScriptCallCodeStartRegister} has been set correctly.
     150     2141560 :   if (FLAG_debug_code && (info->code_kind() == Code::OPTIMIZED_FUNCTION ||
     151             :                           info->code_kind() == Code::BYTECODE_HANDLER)) {
     152         110 :     tasm()->RecordComment("-- Prologue: check code start register --");
     153         110 :     AssembleCodeStartRegisterCheck();
     154             :   }
     155             : 
     156             :   // We want to bailout only from JS functions, which are the only ones
     157             :   // that are optimized.
     158     2141434 :   if (info->IsOptimizing()) {
     159             :     DCHECK(linkage()->GetIncomingDescriptor()->IsJSFunctionCall());
     160      456688 :     tasm()->RecordComment("-- Prologue: check for deoptimization --");
     161      456688 :     BailoutIfDeoptimized();
     162             :   }
     163             : 
     164     2141429 :   InitializeSpeculationPoison();
     165             : 
     166             :   // Define deoptimization literals for all inlined functions.
     167             :   DCHECK_EQ(0u, deoptimization_literals_.size());
     168     4348728 :   for (OptimizedCompilationInfo::InlinedFunctionHolder& inlined :
     169             :        info->inlined_functions()) {
     170       66098 :     if (!inlined.shared_info.equals(info->shared_info())) {
     171             :       int index = DefineDeoptimizationLiteral(
     172       65680 :           DeoptimizationLiteral(inlined.shared_info));
     173             :       inlined.RegisterInlinedFunctionId(index);
     174             :     }
     175             :   }
     176     2141315 :   inlined_function_count_ = deoptimization_literals_.size();
     177             : 
     178             :   // Define deoptimization literals for all BytecodeArrays to which we might
     179             :   // deopt to ensure they are strongly held by the optimized code.
     180     2141315 :   if (info->has_bytecode_array()) {
     181      456686 :     DefineDeoptimizationLiteral(DeoptimizationLiteral(info->bytecode_array()));
     182             :   }
     183     4348712 :   for (OptimizedCompilationInfo::InlinedFunctionHolder& inlined :
     184             :        info->inlined_functions()) {
     185       66098 :     DefineDeoptimizationLiteral(DeoptimizationLiteral(inlined.bytecode_array));
     186             :   }
     187             : 
     188             :   unwinding_info_writer_.SetNumberOfInstructionBlocks(
     189     2141307 :       instructions()->InstructionBlockCount());
     190             : 
     191     2141062 :   if (info->trace_turbo_json_enabled()) {
     192          27 :     block_starts_.assign(instructions()->instruction_blocks().size(), -1);
     193           6 :     instr_starts_.assign(instructions()->instructions().size(), -1);
     194             :   }
     195             : 
     196             :   // Assemble instructions in assembly order.
     197    62613043 :   for (const InstructionBlock* block : instructions()->ao_blocks()) {
     198             :     // Align loop headers on vendor recommended boundaries.
     199    19440916 :     if (block->ShouldAlign() && !tasm()->jump_optimization_info()) {
     200       57812 :       tasm()->CodeTargetAlign();
     201             :     }
     202    19440948 :     if (info->trace_turbo_json_enabled()) {
     203          57 :       block_starts_[block->rpo_number().ToInt()] = tasm()->pc_offset();
     204             :     }
     205             :     // Bind a label for a block.
     206    19440948 :     current_block_ = block->rpo_number();
     207    38881896 :     unwinding_info_writer_.BeginInstructionBlock(tasm()->pc_offset(), block);
     208    19440926 :     if (FLAG_code_comments) {
     209        1984 :       std::ostringstream buffer;
     210        1984 :       buffer << "-- B" << block->rpo_number().ToInt() << " start";
     211        1984 :       if (block->IsDeferred()) buffer << " (deferred)";
     212        1984 :       if (!block->needs_frame()) buffer << " (no frame)";
     213        1984 :       if (block->must_construct_frame()) buffer << " (construct frame)";
     214        1984 :       if (block->must_deconstruct_frame()) buffer << " (deconstruct frame)";
     215             : 
     216        1984 :       if (block->IsLoopHeader()) {
     217          18 :         buffer << " (loop up to " << block->loop_end().ToInt() << ")";
     218             :       }
     219        1984 :       if (block->loop_header().IsValid()) {
     220         819 :         buffer << " (in loop " << block->loop_header().ToInt() << ")";
     221             :       }
     222        1984 :       buffer << " --";
     223        3968 :       tasm()->RecordComment(buffer.str().c_str());
     224             :     }
     225             : 
     226    38881852 :     frame_access_state()->MarkHasFrame(block->needs_frame());
     227             : 
     228    19440982 :     tasm()->bind(GetLabel(current_block_));
     229             : 
     230    19441037 :     TryInsertBranchPoisoning(block);
     231             : 
     232    19440912 :     if (block->must_construct_frame()) {
     233     2151225 :       AssembleConstructFrame();
     234             :       // We need to setup the root register after we assemble the prologue, to
     235             :       // avoid clobbering callee saved registers in case of C linkage and
     236             :       // using the roots.
     237             :       // TODO(mtrofin): investigate how we can avoid doing this repeatedly.
     238     2151183 :       if (linkage()->GetIncomingDescriptor()->InitializeRootRegister()) {
     239      888336 :         tasm()->InitializeRootRegister();
     240             :       }
     241             :     }
     242             : 
     243             :     if (FLAG_enable_embedded_constant_pool && !block->needs_frame()) {
     244             :       ConstantPoolUnavailableScope constant_pool_unavailable(tasm());
     245             :       result_ = AssembleBlock(block);
     246             :     } else {
     247    19440870 :       result_ = AssembleBlock(block);
     248             :     }
     249    19441192 :     if (result_ != kSuccess) return;
     250    19441229 :     unwinding_info_writer_.EndInstructionBlock(block);
     251             :   }
     252             : 
     253             :   // Assemble all out-of-line code.
     254     2141291 :   if (ools_) {
     255      140311 :     tasm()->RecordComment("-- Out of line code --");
     256      790674 :     for (OutOfLineCode* ool = ools_; ool; ool = ool->next()) {
     257      650375 :       tasm()->bind(ool->entry());
     258      650385 :       ool->Generate();
     259      650395 :       if (ool->exit()->is_bound()) tasm()->jmp(ool->exit());
     260             :     }
     261             :   }
     262             : 
     263             :   // This nop operation is needed to ensure that the trampoline is not
     264             :   // confused with the pc of the call before deoptimization.
     265             :   // The test regress/regress-259 is an example of where we need it.
     266     2141279 :   tasm()->nop();
     267             : 
     268             :   // Assemble deoptimization exits.
     269             :   int last_updated = 0;
     270    11924976 :   for (DeoptimizationExit* exit : deoptimization_exits_) {
     271     3261254 :     tasm()->bind(exit->label());
     272     3261258 :     int trampoline_pc = tasm()->pc_offset();
     273             :     int deoptimization_id = exit->deoptimization_id();
     274     6189283 :     DeoptimizationState* ds = deoptimization_states_[deoptimization_id];
     275             : 
     276     3261258 :     if (ds->kind() == DeoptimizeKind::kLazy) {
     277             :       last_updated = safepoints()->UpdateDeoptimizationInfo(
     278     2928025 :           ds->pc_offset(), trampoline_pc, last_updated);
     279             :     }
     280     3261262 :     result_ = AssembleDeoptimizerCall(deoptimization_id, exit->pos());
     281     3261265 :     if (result_ != kSuccess) return;
     282             :   }
     283             : 
     284             :   // TODO(jgruber): Move all inlined metadata generation into a new,
     285             :   // architecture-independent version of FinishCode. Currently, this includes
     286             :   // the safepoint table, handler table, constant pool, and code comments, in
     287             :   // that order.
     288     2141210 :   FinishCode();
     289             : 
     290             :   // Emit the jump tables.
     291     2141274 :   if (jump_tables_) {
     292         312 :     tasm()->Align(kSystemPointerSize);
     293         940 :     for (JumpTable* table = jump_tables_; table; table = table->next()) {
     294         314 :       tasm()->bind(table->label());
     295         314 :       AssembleJumpTable(table->targets(), table->target_count());
     296             :     }
     297             :   }
     298             : 
     299             :   // The PerfJitLogger logs code up until here, excluding the safepoint
     300             :   // table. Resolve the unwinding info now so it is aware of the same code
     301             :   // size as reported by perf.
     302     2141274 :   unwinding_info_writer_.Finish(tasm()->pc_offset());
     303             : 
     304     2141274 :   safepoints()->Emit(tasm(), frame()->GetTotalFrameSlotCount());
     305             : 
     306             :   // Emit the exception handler table.
     307     2379595 :   if (!handlers_.empty()) {
     308             :     handler_table_offset_ = HandlerTable::EmitReturnTableStart(
     309       19888 :         tasm(), static_cast<int>(handlers_.size()));
     310      476484 :     for (size_t i = 0; i < handlers_.size(); ++i) {
     311             :       HandlerTable::EmitReturnEntry(tasm(), handlers_[i].pc_offset,
     312      218354 :                                     handlers_[i].handler->pos());
     313             :     }
     314             :   }
     315             : 
     316             :   tasm()->MaybeEmitOutOfLineConstantPool();
     317     2141353 :   tasm()->FinalizeJumpOptimizationInfo();
     318             : 
     319     2141249 :   result_ = kSuccess;
     320             : }
     321             : 
     322    32997915 : void CodeGenerator::TryInsertBranchPoisoning(const InstructionBlock* block) {
     323             :   // See if our predecessor was a basic block terminated by a branch_and_poison
     324             :   // instruction. If yes, then perform the masking based on the flags.
     325    25325160 :   if (block->PredecessorCount() != 1) return;
     326    13556877 :   RpoNumber pred_rpo = (block->predecessors())[0];
     327    13556877 :   const InstructionBlock* pred = instructions()->InstructionBlockAt(pred_rpo);
     328    13556829 :   if (pred->code_start() == pred->code_end()) return;
     329    27113759 :   Instruction* instr = instructions()->InstructionAt(pred->code_end() - 1);
     330    13556891 :   FlagsMode mode = FlagsModeField::decode(instr->opcode());
     331    13556891 :   switch (mode) {
     332             :     case kFlags_branch_and_poison: {
     333             :       BranchInfo branch;
     334           0 :       RpoNumber target = ComputeBranchInfo(&branch, instr);
     335           0 :       if (!target.IsValid()) {
     336             :         // Non-trivial branch, add the masking code.
     337           0 :         FlagsCondition condition = branch.condition;
     338           0 :         if (branch.false_label == GetLabel(block->rpo_number())) {
     339             :           condition = NegateFlagsCondition(condition);
     340             :         }
     341           0 :         AssembleBranchPoisoning(condition, instr);
     342             :       }
     343             :       break;
     344             :     }
     345             :     case kFlags_deoptimize_and_poison: {
     346           0 :       UNREACHABLE();
     347             :       break;
     348             :     }
     349             :     default:
     350             :       break;
     351             :   }
     352             : }
     353             : 
     354      124998 : void CodeGenerator::AssembleArchBinarySearchSwitchRange(
     355             :     Register input, RpoNumber def_block, std::pair<int32_t, Label*>* begin,
     356             :     std::pair<int32_t, Label*>* end) {
     357      124998 :   if (end - begin < kBinarySearchSwitchMinimalCases) {
     358      282106 :     while (begin != end) {
     359      202246 :       tasm()->JumpIfEqual(input, begin->first, begin->second);
     360      202246 :       ++begin;
     361             :     }
     362       79860 :     AssembleArchJump(def_block);
     363      204858 :     return;
     364             :   }
     365       45138 :   auto middle = begin + (end - begin) / 2;
     366       45138 :   Label less_label;
     367       45138 :   tasm()->JumpIfLessThan(input, middle->first, &less_label);
     368       45138 :   AssembleArchBinarySearchSwitchRange(input, def_block, middle, end);
     369       45138 :   tasm()->bind(&less_label);
     370       45138 :   AssembleArchBinarySearchSwitchRange(input, def_block, begin, middle);
     371             : }
     372             : 
     373      505465 : OwnedVector<byte> CodeGenerator::GetSourcePositionTable() {
     374      505465 :   return source_position_table_builder_.ToSourcePositionTableVector();
     375             : }
     376             : 
     377             : OwnedVector<trap_handler::ProtectedInstructionData>
     378      505506 : CodeGenerator::GetProtectedInstructions() {
     379             :   return OwnedVector<trap_handler::ProtectedInstructionData>::Of(
     380      505506 :       protected_instructions_);
     381             : }
     382             : 
     383    12633580 : MaybeHandle<Code> CodeGenerator::FinalizeCode() {
     384     1579198 :   if (result_ != kSuccess) {
     385           9 :     tasm()->AbortedCodeGeneration();
     386           9 :     return MaybeHandle<Code>();
     387             :   }
     388             : 
     389             :   // Allocate the source position table.
     390             :   Handle<ByteArray> source_positions =
     391     1579189 :       source_position_table_builder_.ToSourcePositionTable(isolate());
     392             : 
     393             :   // Allocate deoptimization data.
     394     1579192 :   Handle<DeoptimizationData> deopt_data = GenerateDeoptimizationData();
     395             : 
     396             :   // Allocate and install the code.
     397     1579199 :   CodeDesc desc;
     398     3158398 :   tasm()->GetCode(isolate(), &desc, safepoints(), handler_table_offset_);
     399     1579198 :   if (unwinding_info_writer_.eh_frame_writer()) {
     400          22 :     unwinding_info_writer_.eh_frame_writer()->GetEhFrame(&desc);
     401             :   }
     402             : 
     403             :   MaybeHandle<Code> maybe_code = isolate()->factory()->TryNewCode(
     404             :       desc, info()->code_kind(), Handle<Object>(), info()->builtin_index(),
     405             :       source_positions, deopt_data, kMovable, true,
     406     6316792 :       frame()->GetTotalFrameSlotCount());
     407             : 
     408             :   Handle<Code> code;
     409     1579200 :   if (!maybe_code.ToHandle(&code)) {
     410           0 :     tasm()->AbortedCodeGeneration();
     411           0 :     return MaybeHandle<Code>();
     412             :   }
     413             : 
     414             :   isolate()->counters()->total_compiled_code_size()->Increment(
     415     1579200 :       code->raw_instruction_size());
     416             : 
     417     1579272 :   LOG_CODE_EVENT(isolate(),
     418             :                  CodeLinePosInfoRecordEvent(code->raw_instruction_start(),
     419             :                                             *source_positions));
     420             : 
     421     1579200 :   return code;
     422             : }
     423             : 
     424    15725024 : bool CodeGenerator::IsNextInAssemblyOrder(RpoNumber block) const {
     425             :   return instructions()
     426             :       ->InstructionBlockAt(current_block_)
     427    15725050 :       ->ao_number()
     428    31450075 :       .IsNext(instructions()->InstructionBlockAt(block)->ao_number());
     429             : }
     430             : 
     431     5812978 : void CodeGenerator::RecordSafepoint(ReferenceMap* references,
     432             :                                     Safepoint::Kind kind,
     433     5812988 :                                     Safepoint::DeoptMode deopt_mode) {
     434     5812978 :   Safepoint safepoint = safepoints()->DefineSafepoint(tasm(), kind, deopt_mode);
     435             :   int stackSlotToSpillSlotDelta =
     436     5812988 :       frame()->GetTotalFrameSlotCount() - frame()->GetSpillSlotCount();
     437    88947076 :   for (const InstructionOperand& operand : references->reference_operands()) {
     438    77320989 :     if (operand.IsStackSlot()) {
     439             :       int index = LocationOperand::cast(operand).index();
     440             :       DCHECK_LE(0, index);
     441             :       // We might index values in the fixed part of the frame (i.e. the
     442             :       // closure pointer or the context pointer); these are not spill slots
     443             :       // and therefore don't work with the SafepointTable currently, but
     444             :       // we also don't need to worry about them, since the GC has special
     445             :       // knowledge about those fields anyway.
     446    15982929 :       if (index < stackSlotToSpillSlotDelta) continue;
     447    15982425 :       safepoint.DefinePointerSlot(index);
     448    61338060 :     } else if (operand.IsRegister() && (kind & Safepoint::kWithRegisters)) {
     449           0 :       Register reg = LocationOperand::cast(operand).GetRegister();
     450           0 :       safepoint.DefinePointerRegister(reg);
     451             :     }
     452             :   }
     453     5813099 : }
     454             : 
     455     8361588 : bool CodeGenerator::IsMaterializableFromRoot(Handle<HeapObject> object,
     456    15880903 :                                              RootIndex* index_return) {
     457             :   const CallDescriptor* incoming_descriptor =
     458             :       linkage()->GetIncomingDescriptor();
     459     8361588 :   if (incoming_descriptor->flags() & CallDescriptor::kCanUseRoots) {
     460     9372187 :     return isolate()->roots_table().IsRootHandle(object, index_return) &&
     461     9372187 :            RootsTable::IsImmortalImmovable(*index_return);
     462             :   }
     463             :   return false;
     464             : }
     465             : 
     466    19440864 : CodeGenerator::CodeGenResult CodeGenerator::AssembleBlock(
     467   228399688 :     const InstructionBlock* block) {
     468   165227056 :   for (int i = block->code_start(); i < block->code_end(); ++i) {
     469    63172648 :     if (info()->trace_turbo_json_enabled()) {
     470         189 :       instr_starts_[i] = tasm()->pc_offset();
     471             :     }
     472             :     Instruction* instr = instructions()->InstructionAt(i);
     473    63172675 :     CodeGenResult result = AssembleInstruction(instr, block);
     474    63172516 :     if (result != kSuccess) return result;
     475             :   }
     476             :   return kSuccess;
     477             : }
     478             : 
     479       36368 : bool CodeGenerator::IsValidPush(InstructionOperand source,
     480             :                                 CodeGenerator::PushTypeFlags push_type) {
     481       36368 :   if (source.IsImmediate() &&
     482             :       ((push_type & CodeGenerator::kImmediatePush) != 0)) {
     483             :     return true;
     484             :   }
     485       59856 :   if (source.IsRegister() &&
     486             :       ((push_type & CodeGenerator::kRegisterPush) != 0)) {
     487             :     return true;
     488             :   }
     489       24992 :   if (source.IsStackSlot() &&
     490             :       ((push_type & CodeGenerator::kStackSlotPush) != 0)) {
     491             :     return true;
     492             :   }
     493         768 :   return false;
     494             : }
     495             : 
     496      119308 : void CodeGenerator::GetPushCompatibleMoves(Instruction* instr,
     497             :                                            PushTypeFlags push_type,
     498             :                                            ZoneVector<MoveOperands*>* pushes) {
     499      174212 :   pushes->clear();
     500      325332 :   for (int i = Instruction::FIRST_GAP_POSITION;
     501             :        i <= Instruction::LAST_GAP_POSITION; ++i) {
     502             :     Instruction::GapPosition inner_pos =
     503             :         static_cast<Instruction::GapPosition>(i);
     504             :     ParallelMove* parallel_move = instr->GetParallelMove(inner_pos);
     505      222320 :     if (parallel_move != nullptr) {
     506      682462 :       for (auto move : *parallel_move) {
     507      428686 :         InstructionOperand source = move->source();
     508      428686 :         InstructionOperand destination = move->destination();
     509             :         int first_push_compatible_index =
     510             :             V8_TARGET_ARCH_STORES_RETURN_ADDRESS_ON_STACK ? 1 : 0;
     511             :         // If there are any moves from slots that will be overridden by pushes,
     512             :         // then the full gap resolver must be used since optimization with
     513             :         // pushes don't participate in the parallel move and might clobber
     514             :         // values needed for the gap resolve.
     515      457618 :         if (source.IsStackSlot() && LocationOperand::cast(source).index() >=
     516             :                                         first_push_compatible_index) {
     517             :           pushes->clear();
     518      119308 :           return;
     519             :         }
     520             :         // TODO(danno): Right now, only consider moves from the FIRST gap for
     521             :         // pushes. Theoretically, we could extract pushes for both gaps (there
     522             :         // are cases where this happens), but the logic for that would also have
     523             :         // to check to make sure that non-memory inputs to the pushes from the
     524             :         // LAST gap don't get clobbered in the FIRST gap.
     525      412390 :         if (i == Instruction::FIRST_GAP_POSITION) {
     526      467394 :           if (destination.IsStackSlot() &&
     527             :               LocationOperand::cast(destination).index() >=
     528             :                   first_push_compatible_index) {
     529             :             int index = LocationOperand::cast(destination).index();
     530       36368 :             if (IsValidPush(source, push_type)) {
     531       35600 :               if (index >= static_cast<int>(pushes->size())) {
     532       35600 :                 pushes->resize(index + 1);
     533             :               }
     534       71200 :               (*pushes)[index] = move;
     535             :             }
     536             :           }
     537             :         }
     538             :       }
     539             :     }
     540             :   }
     541             : 
     542             :   // For now, only support a set of continuous pushes at the end of the list.
     543             :   size_t push_count_upper_bound = pushes->size();
     544             :   size_t push_begin = push_count_upper_bound;
     545      173096 :   for (auto move : base::Reversed(*pushes)) {
     546       41092 :     if (move == nullptr) break;
     547       28992 :     push_begin--;
     548             :   }
     549      103012 :   size_t push_count = pushes->size() - push_begin;
     550             :   std::copy(pushes->begin() + push_begin,
     551             :             pushes->begin() + push_begin + push_count, pushes->begin());
     552      103012 :   pushes->resize(push_count);
     553             : }
     554             : 
     555    35844273 : CodeGenerator::MoveType::Type CodeGenerator::MoveType::InferMove(
     556             :     InstructionOperand* source, InstructionOperand* destination) {
     557    35844273 :   if (source->IsConstant()) {
     558    18559258 :     if (destination->IsAnyRegister()) {
     559             :       return MoveType::kConstantToRegister;
     560             :     } else {
     561             :       DCHECK(destination->IsAnyStackSlot());
     562       45287 :       return MoveType::kConstantToStack;
     563             :     }
     564             :   }
     565             :   DCHECK(LocationOperand::cast(source)->IsCompatible(
     566             :       LocationOperand::cast(destination)));
     567    17285015 :   if (source->IsAnyRegister()) {
     568     9053985 :     if (destination->IsAnyRegister()) {
     569             :       return MoveType::kRegisterToRegister;
     570             :     } else {
     571             :       DCHECK(destination->IsAnyStackSlot());
     572     4948630 :       return MoveType::kRegisterToStack;
     573             :     }
     574             :   } else {
     575             :     DCHECK(source->IsAnyStackSlot());
     576     8231030 :     if (destination->IsAnyRegister()) {
     577             :       return MoveType::kStackToRegister;
     578             :     } else {
     579             :       DCHECK(destination->IsAnyStackSlot());
     580       44286 :       return MoveType::kStackToStack;
     581             :     }
     582             :   }
     583             : }
     584             : 
     585       75903 : CodeGenerator::MoveType::Type CodeGenerator::MoveType::InferSwap(
     586             :     InstructionOperand* source, InstructionOperand* destination) {
     587             :   DCHECK(LocationOperand::cast(source)->IsCompatible(
     588             :       LocationOperand::cast(destination)));
     589       75903 :   if (source->IsAnyRegister()) {
     590       72186 :     if (destination->IsAnyRegister()) {
     591             :       return MoveType::kRegisterToRegister;
     592             :     } else {
     593             :       DCHECK(destination->IsAnyStackSlot());
     594        6899 :       return MoveType::kRegisterToStack;
     595             :     }
     596             :   } else {
     597             :     DCHECK(source->IsAnyStackSlot());
     598             :     DCHECK(destination->IsAnyStackSlot());
     599             :     return MoveType::kStackToStack;
     600             :   }
     601             : }
     602             : 
     603     5358488 : RpoNumber CodeGenerator::ComputeBranchInfo(BranchInfo* branch,
     604    26786050 :                                            Instruction* instr) {
     605             :   // Assemble a branch after this instruction.
     606             :   InstructionOperandConverter i(this, instr);
     607     5358488 :   RpoNumber true_rpo = i.InputRpo(instr->InputCount() - 2);
     608     5358500 :   RpoNumber false_rpo = i.InputRpo(instr->InputCount() - 1);
     609             : 
     610     5358503 :   if (true_rpo == false_rpo) {
     611        2147 :     return true_rpo;
     612             :   }
     613     5356356 :   FlagsCondition condition = FlagsConditionField::decode(instr->opcode());
     614     5356356 :   if (IsNextInAssemblyOrder(true_rpo)) {
     615             :     // true block is next, can fall through if condition negated.
     616             :     std::swap(true_rpo, false_rpo);
     617             :     condition = NegateFlagsCondition(condition);
     618             :   }
     619     5356353 :   branch->condition = condition;
     620     5356353 :   branch->true_label = GetLabel(true_rpo);
     621     5356353 :   branch->false_label = GetLabel(false_rpo);
     622     5356353 :   branch->fallthru = IsNextInAssemblyOrder(false_rpo);
     623             :   return RpoNumber::Invalid();
     624             : }
     625             : 
     626    63172641 : CodeGenerator::CodeGenResult CodeGenerator::AssembleInstruction(
     627   194445764 :     Instruction* instr, const InstructionBlock* block) {
     628             :   int first_unused_stack_slot;
     629    63172641 :   FlagsMode mode = FlagsModeField::decode(instr->opcode());
     630    63172641 :   if (mode != kFlags_trap) {
     631    63139378 :     AssembleSourcePosition(instr);
     632             :   }
     633             :   bool adjust_stack =
     634    63172802 :       GetSlotAboveSPBeforeTailCall(instr, &first_unused_stack_slot);
     635    63173149 :   if (adjust_stack) AssembleTailCallBeforeGap(instr, first_unused_stack_slot);
     636    63173149 :   AssembleGaps(instr);
     637    63173051 :   if (adjust_stack) AssembleTailCallAfterGap(instr, first_unused_stack_slot);
     638             :   DCHECK_IMPLIES(
     639             :       block->must_deconstruct_frame(),
     640             :       instr != instructions()->InstructionAt(block->last_instruction_index()) ||
     641             :           instr->IsRet() || instr->IsJump());
     642    68103231 :   if (instr->IsJump() && block->must_deconstruct_frame()) {
     643       48502 :     AssembleDeconstructFrame();
     644             :   }
     645             :   // Assemble architecture-specific code for the instruction.
     646    63173123 :   CodeGenResult result = AssembleArchInstruction(instr);
     647    63172419 :   if (result != kSuccess) return result;
     648             : 
     649    63172587 :   FlagsCondition condition = FlagsConditionField::decode(instr->opcode());
     650    63172587 :   switch (mode) {
     651             :     case kFlags_branch:
     652             :     case kFlags_branch_and_poison: {
     653             :       BranchInfo branch;
     654     5358491 :       RpoNumber target = ComputeBranchInfo(&branch, instr);
     655     5358501 :       if (target.IsValid()) {
     656             :         // redundant branch.
     657        2147 :         if (!IsNextInAssemblyOrder(target)) {
     658         320 :           AssembleArchJump(target);
     659             :         }
     660        2147 :         return kSuccess;
     661             :       }
     662             :       // Assemble architecture-specific branch.
     663     5356354 :       AssembleArchBranch(instr, &branch);
     664     5356332 :       break;
     665             :     }
     666             :     case kFlags_deoptimize:
     667             :     case kFlags_deoptimize_and_poison: {
     668             :       // Assemble a conditional eager deoptimization after this instruction.
     669             :       InstructionOperandConverter i(this, instr);
     670      333239 :       size_t frame_state_offset = MiscField::decode(instr->opcode());
     671             :       DeoptimizationExit* const exit =
     672      333239 :           AddDeoptimizationExit(instr, frame_state_offset);
     673      333240 :       Label continue_label;
     674             :       BranchInfo branch;
     675      333240 :       branch.condition = condition;
     676      333240 :       branch.true_label = exit->label();
     677      333240 :       branch.false_label = &continue_label;
     678      333240 :       branch.fallthru = true;
     679             :       // Assemble architecture-specific branch.
     680      333240 :       AssembleArchDeoptBranch(instr, &branch);
     681      333238 :       tasm()->bind(&continue_label);
     682      333240 :       if (mode == kFlags_deoptimize_and_poison) {
     683           0 :         AssembleBranchPoisoning(NegateFlagsCondition(branch.condition), instr);
     684             :       }
     685             :       break;
     686             :     }
     687             :     case kFlags_set: {
     688             :       // Assemble a boolean materialization after this instruction.
     689      376860 :       AssembleArchBoolean(instr, condition);
     690      376859 :       break;
     691             :     }
     692             :     case kFlags_trap: {
     693       33448 :       AssembleArchTrap(instr, condition);
     694       33447 :       break;
     695             :     }
     696             :     case kFlags_none: {
     697             :       break;
     698             :     }
     699             :   }
     700             : 
     701             :   // TODO(jarin) We should thread the flag through rather than set it.
     702    63170428 :   if (instr->IsCall()) {
     703             :     ResetSpeculationPoison();
     704             :   }
     705             : 
     706             :   return kSuccess;
     707             : }
     708             : 
     709   103567624 : void CodeGenerator::AssembleSourcePosition(Instruction* instr) {
     710    63257831 :   SourcePosition source_position = SourcePosition::Unknown();
     711   121867479 :   if (instr->IsNop() && instr->AreMovesRedundant()) return;
     712    40309793 :   if (!instructions()->GetSourcePosition(instr, &source_position)) return;
     713     4648531 :   AssembleSourcePosition(source_position);
     714             : }
     715             : 
     716     4660667 : void CodeGenerator::AssembleSourcePosition(SourcePosition source_position) {
     717     4659630 :   if (source_position == current_source_position_) return;
     718     3512455 :   current_source_position_ = source_position;
     719     3512455 :   if (!source_position.IsKnown()) return;
     720     3512415 :   source_position_table_builder_.AddPosition(tasm()->pc_offset(),
     721     3512415 :                                              source_position, false);
     722     3512536 :   if (FLAG_code_comments) {
     723             :     OptimizedCompilationInfo* info = this->info();
     724        1037 :     if (info->IsNotOptimizedFunctionOrWasmFunction()) return;
     725        1037 :     std::ostringstream buffer;
     726        1037 :     buffer << "-- ";
     727             :     // Turbolizer only needs the source position, as it can reconstruct
     728             :     // the inlining stack from other information.
     729        2074 :     if (info->trace_turbo_json_enabled() || !tasm()->isolate() ||
     730        1037 :         tasm()->isolate()->concurrent_recompilation_enabled()) {
     731         153 :       buffer << source_position;
     732             :     } else {
     733             :       AllowHeapAllocation allocation;
     734             :       AllowHandleAllocation handles;
     735             :       AllowHandleDereference deref;
     736        1768 :       buffer << source_position.InliningStack(info);
     737             :     }
     738        1037 :     buffer << " --";
     739        2074 :     tasm()->RecordComment(buffer.str().c_str());
     740             :   }
     741             : }
     742             : 
     743    63292115 : bool CodeGenerator::GetSlotAboveSPBeforeTailCall(Instruction* instr,
     744             :                                                  int* slot) {
     745    63172819 :   if (instr->IsTailCall()) {
     746             :     InstructionOperandConverter g(this, instr);
     747      119296 :     *slot = g.InputInt32(instr->InputCount() - 1);
     748             :     return true;
     749             :   } else {
     750             :     return false;
     751             :   }
     752             : }
     753             : 
     754      458776 : StubCallMode CodeGenerator::DetermineStubCallMode() const {
     755      458776 :   Code::Kind code_kind = info()->code_kind();
     756      458776 :   return (code_kind == Code::WASM_FUNCTION ||
     757             :           code_kind == Code::WASM_TO_JS_FUNCTION)
     758             :              ? StubCallMode::kCallWasmRuntimeStub
     759      458776 :              : StubCallMode::kCallCodeObject;
     760             : }
     761             : 
     762    63172848 : void CodeGenerator::AssembleGaps(Instruction* instr) {
     763   189518450 :   for (int i = Instruction::FIRST_GAP_POSITION;
     764             :        i <= Instruction::LAST_GAP_POSITION; i++) {
     765             :     Instruction::GapPosition inner_pos =
     766             :         static_cast<Instruction::GapPosition>(i);
     767             :     ParallelMove* move = instr->GetParallelMove(inner_pos);
     768   126345352 :     if (move != nullptr) resolver()->Resolve(move);
     769             :   }
     770    63173098 : }
     771             : 
     772             : namespace {
     773             : 
     774      456573 : Handle<PodArray<InliningPosition>> CreateInliningPositions(
     775             :     OptimizedCompilationInfo* info, Isolate* isolate) {
     776      535815 :   const OptimizedCompilationInfo::InlinedFunctionList& inlined_functions =
     777             :       info->inlined_functions();
     778      456573 :   if (inlined_functions.size() == 0) {
     779             :     return Handle<PodArray<InliningPosition>>::cast(
     780      443310 :         isolate->factory()->empty_byte_array());
     781             :   }
     782             :   Handle<PodArray<InliningPosition>> inl_positions =
     783             :       PodArray<InliningPosition>::New(
     784       13263 :           isolate, static_cast<int>(inlined_functions.size()), TENURED);
     785      158484 :   for (size_t i = 0; i < inlined_functions.size(); ++i) {
     786             :     inl_positions->set(static_cast<int>(i), inlined_functions[i].position);
     787             :   }
     788       13263 :   return inl_positions;
     789             : }
     790             : 
     791             : }  // namespace
     792             : 
     793     6307298 : Handle<DeoptimizationData> CodeGenerator::GenerateDeoptimizationData() {
     794      456574 :   OptimizedCompilationInfo* info = this->info();
     795     1579195 :   int deopt_count = static_cast<int>(deoptimization_states_.size());
     796     2701818 :   if (deopt_count == 0 && !info->is_osr()) {
     797     1122623 :     return DeoptimizationData::Empty(isolate());
     798             :   }
     799             :   Handle<DeoptimizationData> data =
     800      456572 :       DeoptimizationData::New(isolate(), deopt_count, TENURED);
     801             : 
     802             :   Handle<ByteArray> translation_array =
     803      456571 :       translations_.CreateByteArray(isolate()->factory());
     804             : 
     805      913146 :   data->SetTranslationByteArray(*translation_array);
     806             :   data->SetInlinedFunctionCount(
     807      456574 :       Smi::FromInt(static_cast<int>(inlined_function_count_)));
     808             :   data->SetOptimizationId(Smi::FromInt(info->optimization_id()));
     809             : 
     810      456574 :   if (info->has_shared_info()) {
     811      913148 :     data->SetSharedFunctionInfo(*info->shared_info());
     812             :   } else {
     813           0 :     data->SetSharedFunctionInfo(Smi::kZero);
     814             :   }
     815             : 
     816             :   Handle<FixedArray> literals = isolate()->factory()->NewFixedArray(
     817      913148 :       static_cast<int>(deoptimization_literals_.size()), TENURED);
     818     4471528 :   for (unsigned i = 0; i < deoptimization_literals_.size(); i++) {
     819     1779190 :     Handle<Object> object = deoptimization_literals_[i].Reify(isolate());
     820     3558387 :     literals->set(i, *object);
     821             :   }
     822      913147 :   data->SetLiteralArray(*literals);
     823             : 
     824             :   Handle<PodArray<InliningPosition>> inl_pos =
     825      456573 :       CreateInliningPositions(info, isolate());
     826      913147 :   data->SetInliningPositions(*inl_pos);
     827             : 
     828      456574 :   if (info->is_osr()) {
     829             :     DCHECK_LE(0, osr_pc_offset_);
     830        4991 :     data->SetOsrBytecodeOffset(Smi::FromInt(info_->osr_offset().ToInt()));
     831        4991 :     data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
     832             :   } else {
     833             :     BailoutId osr_offset = BailoutId::None();
     834             :     data->SetOsrBytecodeOffset(Smi::FromInt(osr_offset.ToInt()));
     835             :     data->SetOsrPcOffset(Smi::FromInt(-1));
     836             :   }
     837             : 
     838             :   // Populate deoptimization entries.
     839     3272608 :   for (int i = 0; i < deopt_count; i++) {
     840     9817826 :     DeoptimizationState* deoptimization_state = deoptimization_states_[i];
     841     6545218 :     data->SetBytecodeOffset(i, deoptimization_state->bailout_id());
     842     3272609 :     CHECK(deoptimization_state);
     843             :     data->SetTranslationIndex(
     844     3272609 :         i, Smi::FromInt(deoptimization_state->translation_id()));
     845     3272608 :     data->SetPc(i, Smi::FromInt(deoptimization_state->pc_offset()));
     846             :   }
     847             : 
     848      456574 :   return data;
     849             : }
     850             : 
     851         314 : Label* CodeGenerator::AddJumpTable(Label** targets, size_t target_count) {
     852         628 :   jump_tables_ = new (zone()) JumpTable(jump_tables_, targets, target_count);
     853         314 :   return jump_tables_->label();
     854             : }
     855             : 
     856    15015793 : void CodeGenerator::RecordCallPosition(Instruction* instr) {
     857     5694449 :   CallDescriptor::Flags flags(MiscField::decode(instr->opcode()));
     858             : 
     859     5694449 :   bool needs_frame_state = (flags & CallDescriptor::kNeedsFrameState);
     860             : 
     861             :   RecordSafepoint(
     862             :       instr->reference_map(), Safepoint::kSimple,
     863    11388898 :       needs_frame_state ? Safepoint::kLazyDeopt : Safepoint::kNoLazyDeopt);
     864             : 
     865     5694485 :   if (flags & CallDescriptor::kHasExceptionHandler) {
     866             :     InstructionOperandConverter i(this, instr);
     867      218354 :     RpoNumber handler_rpo = i.InputRpo(instr->InputCount() - 1);
     868      655061 :     handlers_.push_back({GetLabel(handler_rpo), tasm()->pc_offset()});
     869             :   }
     870             : 
     871     5694484 :   if (needs_frame_state) {
     872             :     MarkLazyDeoptSite();
     873             :     // If the frame state is present, it starts at argument 2 - after
     874             :     // the code address and the poison-alias index.
     875             :     size_t frame_state_offset = 2;
     876             :     FrameStateDescriptor* descriptor =
     877     3190184 :         GetDeoptimizationEntry(instr, frame_state_offset).descriptor();
     878     3190185 :     int pc_offset = tasm()->pc_offset();
     879             :     int deopt_state_id = BuildTranslation(instr, pc_offset, frame_state_offset,
     880     3190185 :                                           descriptor->state_combine());
     881             : 
     882             :     DeoptimizationExit* const exit = new (zone())
     883     6380374 :         DeoptimizationExit(deopt_state_id, current_source_position_);
     884     3190187 :     deoptimization_exits_.push_back(exit);
     885     3190184 :     safepoints()->RecordLazyDeoptimizationIndex(deopt_state_id);
     886             :   }
     887     5694486 : }
     888             : 
     889     8079733 : int CodeGenerator::DefineDeoptimizationLiteral(DeoptimizationLiteral literal) {
     890     8079733 :   int result = static_cast<int>(deoptimization_literals_.size());
     891   159227334 :   for (unsigned i = 0; i < deoptimization_literals_.size(); ++i) {
     892    77833858 :     if (deoptimization_literals_[i] == literal) return i;
     893             :   }
     894     1779796 :   deoptimization_literals_.push_back(literal);
     895     1779789 :   return result;
     896             : }
     897             : 
     898     6759205 : DeoptimizationEntry const& CodeGenerator::GetDeoptimizationEntry(
     899     6759215 :     Instruction* instr, size_t frame_state_offset) {
     900             :   InstructionOperandConverter i(this, instr);
     901     6759205 :   int const state_id = i.InputInt32(frame_state_offset);
     902     6759215 :   return instructions()->GetDeoptimizationEntry(state_id);
     903             : }
     904             : 
     905     3306859 : DeoptimizeKind CodeGenerator::GetDeoptimizationKind(
     906             :     int deoptimization_id) const {
     907             :   size_t const index = static_cast<size_t>(deoptimization_id);
     908             :   DCHECK_LT(index, deoptimization_states_.size());
     909     3306861 :   return deoptimization_states_[index]->kind();
     910             : }
     911             : 
     912     3306861 : DeoptimizeReason CodeGenerator::GetDeoptimizationReason(
     913             :     int deoptimization_id) const {
     914             :   size_t const index = static_cast<size_t>(deoptimization_id);
     915             :   DCHECK_LT(index, deoptimization_states_.size());
     916     3306869 :   return deoptimization_states_[index]->reason();
     917             : }
     918             : 
     919    51189143 : void CodeGenerator::TranslateStateValueDescriptor(
     920    51224602 :     StateValueDescriptor* desc, StateValueList* nested,
     921      456492 :     Translation* translation, InstructionOperandIterator* iter) {
     922             :   // Note:
     923             :   // If translation is null, we just skip the relevant instruction operands.
     924    51189143 :   if (desc->IsNested()) {
     925       98457 :     if (translation != nullptr) {
     926       98457 :       translation->BeginCapturedObject(static_cast<int>(nested->size()));
     927             :     }
     928      791284 :     for (auto field : *nested) {
     929             :       TranslateStateValueDescriptor(field.desc, field.nested, translation,
     930      594370 :                                     iter);
     931             :     }
     932    51090686 :   } else if (desc->IsArgumentsElements()) {
     933        6180 :     if (translation != nullptr) {
     934        6180 :       translation->ArgumentsElements(desc->arguments_type());
     935             :     }
     936    51084506 :   } else if (desc->IsArgumentsLength()) {
     937        6500 :     if (translation != nullptr) {
     938        6500 :       translation->ArgumentsLength(desc->arguments_type());
     939             :     }
     940    51078006 :   } else if (desc->IsDuplicate()) {
     941       22779 :     if (translation != nullptr) {
     942       22779 :       translation->DuplicateObject(static_cast<int>(desc->id()));
     943             :     }
     944    51055227 :   } else if (desc->IsPlain()) {
     945    23217982 :     InstructionOperand* op = iter->Advance();
     946    23217982 :     if (translation != nullptr) {
     947             :       AddTranslationForOperand(translation, iter->instruction(), op,
     948    23217988 :                                desc->type());
     949             :     }
     950             :   } else {
     951             :     DCHECK(desc->IsOptimizedOut());
     952    27837245 :     if (translation != nullptr) {
     953    27837244 :       if (optimized_out_literal_id_ == -1) {
     954             :         optimized_out_literal_id_ = DefineDeoptimizationLiteral(
     955      456492 :             DeoptimizationLiteral(isolate()->factory()->optimized_out()));
     956             :       }
     957    27837237 :       translation->StoreLiteral(optimized_out_literal_id_);
     958             :     }
     959             :   }
     960    51189121 : }
     961             : 
     962     3946949 : void CodeGenerator::TranslateFrameStateDescriptorOperands(
     963             :     FrameStateDescriptor* desc, InstructionOperandIterator* iter,
     964             :     Translation* translation) {
     965             :   size_t index = 0;
     966             :   StateValueList* values = desc->GetStateValueDescriptors();
     967    58488288 :   for (StateValueList::iterator it = values->begin(); it != values->end();
     968             :        ++it, ++index) {
     969    50594377 :     TranslateStateValueDescriptor((*it).desc, (*it).nested, translation, iter);
     970             :   }
     971             :   DCHECK_EQ(desc->GetSize(), index);
     972     3946962 : }
     973             : 
     974     3946957 : void CodeGenerator::BuildTranslationForFrameStateDescriptor(
     975    14221238 :     FrameStateDescriptor* descriptor, InstructionOperandIterator* iter,
     976        2100 :     Translation* translation, OutputFrameStateCombine state_combine) {
     977             :   // Outer-most state must be added to translation first.
     978     3946957 :   if (descriptor->outer_state() != nullptr) {
     979             :     BuildTranslationForFrameStateDescriptor(descriptor->outer_state(), iter,
     980      377929 :                                             translation, state_combine);
     981             :   }
     982             : 
     983             :   Handle<SharedFunctionInfo> shared_info;
     984     3946958 :   if (!descriptor->shared_info().ToHandle(&shared_info)) {
     985        2100 :     if (!info()->has_shared_info()) {
     986     3946962 :       return;  // Stub with no SharedFunctionInfo.
     987             :     }
     988             :     shared_info = info()->shared_info();
     989             :   }
     990             :   int shared_info_id =
     991     3946958 :       DefineDeoptimizationLiteral(DeoptimizationLiteral(shared_info));
     992             : 
     993     3946969 :   switch (descriptor->type()) {
     994             :     case FrameStateType::kInterpretedFunction: {
     995             :       int return_offset = 0;
     996             :       int return_count = 0;
     997     3823534 :       if (!state_combine.IsOutputIgnored()) {
     998     2380343 :         return_offset = static_cast<int>(state_combine.GetOffsetToPokeAt());
     999     4760686 :         return_count = static_cast<int>(iter->instruction()->OutputCount());
    1000             :       }
    1001             :       translation->BeginInterpretedFrame(
    1002             :           descriptor->bailout_id(), shared_info_id,
    1003             :           static_cast<unsigned int>(descriptor->locals_count() + 1),
    1004     3823534 :           return_offset, return_count);
    1005     3823528 :       break;
    1006             :     }
    1007             :     case FrameStateType::kArgumentsAdaptor:
    1008             :       translation->BeginArgumentsAdaptorFrame(
    1009             :           shared_info_id,
    1010       83729 :           static_cast<unsigned int>(descriptor->parameters_count()));
    1011       83729 :       break;
    1012             :     case FrameStateType::kConstructStub:
    1013             :       DCHECK(descriptor->bailout_id().IsValidForConstructStub());
    1014             :       translation->BeginConstructStubFrame(
    1015             :           descriptor->bailout_id(), shared_info_id,
    1016       26155 :           static_cast<unsigned int>(descriptor->parameters_count() + 1));
    1017       26155 :       break;
    1018             :     case FrameStateType::kBuiltinContinuation: {
    1019        2100 :       BailoutId bailout_id = descriptor->bailout_id();
    1020             :       int parameter_count =
    1021             :           static_cast<unsigned int>(descriptor->parameters_count());
    1022             :       translation->BeginBuiltinContinuationFrame(bailout_id, shared_info_id,
    1023        2100 :                                                  parameter_count);
    1024             :       break;
    1025             :     }
    1026             :     case FrameStateType::kJavaScriptBuiltinContinuation: {
    1027       11184 :       BailoutId bailout_id = descriptor->bailout_id();
    1028             :       int parameter_count =
    1029             :           static_cast<unsigned int>(descriptor->parameters_count());
    1030             :       translation->BeginJavaScriptBuiltinContinuationFrame(
    1031       11184 :           bailout_id, shared_info_id, parameter_count);
    1032             :       break;
    1033             :     }
    1034             :     case FrameStateType::kJavaScriptBuiltinContinuationWithCatch: {
    1035         267 :       BailoutId bailout_id = descriptor->bailout_id();
    1036             :       int parameter_count =
    1037             :           static_cast<unsigned int>(descriptor->parameters_count());
    1038             :       translation->BeginJavaScriptBuiltinContinuationWithCatchFrame(
    1039         267 :           bailout_id, shared_info_id, parameter_count);
    1040             :       break;
    1041             :     }
    1042             :   }
    1043             : 
    1044     3946963 :   TranslateFrameStateDescriptorOperands(descriptor, iter, translation);
    1045             : }
    1046             : 
    1047     3569027 : int CodeGenerator::BuildTranslation(Instruction* instr, int pc_offset,
    1048             :                                     size_t frame_state_offset,
    1049     7138072 :                                     OutputFrameStateCombine state_combine) {
    1050     7138072 :   DeoptimizationEntry const& entry =
    1051     3569027 :       GetDeoptimizationEntry(instr, frame_state_offset);
    1052             :   FrameStateDescriptor* const descriptor = entry.descriptor();
    1053     3569034 :   frame_state_offset++;
    1054             : 
    1055     3569034 :   int update_feedback_count = entry.feedback().IsValid() ? 1 : 0;
    1056             :   Translation translation(&translations_,
    1057     3569034 :                           static_cast<int>(descriptor->GetFrameCount()),
    1058     3569034 :                           static_cast<int>(descriptor->GetJSFrameCount()),
    1059     7138073 :                           update_feedback_count, zone());
    1060     3569039 :   if (entry.feedback().IsValid()) {
    1061             :     DeoptimizationLiteral literal =
    1062             :         DeoptimizationLiteral(entry.feedback().vector());
    1063       38854 :     int literal_id = DefineDeoptimizationLiteral(literal);
    1064       38854 :     translation.AddUpdateFeedback(literal_id, entry.feedback().slot().ToInt());
    1065             :   }
    1066             :   InstructionOperandIterator iter(instr, frame_state_offset);
    1067             :   BuildTranslationForFrameStateDescriptor(descriptor, &iter, &translation,
    1068     3569039 :                                           state_combine);
    1069             : 
    1070     3569038 :   int deoptimization_id = static_cast<int>(deoptimization_states_.size());
    1071             : 
    1072             :   deoptimization_states_.push_back(new (zone()) DeoptimizationState(
    1073     3569038 :       descriptor->bailout_id(), translation.index(), pc_offset, entry.kind(),
    1074     7138077 :       entry.reason()));
    1075             : 
    1076     3569038 :   return deoptimization_id;
    1077             : }
    1078             : 
    1079    23218128 : void CodeGenerator::AddTranslationForOperand(Translation* translation,
    1080             :                                              Instruction* instr,
    1081             :                                              InstructionOperand* op,
    1082     6647561 :                                              MachineType type) {
    1083    23218128 :   if (op->IsStackSlot()) {
    1084    15739748 :     if (type.representation() == MachineRepresentation::kBit) {
    1085       21554 :       translation->StoreBoolStackSlot(LocationOperand::cast(op)->index());
    1086    47153179 :     } else if (type == MachineType::Int8() || type == MachineType::Int16() ||
    1087             :                type == MachineType::Int32()) {
    1088      475418 :       translation->StoreInt32StackSlot(LocationOperand::cast(op)->index());
    1089    45728315 :     } else if (type == MachineType::Uint8() || type == MachineType::Uint16() ||
    1090             :                type == MachineType::Uint32()) {
    1091       11119 :       translation->StoreUint32StackSlot(LocationOperand::cast(op)->index());
    1092    15231657 :     } else if (type == MachineType::Int64()) {
    1093         135 :       translation->StoreInt64StackSlot(LocationOperand::cast(op)->index());
    1094             :     } else {
    1095    15231522 :       CHECK_EQ(MachineRepresentation::kTagged, type.representation());
    1096    15231522 :       translation->StoreStackSlot(LocationOperand::cast(op)->index());
    1097             :     }
    1098     7478380 :   } else if (op->IsFPStackSlot()) {
    1099      252331 :     if (type.representation() == MachineRepresentation::kFloat64) {
    1100      251434 :       translation->StoreDoubleStackSlot(LocationOperand::cast(op)->index());
    1101             :     } else {
    1102         897 :       CHECK_EQ(MachineRepresentation::kFloat32, type.representation());
    1103         897 :       translation->StoreFloatStackSlot(LocationOperand::cast(op)->index());
    1104             :     }
    1105     7226049 :   } else if (op->IsRegister()) {
    1106             :     InstructionOperandConverter converter(this, instr);
    1107      514983 :     if (type.representation() == MachineRepresentation::kBit) {
    1108        3797 :       translation->StoreBoolRegister(converter.ToRegister(op));
    1109     1532694 :     } else if (type == MachineType::Int8() || type == MachineType::Int16() ||
    1110             :                type == MachineType::Int32()) {
    1111       35569 :       translation->StoreInt32Register(converter.ToRegister(op));
    1112     1426852 :     } else if (type == MachineType::Uint8() || type == MachineType::Uint16() ||
    1113             :                type == MachineType::Uint32()) {
    1114        1603 :       translation->StoreUint32Register(converter.ToRegister(op));
    1115      474014 :     } else if (type == MachineType::Int64()) {
    1116          14 :       translation->StoreInt64Register(converter.ToRegister(op));
    1117             :     } else {
    1118      474000 :       CHECK_EQ(MachineRepresentation::kTagged, type.representation());
    1119      474000 :       translation->StoreRegister(converter.ToRegister(op));
    1120             :     }
    1121     6711066 :   } else if (op->IsFPRegister()) {
    1122             :     InstructionOperandConverter converter(this, instr);
    1123       64301 :     if (type.representation() == MachineRepresentation::kFloat64) {
    1124       64183 :       translation->StoreDoubleRegister(converter.ToDoubleRegister(op));
    1125             :     } else {
    1126         118 :       CHECK_EQ(MachineRepresentation::kFloat32, type.representation());
    1127         118 :       translation->StoreFloatRegister(converter.ToFloatRegister(op));
    1128             :     }
    1129             :   } else {
    1130     6646765 :     CHECK(op->IsImmediate());
    1131             :     InstructionOperandConverter converter(this, instr);
    1132     6646765 :     Constant constant = converter.ToConstant(op);
    1133             :     DeoptimizationLiteral literal;
    1134     6646776 :     switch (constant.type()) {
    1135             :       case Constant::kInt32:
    1136       16534 :         if (type.representation() == MachineRepresentation::kTagged) {
    1137             :           // When pointers are 4 bytes, we can use int32 constants to represent
    1138             :           // Smis.
    1139             :           DCHECK_EQ(4, kSystemPointerSize);
    1140          10 :           Smi smi(static_cast<Address>(constant.ToInt32()));
    1141             :           DCHECK(smi->IsSmi());
    1142           5 :           literal = DeoptimizationLiteral(smi->value());
    1143       16529 :         } else if (type.representation() == MachineRepresentation::kBit) {
    1144        1566 :           if (constant.ToInt32() == 0) {
    1145             :             literal =
    1146         340 :                 DeoptimizationLiteral(isolate()->factory()->false_value());
    1147             :           } else {
    1148             :             DCHECK_EQ(1, constant.ToInt32());
    1149         443 :             literal = DeoptimizationLiteral(isolate()->factory()->true_value());
    1150             :           }
    1151             :         } else {
    1152             :           DCHECK(type == MachineType::Int32() ||
    1153             :                  type == MachineType::Uint32() ||
    1154             :                  type.representation() == MachineRepresentation::kWord32 ||
    1155             :                  type.representation() == MachineRepresentation::kNone);
    1156             :           DCHECK(type.representation() != MachineRepresentation::kNone ||
    1157             :                  constant.ToInt32() == FrameStateDescriptor::kImpossibleValue);
    1158       15746 :           if (type == MachineType::Uint32()) {
    1159             :             literal = DeoptimizationLiteral(
    1160        1640 :                 static_cast<uint32_t>(constant.ToInt32()));
    1161             :           } else {
    1162       29852 :             literal = DeoptimizationLiteral(constant.ToInt32());
    1163             :           }
    1164             :         }
    1165             :         break;
    1166             :       case Constant::kInt64:
    1167             :         DCHECK_EQ(8, kSystemPointerSize);
    1168      548293 :         if (type.representation() == MachineRepresentation::kWord64) {
    1169             :           literal =
    1170         556 :               DeoptimizationLiteral(static_cast<double>(constant.ToInt64()));
    1171             :         } else {
    1172             :           // When pointers are 8 bytes, we can use int64 constants to represent
    1173             :           // Smis.
    1174             :           DCHECK_EQ(MachineRepresentation::kTagged, type.representation());
    1175             :           Smi smi(static_cast<Address>(constant.ToInt64()));
    1176             :           DCHECK(smi->IsSmi());
    1177      547737 :           literal = DeoptimizationLiteral(smi->value());
    1178             :         }
    1179             :         break;
    1180             :       case Constant::kFloat32:
    1181             :         DCHECK(type.representation() == MachineRepresentation::kFloat32 ||
    1182             :                type.representation() == MachineRepresentation::kTagged);
    1183           0 :         literal = DeoptimizationLiteral(constant.ToFloat32());
    1184           0 :         break;
    1185             :       case Constant::kFloat64:
    1186             :         DCHECK(type.representation() == MachineRepresentation::kFloat64 ||
    1187             :                type.representation() == MachineRepresentation::kTagged);
    1188       93081 :         literal = DeoptimizationLiteral(constant.ToFloat64().value());
    1189       93081 :         break;
    1190             :       case Constant::kHeapObject:
    1191             :         DCHECK_EQ(MachineRepresentation::kTagged, type.representation());
    1192     5986378 :         literal = DeoptimizationLiteral(constant.ToHeapObject());
    1193     5986380 :         break;
    1194             :       case Constant::kDelayedStringConstant:
    1195             :         DCHECK_EQ(MachineRepresentation::kTagged, type.representation());
    1196        2490 :         literal = DeoptimizationLiteral(constant.ToDelayedStringConstant());
    1197        2490 :         break;
    1198             :       default:
    1199           0 :         UNREACHABLE();
    1200             :     }
    1201     6646778 :     if (literal.object().equals(info()->closure())) {
    1202     3597587 :       translation->StoreJSFrameFunction();
    1203             :     } else {
    1204     3049191 :       int literal_id = DefineDeoptimizationLiteral(literal);
    1205     3049188 :       translation->StoreLiteral(literal_id);
    1206             :     }
    1207             :   }
    1208    23218111 : }
    1209             : 
    1210           0 : void CodeGenerator::MarkLazyDeoptSite() {
    1211     6380368 :   last_lazy_deopt_pc_ = tasm()->pc_offset();
    1212           0 : }
    1213             : 
    1214      333237 : DeoptimizationExit* CodeGenerator::AddDeoptimizationExit(
    1215      333241 :     Instruction* instr, size_t frame_state_offset) {
    1216             :   int const deoptimization_id = BuildTranslation(
    1217      333237 :       instr, -1, frame_state_offset, OutputFrameStateCombine::Ignore());
    1218             : 
    1219             :   DeoptimizationExit* const exit = new (zone())
    1220      666482 :       DeoptimizationExit(deoptimization_id, current_source_position_);
    1221      333241 :   deoptimization_exits_.push_back(exit);
    1222      333240 :   return exit;
    1223             : }
    1224             : 
    1225     2141323 : void CodeGenerator::InitializeSpeculationPoison() {
    1226     4282646 :   if (poisoning_level_ == PoisoningMitigationLevel::kDontPoison) return;
    1227             : 
    1228             :   // Initialize {kSpeculationPoisonRegister} either by comparing the expected
    1229             :   // with the actual call target, or by unconditionally using {-1} initially.
    1230             :   // Masking register arguments with it only makes sense in the first case.
    1231           0 :   if (info()->called_with_code_start_register()) {
    1232           0 :     tasm()->RecordComment("-- Prologue: generate speculation poison --");
    1233           0 :     GenerateSpeculationPoisonFromCodeStartRegister();
    1234           0 :     if (info()->is_poisoning_register_arguments()) {
    1235           0 :       AssembleRegisterArgumentPoisoning();
    1236             :     }
    1237             :   } else {
    1238             :     ResetSpeculationPoison();
    1239             :   }
    1240             : }
    1241             : 
    1242        4991 : void CodeGenerator::ResetSpeculationPoison() {
    1243     5728941 :   if (poisoning_level_ != PoisoningMitigationLevel::kDontPoison) {
    1244           0 :     tasm()->ResetSpeculationPoisonRegister();
    1245             :   }
    1246        4991 : }
    1247             : 
    1248     1300644 : OutOfLineCode::OutOfLineCode(CodeGenerator* gen)
    1249     1300644 :     : frame_(gen->frame()), tasm_(gen->tasm()), next_(gen->ools_) {
    1250      650322 :   gen->ools_ = this;
    1251      650322 : }
    1252             : 
    1253             : OutOfLineCode::~OutOfLineCode() = default;
    1254             : 
    1255     1779192 : Handle<Object> DeoptimizationLiteral::Reify(Isolate* isolate) const {
    1256     1779192 :   switch (kind_) {
    1257             :     case DeoptimizationLiteralKind::kObject: {
    1258     1701645 :       return object_;
    1259             :     }
    1260             :     case DeoptimizationLiteralKind::kNumber: {
    1261       76912 :       return isolate->factory()->NewNumber(number_);
    1262             :     }
    1263             :     case DeoptimizationLiteralKind::kString: {
    1264         635 :       return string_->AllocateStringConstant(isolate);
    1265             :     }
    1266             :   }
    1267           0 :   UNREACHABLE();
    1268             : }
    1269             : 
    1270             : }  // namespace compiler
    1271             : }  // namespace internal
    1272      178779 : }  // namespace v8

Generated by: LCOV version 1.10