LCOV - code coverage report
Current view: top level - src/compiler/backend - code-generator.h (source / functions) Hit Total Coverage
Test: app.info Lines: 14 14 100.0 %
Date: 2019-01-20 Functions: 2 3 66.7 %

          Line data    Source code
       1             : // Copyright 2014 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #ifndef V8_COMPILER_BACKEND_CODE_GENERATOR_H_
       6             : #define V8_COMPILER_BACKEND_CODE_GENERATOR_H_
       7             : 
       8             : #include "src/base/optional.h"
       9             : #include "src/compiler/backend/gap-resolver.h"
      10             : #include "src/compiler/backend/instruction.h"
      11             : #include "src/compiler/backend/unwinding-info-writer.h"
      12             : #include "src/compiler/osr.h"
      13             : #include "src/deoptimizer.h"
      14             : #include "src/macro-assembler.h"
      15             : #include "src/safepoint-table.h"
      16             : #include "src/source-position-table.h"
      17             : #include "src/trap-handler/trap-handler.h"
      18             : 
      19             : namespace v8 {
      20             : namespace internal {
      21             : 
      22             : class OptimizedCompilationInfo;
      23             : 
      24             : namespace compiler {
      25             : 
      26             : // Forward declarations.
      27             : class DeoptimizationExit;
      28             : class FrameAccessState;
      29             : class Linkage;
      30             : class OutOfLineCode;
      31             : 
      32             : struct BranchInfo {
      33             :   FlagsCondition condition;
      34             :   Label* true_label;
      35             :   Label* false_label;
      36             :   bool fallthru;
      37             : };
      38             : 
      39             : class InstructionOperandIterator {
      40             :  public:
      41             :   InstructionOperandIterator(Instruction* instr, size_t pos)
      42     2998795 :       : instr_(instr), pos_(pos) {}
      43             : 
      44             :   Instruction* instruction() const { return instr_; }
      45    20409587 :   InstructionOperand* Advance() { return instr_->InputAt(pos_++); }
      46             : 
      47             :  private:
      48             :   Instruction* instr_;
      49             :   size_t pos_;
      50             : };
      51             : 
      52             : enum class DeoptimizationLiteralKind { kObject, kNumber, kString };
      53             : 
      54             : // Either a non-null Handle<Object>, a double or a StringConstantBase.
      55             : class DeoptimizationLiteral {
      56             :  public:
      57     6096823 :   DeoptimizationLiteral() : object_(), number_(0), string_(nullptr) {}
      58             :   explicit DeoptimizationLiteral(Handle<Object> object)
      59     4451282 :       : kind_(DeoptimizationLiteralKind::kObject), object_(object) {
      60             :     DCHECK(!object_.is_null());
      61             :   }
      62             :   explicit DeoptimizationLiteral(double number)
      63             :       : kind_(DeoptimizationLiteralKind::kNumber), number_(number) {}
      64             :   explicit DeoptimizationLiteral(const StringConstantBase* string)
      65             :       : kind_(DeoptimizationLiteralKind::kString), string_(string) {}
      66             : 
      67             :   Handle<Object> object() const { return object_; }
      68             :   const StringConstantBase* string() const { return string_; }
      69             : 
      70    67402774 :   bool operator==(const DeoptimizationLiteral& other) const {
      71   136575171 :     return kind_ == other.kind_ && object_.equals(other.object_) &&
      72    89066382 :            bit_cast<uint64_t>(number_) == bit_cast<uint64_t>(other.number_) &&
      73    78772346 :            bit_cast<intptr_t>(string_) == bit_cast<intptr_t>(other.string_);
      74             :   }
      75             : 
      76             :   Handle<Object> Reify(Isolate* isolate) const;
      77             : 
      78             :   DeoptimizationLiteralKind kind() const { return kind_; }
      79             : 
      80             :  private:
      81             :   DeoptimizationLiteralKind kind_;
      82             : 
      83             :   Handle<Object> object_;
      84             :   double number_ = 0;
      85             :   const StringConstantBase* string_ = nullptr;
      86             : };
      87             : 
      88             : // Generates native code for a sequence of instructions.
      89     8849168 : class CodeGenerator final : public GapResolver::Assembler {
      90             :  public:
      91             :   explicit CodeGenerator(Zone* codegen_zone, Frame* frame, Linkage* linkage,
      92             :                          InstructionSequence* code,
      93             :                          OptimizedCompilationInfo* info, Isolate* isolate,
      94             :                          base::Optional<OsrHelper> osr_helper,
      95             :                          int start_source_position,
      96             :                          JumpOptimizationInfo* jump_opt,
      97             :                          PoisoningMitigationLevel poisoning_level,
      98             :                          const AssemblerOptions& options,
      99             :                          int32_t builtin_index);
     100             : 
     101             :   // Generate native code. After calling AssembleCode, call FinalizeCode to
     102             :   // produce the actual code object. If an error occurs during either phase,
     103             :   // FinalizeCode returns an empty MaybeHandle.
     104             :   void AssembleCode();  // Does not need to run on main thread.
     105             :   MaybeHandle<Code> FinalizeCode();
     106             : 
     107             :   OwnedVector<byte> GetSourcePositionTable();
     108             :   OwnedVector<trap_handler::ProtectedInstructionData>
     109             :   GetProtectedInstructions();
     110             : 
     111             :   InstructionSequence* code() const { return code_; }
     112             :   FrameAccessState* frame_access_state() const { return frame_access_state_; }
     113    21202594 :   const Frame* frame() const { return frame_access_state_->frame(); }
     114             :   Isolate* isolate() const { return isolate_; }
     115             :   Linkage* linkage() const { return linkage_; }
     116             : 
     117    34682326 :   Label* GetLabel(RpoNumber rpo) { return &labels_[rpo.ToSize()]; }
     118             : 
     119             :   void AddProtectedInstructionLanding(uint32_t instr_offset,
     120             :                                       uint32_t landing_offset);
     121             : 
     122             :   bool wasm_runtime_exception_support() const;
     123             : 
     124             :   SourcePosition start_source_position() const {
     125             :     return start_source_position_;
     126             :   }
     127             : 
     128             :   void AssembleSourcePosition(Instruction* instr);
     129             :   void AssembleSourcePosition(SourcePosition source_position);
     130             : 
     131             :   // Record a safepoint with the given pointer map.
     132             :   void RecordSafepoint(ReferenceMap* references, Safepoint::Kind kind,
     133             :                        int arguments, Safepoint::DeoptMode deopt_mode);
     134             : 
     135             :   Zone* zone() const { return zone_; }
     136             :   TurboAssembler* tasm() { return &tasm_; }
     137     1068701 :   size_t GetSafepointTableOffset() const { return safepoints_.GetCodeOffset(); }
     138     1068701 :   size_t GetHandlerTableOffset() const { return handler_table_offset_; }
     139             : 
     140             :   const ZoneVector<int>& block_starts() const { return block_starts_; }
     141             :   const ZoneVector<int>& instr_starts() const { return instr_starts_; }
     142             : 
     143             :   static constexpr int kBinarySearchSwitchMinimalCases = 4;
     144             : 
     145             :  private:
     146             :   GapResolver* resolver() { return &resolver_; }
     147             :   SafepointTableBuilder* safepoints() { return &safepoints_; }
     148             :   OptimizedCompilationInfo* info() const { return info_; }
     149             :   OsrHelper* osr_helper() { return &(*osr_helper_); }
     150             : 
     151             :   // Create the FrameAccessState object. The Frame is immutable from here on.
     152             :   void CreateFrameAccessState(Frame* frame);
     153             : 
     154             :   // Architecture - specific frame finalization.
     155             :   void FinishFrame(Frame* frame);
     156             : 
     157             :   // Checks if {block} will appear directly after {current_block_} when
     158             :   // assembling code, in which case, a fall-through can be used.
     159             :   bool IsNextInAssemblyOrder(RpoNumber block) const;
     160             : 
     161             :   // Check if a heap object can be materialized by loading from a heap root,
     162             :   // which is cheaper on some platforms than materializing the actual heap
     163             :   // object constant.
     164             :   bool IsMaterializableFromRoot(Handle<HeapObject> object,
     165             :                                 RootIndex* index_return);
     166             : 
     167             :   enum CodeGenResult { kSuccess, kTooManyDeoptimizationBailouts };
     168             : 
     169             :   // Assemble instructions for the specified block.
     170             :   CodeGenResult AssembleBlock(const InstructionBlock* block);
     171             : 
     172             :   // Inserts mask update at the beginning of an instruction block if the
     173             :   // predecessor blocks ends with a masking branch.
     174             :   void TryInsertBranchPoisoning(const InstructionBlock* block);
     175             : 
     176             :   // Initializes the masking register in the prologue of a function.
     177             :   void InitializeSpeculationPoison();
     178             :   // Reset the masking register during execution of a function.
     179             :   void ResetSpeculationPoison();
     180             :   // Generates a mask from the pc passed in {kJavaScriptCallCodeStartRegister}.
     181             :   void GenerateSpeculationPoisonFromCodeStartRegister();
     182             : 
     183             :   // Assemble code for the specified instruction.
     184             :   CodeGenResult AssembleInstruction(Instruction* instr,
     185             :                                     const InstructionBlock* block);
     186             :   void AssembleGaps(Instruction* instr);
     187             : 
     188             :   // Compute branch info from given instruction. Returns a valid rpo number
     189             :   // if the branch is redundant, the returned rpo number point to the target
     190             :   // basic block.
     191             :   RpoNumber ComputeBranchInfo(BranchInfo* branch, Instruction* instr);
     192             : 
     193             :   // Returns true if a instruction is a tail call that needs to adjust the stack
     194             :   // pointer before execution. The stack slot index to the empty slot above the
     195             :   // adjusted stack pointer is returned in |slot|.
     196             :   bool GetSlotAboveSPBeforeTailCall(Instruction* instr, int* slot);
     197             : 
     198             :   // Determines how to call helper stubs depending on the code kind.
     199             :   StubCallMode DetermineStubCallMode() const;
     200             : 
     201             :   CodeGenResult AssembleDeoptimizerCall(int deoptimization_id,
     202             :                                         SourcePosition pos);
     203             : 
     204             :   // ===========================================================================
     205             :   // ============= Architecture-specific code generation methods. ==============
     206             :   // ===========================================================================
     207             : 
     208             :   CodeGenResult AssembleArchInstruction(Instruction* instr);
     209             :   void AssembleArchJump(RpoNumber target);
     210             :   void AssembleArchBranch(Instruction* instr, BranchInfo* branch);
     211             : 
     212             :   // Generates special branch for deoptimization condition.
     213             :   void AssembleArchDeoptBranch(Instruction* instr, BranchInfo* branch);
     214             : 
     215             :   void AssembleArchBoolean(Instruction* instr, FlagsCondition condition);
     216             :   void AssembleArchTrap(Instruction* instr, FlagsCondition condition);
     217             :   void AssembleArchBinarySearchSwitchRange(Register input, RpoNumber def_block,
     218             :                                            std::pair<int32_t, Label*>* begin,
     219             :                                            std::pair<int32_t, Label*>* end);
     220             :   void AssembleArchBinarySearchSwitch(Instruction* instr);
     221             :   void AssembleArchLookupSwitch(Instruction* instr);
     222             :   void AssembleArchTableSwitch(Instruction* instr);
     223             : 
     224             :   // Generates code that checks whether the {kJavaScriptCallCodeStartRegister}
     225             :   // contains the expected pointer to the start of the instruction stream.
     226             :   void AssembleCodeStartRegisterCheck();
     227             : 
     228             :   void AssembleBranchPoisoning(FlagsCondition condition, Instruction* instr);
     229             : 
     230             :   // When entering a code that is marked for deoptimization, rather continuing
     231             :   // with its execution, we jump to a lazy compiled code. We need to do this
     232             :   // because this code has already been deoptimized and needs to be unlinked
     233             :   // from the JS functions referring it.
     234             :   void BailoutIfDeoptimized();
     235             : 
     236             :   // Generates code to poison the stack pointer and implicit register arguments
     237             :   // like the context register and the function register.
     238             :   void AssembleRegisterArgumentPoisoning();
     239             : 
     240             :   // Generates an architecture-specific, descriptor-specific prologue
     241             :   // to set up a stack frame.
     242             :   void AssembleConstructFrame();
     243             : 
     244             :   // Generates an architecture-specific, descriptor-specific return sequence
     245             :   // to tear down a stack frame.
     246             :   void AssembleReturn(InstructionOperand* pop);
     247             : 
     248             :   void AssembleDeconstructFrame();
     249             : 
     250             :   // Generates code to manipulate the stack in preparation for a tail call.
     251             :   void AssemblePrepareTailCall();
     252             : 
     253             :   // Generates code to pop current frame if it is an arguments adaptor frame.
     254             :   void AssemblePopArgumentsAdaptorFrame(Register args_reg, Register scratch1,
     255             :                                         Register scratch2, Register scratch3);
     256             : 
     257             :   enum PushTypeFlag {
     258             :     kImmediatePush = 0x1,
     259             :     kRegisterPush = 0x2,
     260             :     kStackSlotPush = 0x4,
     261             :     kScalarPush = kRegisterPush | kStackSlotPush
     262             :   };
     263             : 
     264             :   typedef base::Flags<PushTypeFlag> PushTypeFlags;
     265             : 
     266             :   static bool IsValidPush(InstructionOperand source, PushTypeFlags push_type);
     267             : 
     268             :   // Generate a list moves from an instruction that are candidates to be turned
     269             :   // into push instructions on platforms that support them. In general, the list
     270             :   // of push candidates are moves to a set of contiguous destination
     271             :   // InstructionOperand locations on the stack that don't clobber values that
     272             :   // are needed for resolve the gap or use values generated by the gap,
     273             :   // i.e. moves that can be hoisted together before the actual gap and assembled
     274             :   // together.
     275             :   static void GetPushCompatibleMoves(Instruction* instr,
     276             :                                      PushTypeFlags push_type,
     277             :                                      ZoneVector<MoveOperands*>* pushes);
     278             : 
     279             :   class MoveType {
     280             :    public:
     281             :     enum Type {
     282             :       kRegisterToRegister,
     283             :       kRegisterToStack,
     284             :       kStackToRegister,
     285             :       kStackToStack,
     286             :       kConstantToRegister,
     287             :       kConstantToStack
     288             :     };
     289             : 
     290             :     // Detect what type of move or swap needs to be performed. Note that these
     291             :     // functions do not take into account the representation (Tagged, FP,
     292             :     // ...etc).
     293             : 
     294             :     static Type InferMove(InstructionOperand* source,
     295             :                           InstructionOperand* destination);
     296             :     static Type InferSwap(InstructionOperand* source,
     297             :                           InstructionOperand* destination);
     298             :   };
     299             :   // Called before a tail call |instr|'s gap moves are assembled and allows
     300             :   // gap-specific pre-processing, e.g. adjustment of the sp for tail calls that
     301             :   // need it before gap moves or conversion of certain gap moves into pushes.
     302             :   void AssembleTailCallBeforeGap(Instruction* instr,
     303             :                                  int first_unused_stack_slot);
     304             :   // Called after a tail call |instr|'s gap moves are assembled and allows
     305             :   // gap-specific post-processing, e.g. adjustment of the sp for tail calls that
     306             :   // need it after gap moves.
     307             :   void AssembleTailCallAfterGap(Instruction* instr,
     308             :                                 int first_unused_stack_slot);
     309             : 
     310             :   void FinishCode();
     311             : 
     312             :   // ===========================================================================
     313             :   // ============== Architecture-specific gap resolver methods. ================
     314             :   // ===========================================================================
     315             : 
     316             :   // Interface used by the gap resolver to emit moves and swaps.
     317             :   void AssembleMove(InstructionOperand* source,
     318             :                     InstructionOperand* destination) final;
     319             :   void AssembleSwap(InstructionOperand* source,
     320             :                     InstructionOperand* destination) final;
     321             : 
     322             :   // ===========================================================================
     323             :   // =================== Jump table construction methods. ======================
     324             :   // ===========================================================================
     325             : 
     326             :   class JumpTable;
     327             :   // Adds a jump table that is emitted after the actual code.  Returns label
     328             :   // pointing to the beginning of the table.  {targets} is assumed to be static
     329             :   // or zone allocated.
     330             :   Label* AddJumpTable(Label** targets, size_t target_count);
     331             :   // Emits a jump table.
     332             :   void AssembleJumpTable(Label** targets, size_t target_count);
     333             : 
     334             :   // ===========================================================================
     335             :   // ================== Deoptimization table construction. =====================
     336             :   // ===========================================================================
     337             : 
     338             :   void RecordCallPosition(Instruction* instr);
     339             :   Handle<DeoptimizationData> GenerateDeoptimizationData();
     340             :   int DefineDeoptimizationLiteral(DeoptimizationLiteral literal);
     341             :   DeoptimizationEntry const& GetDeoptimizationEntry(Instruction* instr,
     342             :                                                     size_t frame_state_offset);
     343             :   DeoptimizeKind GetDeoptimizationKind(int deoptimization_id) const;
     344             :   DeoptimizeReason GetDeoptimizationReason(int deoptimization_id) const;
     345             :   int BuildTranslation(Instruction* instr, int pc_offset,
     346             :                        size_t frame_state_offset,
     347             :                        OutputFrameStateCombine state_combine);
     348             :   void BuildTranslationForFrameStateDescriptor(
     349             :       FrameStateDescriptor* descriptor, InstructionOperandIterator* iter,
     350             :       Translation* translation, OutputFrameStateCombine state_combine);
     351             :   void TranslateStateValueDescriptor(StateValueDescriptor* desc,
     352             :                                      StateValueList* nested,
     353             :                                      Translation* translation,
     354             :                                      InstructionOperandIterator* iter);
     355             :   void TranslateFrameStateDescriptorOperands(FrameStateDescriptor* desc,
     356             :                                              InstructionOperandIterator* iter,
     357             :                                              Translation* translation);
     358             :   void AddTranslationForOperand(Translation* translation, Instruction* instr,
     359             :                                 InstructionOperand* op, MachineType type);
     360             :   void MarkLazyDeoptSite();
     361             : 
     362             :   DeoptimizationExit* AddDeoptimizationExit(Instruction* instr,
     363             :                                             size_t frame_state_offset);
     364             : 
     365             :   // ===========================================================================
     366             : 
     367             :   class DeoptimizationState final : public ZoneObject {
     368             :    public:
     369             :     DeoptimizationState(BailoutId bailout_id, int translation_id, int pc_offset,
     370             :                         DeoptimizeKind kind, DeoptimizeReason reason)
     371             :         : bailout_id_(bailout_id),
     372             :           translation_id_(translation_id),
     373             :           pc_offset_(pc_offset),
     374             :           kind_(kind),
     375     2998803 :           reason_(reason) {}
     376             : 
     377             :     BailoutId bailout_id() const { return bailout_id_; }
     378             :     int translation_id() const { return translation_id_; }
     379             :     int pc_offset() const { return pc_offset_; }
     380             :     DeoptimizeKind kind() const { return kind_; }
     381             :     DeoptimizeReason reason() const { return reason_; }
     382             : 
     383             :    private:
     384             :     BailoutId bailout_id_;
     385             :     int translation_id_;
     386             :     int pc_offset_;
     387             :     DeoptimizeKind kind_;
     388             :     DeoptimizeReason reason_;
     389             :   };
     390             : 
     391             :   struct HandlerInfo {
     392             :     Label* handler;
     393             :     int pc_offset;
     394             :   };
     395             : 
     396             :   friend class OutOfLineCode;
     397             :   friend class CodeGeneratorTester;
     398             : 
     399             :   Zone* zone_;
     400             :   Isolate* isolate_;
     401             :   FrameAccessState* frame_access_state_;
     402             :   Linkage* const linkage_;
     403             :   InstructionSequence* const code_;
     404             :   UnwindingInfoWriter unwinding_info_writer_;
     405             :   OptimizedCompilationInfo* const info_;
     406             :   Label* const labels_;
     407             :   Label return_label_;
     408             :   RpoNumber current_block_;
     409             :   SourcePosition start_source_position_;
     410             :   SourcePosition current_source_position_;
     411             :   TurboAssembler tasm_;
     412             :   GapResolver resolver_;
     413             :   SafepointTableBuilder safepoints_;
     414             :   ZoneVector<HandlerInfo> handlers_;
     415             :   ZoneDeque<DeoptimizationExit*> deoptimization_exits_;
     416             :   ZoneDeque<DeoptimizationState*> deoptimization_states_;
     417             :   ZoneDeque<DeoptimizationLiteral> deoptimization_literals_;
     418             :   size_t inlined_function_count_ = 0;
     419             :   TranslationBuffer translations_;
     420             :   int handler_table_offset_ = 0;
     421             :   int last_lazy_deopt_pc_ = 0;
     422             : 
     423             :   // kArchCallCFunction could be reached either:
     424             :   //   kArchCallCFunction;
     425             :   // or:
     426             :   //   kArchSaveCallerRegisters;
     427             :   //   kArchCallCFunction;
     428             :   //   kArchRestoreCallerRegisters;
     429             :   // The boolean is used to distinguish the two cases. In the latter case, we
     430             :   // also need to decide if FP registers need to be saved, which is controlled
     431             :   // by fp_mode_.
     432             :   bool caller_registers_saved_;
     433             :   SaveFPRegsMode fp_mode_;
     434             : 
     435             :   JumpTable* jump_tables_;
     436             :   OutOfLineCode* ools_;
     437             :   base::Optional<OsrHelper> osr_helper_;
     438             :   int osr_pc_offset_;
     439             :   int optimized_out_literal_id_;
     440             :   SourcePositionTableBuilder source_position_table_builder_;
     441             :   ZoneVector<trap_handler::ProtectedInstructionData> protected_instructions_;
     442             :   CodeGenResult result_;
     443             :   PoisoningMitigationLevel poisoning_level_;
     444             :   ZoneVector<int> block_starts_;
     445             :   ZoneVector<int> instr_starts_;
     446             : };
     447             : 
     448             : }  // namespace compiler
     449             : }  // namespace internal
     450             : }  // namespace v8
     451             : 
     452             : #endif  // V8_COMPILER_BACKEND_CODE_GENERATOR_H_

Generated by: LCOV version 1.10