Home | History | Annotate | Download | only in arm
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #ifndef V8_ARM_LITHIUM_CODEGEN_ARM_H_
     29 #define V8_ARM_LITHIUM_CODEGEN_ARM_H_
     30 
     31 #include "arm/lithium-arm.h"
     32 
     33 #include "arm/lithium-gap-resolver-arm.h"
     34 #include "deoptimizer.h"
     35 #include "safepoint-table.h"
     36 #include "scopes.h"
     37 #include "v8utils.h"
     38 
     39 namespace v8 {
     40 namespace internal {
     41 
     42 // Forward declarations.
     43 class LDeferredCode;
     44 class SafepointGenerator;
     45 
     46 class LCodeGen BASE_EMBEDDED {
     47  public:
     48   LCodeGen(LChunk* chunk, MacroAssembler* assembler, CompilationInfo* info)
     49       : zone_(info->zone()),
     50         chunk_(static_cast<LPlatformChunk*>(chunk)),
     51         masm_(assembler),
     52         info_(info),
     53         current_block_(-1),
     54         current_instruction_(-1),
     55         instructions_(chunk->instructions()),
     56         deoptimizations_(4, info->zone()),
     57         deopt_jump_table_(4, info->zone()),
     58         deoptimization_literals_(8, info->zone()),
     59         inlined_function_count_(0),
     60         scope_(info->scope()),
     61         status_(UNUSED),
     62         translations_(info->zone()),
     63         deferred_(8, info->zone()),
     64         osr_pc_offset_(-1),
     65         last_lazy_deopt_pc_(0),
     66         frame_is_built_(false),
     67         safepoints_(info->zone()),
     68         resolver_(this),
     69         expected_safepoint_kind_(Safepoint::kSimple),
     70         old_position_(RelocInfo::kNoPosition) {
     71     PopulateDeoptimizationLiteralsWithInlinedFunctions();
     72   }
     73 
     74 
     75   // Simple accessors.
     76   MacroAssembler* masm() const { return masm_; }
     77   CompilationInfo* info() const { return info_; }
     78   Isolate* isolate() const { return info_->isolate(); }
     79   Factory* factory() const { return isolate()->factory(); }
     80   Heap* heap() const { return isolate()->heap(); }
     81   Zone* zone() const { return zone_; }
     82 
     83   int LookupDestination(int block_id) const {
     84     return chunk()->LookupDestination(block_id);
     85   }
     86 
     87   bool IsNextEmittedBlock(int block_id) const {
     88     return LookupDestination(block_id) == GetNextEmittedBlock();
     89   }
     90 
     91   bool NeedsEagerFrame() const {
     92     return GetStackSlotCount() > 0 ||
     93         info()->is_non_deferred_calling() ||
     94         !info()->IsStub() ||
     95         info()->requires_frame();
     96   }
     97   bool NeedsDeferredFrame() const {
     98     return !NeedsEagerFrame() && info()->is_deferred_calling();
     99   }
    100 
    101   LinkRegisterStatus GetLinkRegisterState() const {
    102     return frame_is_built_ ? kLRHasBeenSaved : kLRHasNotBeenSaved;
    103   }
    104 
    105   // Support for converting LOperands to assembler types.
    106   // LOperand must be a register.
    107   Register ToRegister(LOperand* op) const;
    108 
    109   // LOperand is loaded into scratch, unless already a register.
    110   Register EmitLoadRegister(LOperand* op, Register scratch);
    111 
    112   // LOperand must be a double register.
    113   DwVfpRegister ToDoubleRegister(LOperand* op) const;
    114 
    115   // LOperand is loaded into dbl_scratch, unless already a double register.
    116   DwVfpRegister EmitLoadDoubleRegister(LOperand* op,
    117                                        SwVfpRegister flt_scratch,
    118                                        DwVfpRegister dbl_scratch);
    119   int32_t ToRepresentation(LConstantOperand* op, const Representation& r) const;
    120   int32_t ToInteger32(LConstantOperand* op) const;
    121   Smi* ToSmi(LConstantOperand* op) const;
    122   double ToDouble(LConstantOperand* op) const;
    123   Operand ToOperand(LOperand* op);
    124   MemOperand ToMemOperand(LOperand* op) const;
    125   // Returns a MemOperand pointing to the high word of a DoubleStackSlot.
    126   MemOperand ToHighMemOperand(LOperand* op) const;
    127 
    128   bool IsInteger32(LConstantOperand* op) const;
    129   bool IsSmi(LConstantOperand* op) const;
    130   Handle<Object> ToHandle(LConstantOperand* op) const;
    131 
    132   // Try to generate code for the entire chunk, but it may fail if the
    133   // chunk contains constructs we cannot handle. Returns true if the
    134   // code generation attempt succeeded.
    135   bool GenerateCode();
    136 
    137   // Finish the code by setting stack height, safepoint, and bailout
    138   // information on it.
    139   void FinishCode(Handle<Code> code);
    140 
    141   // Deferred code support.
    142   void DoDeferredNumberTagD(LNumberTagD* instr);
    143 
    144   enum IntegerSignedness { SIGNED_INT32, UNSIGNED_INT32 };
    145   void DoDeferredNumberTagI(LInstruction* instr,
    146                             LOperand* value,
    147                             IntegerSignedness signedness);
    148 
    149   void DoDeferredTaggedToI(LTaggedToI* instr);
    150   void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr);
    151   void DoDeferredStackCheck(LStackCheck* instr);
    152   void DoDeferredRandom(LRandom* instr);
    153   void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
    154   void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
    155   void DoDeferredAllocate(LAllocate* instr);
    156   void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
    157                                        Label* map_check);
    158   void DoDeferredInstanceMigration(LCheckMaps* instr, Register object);
    159 
    160   // Parallel move support.
    161   void DoParallelMove(LParallelMove* move);
    162   void DoGap(LGap* instr);
    163 
    164   MemOperand PrepareKeyedOperand(Register key,
    165                                  Register base,
    166                                  bool key_is_constant,
    167                                  int constant_key,
    168                                  int element_size,
    169                                  int shift_size,
    170                                  int additional_index,
    171                                  int additional_offset);
    172 
    173   // Emit frame translation commands for an environment.
    174   void WriteTranslation(LEnvironment* environment, Translation* translation);
    175 
    176   // Declare methods that deal with the individual node types.
    177 #define DECLARE_DO(type) void Do##type(L##type* node);
    178   LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
    179 #undef DECLARE_DO
    180 
    181  private:
    182   enum Status {
    183     UNUSED,
    184     GENERATING,
    185     DONE,
    186     ABORTED
    187   };
    188 
    189   bool is_unused() const { return status_ == UNUSED; }
    190   bool is_generating() const { return status_ == GENERATING; }
    191   bool is_done() const { return status_ == DONE; }
    192   bool is_aborted() const { return status_ == ABORTED; }
    193 
    194   StrictModeFlag strict_mode_flag() const {
    195     return info()->is_classic_mode() ? kNonStrictMode : kStrictMode;
    196   }
    197 
    198   LPlatformChunk* chunk() const { return chunk_; }
    199   Scope* scope() const { return scope_; }
    200   HGraph* graph() const { return chunk()->graph(); }
    201 
    202   Register scratch0() { return r9; }
    203   LowDwVfpRegister double_scratch0() { return kScratchDoubleReg; }
    204 
    205   int GetNextEmittedBlock() const;
    206   LInstruction* GetNextInstruction();
    207 
    208   void EmitClassOfTest(Label* if_true,
    209                        Label* if_false,
    210                        Handle<String> class_name,
    211                        Register input,
    212                        Register temporary,
    213                        Register temporary2);
    214 
    215   int GetStackSlotCount() const { return chunk()->spill_slot_count(); }
    216 
    217   void Abort(BailoutReason reason);
    218   void FPRINTF_CHECKING Comment(const char* format, ...);
    219 
    220   void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code, zone()); }
    221 
    222   // Code generation passes.  Returns true if code generation should
    223   // continue.
    224   bool GeneratePrologue();
    225   bool GenerateBody();
    226   bool GenerateDeferredCode();
    227   bool GenerateDeoptJumpTable();
    228   bool GenerateSafepointTable();
    229 
    230   enum SafepointMode {
    231     RECORD_SIMPLE_SAFEPOINT,
    232     RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS
    233   };
    234 
    235   void CallCode(
    236       Handle<Code> code,
    237       RelocInfo::Mode mode,
    238       LInstruction* instr,
    239       TargetAddressStorageMode storage_mode = CAN_INLINE_TARGET_ADDRESS);
    240 
    241   void CallCodeGeneric(
    242       Handle<Code> code,
    243       RelocInfo::Mode mode,
    244       LInstruction* instr,
    245       SafepointMode safepoint_mode,
    246       TargetAddressStorageMode storage_mode = CAN_INLINE_TARGET_ADDRESS);
    247 
    248   void CallRuntime(const Runtime::Function* function,
    249                    int num_arguments,
    250                    LInstruction* instr);
    251 
    252   void CallRuntime(Runtime::FunctionId id,
    253                    int num_arguments,
    254                    LInstruction* instr) {
    255     const Runtime::Function* function = Runtime::FunctionForId(id);
    256     CallRuntime(function, num_arguments, instr);
    257   }
    258 
    259   void CallRuntimeFromDeferred(Runtime::FunctionId id,
    260                                int argc,
    261                                LInstruction* instr);
    262 
    263   enum R1State {
    264     R1_UNINITIALIZED,
    265     R1_CONTAINS_TARGET
    266   };
    267 
    268   // Generate a direct call to a known function.  Expects the function
    269   // to be in r1.
    270   void CallKnownFunction(Handle<JSFunction> function,
    271                          int formal_parameter_count,
    272                          int arity,
    273                          LInstruction* instr,
    274                          CallKind call_kind,
    275                          R1State r1_state);
    276 
    277   void LoadHeapObject(Register result, Handle<HeapObject> object);
    278 
    279   void RecordSafepointWithLazyDeopt(LInstruction* instr,
    280                                     SafepointMode safepoint_mode);
    281 
    282   void RegisterEnvironmentForDeoptimization(LEnvironment* environment,
    283                                             Safepoint::DeoptMode mode);
    284   void DeoptimizeIf(Condition condition,
    285                     LEnvironment* environment,
    286                     Deoptimizer::BailoutType bailout_type);
    287   void DeoptimizeIf(Condition condition, LEnvironment* environment);
    288   void ApplyCheckIf(Condition condition, LBoundsCheck* check);
    289 
    290   void AddToTranslation(LEnvironment* environment,
    291                         Translation* translation,
    292                         LOperand* op,
    293                         bool is_tagged,
    294                         bool is_uint32,
    295                         int* object_index_pointer,
    296                         int* dematerialized_index_pointer);
    297   void RegisterDependentCodeForEmbeddedMaps(Handle<Code> code);
    298   void PopulateDeoptimizationData(Handle<Code> code);
    299   int DefineDeoptimizationLiteral(Handle<Object> literal);
    300 
    301   void PopulateDeoptimizationLiteralsWithInlinedFunctions();
    302 
    303   Register ToRegister(int index) const;
    304   DwVfpRegister ToDoubleRegister(int index) const;
    305 
    306   void EmitIntegerMathAbs(LMathAbs* instr);
    307 
    308   // Support for recording safepoint and position information.
    309   void RecordSafepoint(LPointerMap* pointers,
    310                        Safepoint::Kind kind,
    311                        int arguments,
    312                        Safepoint::DeoptMode mode);
    313   void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode);
    314   void RecordSafepoint(Safepoint::DeoptMode mode);
    315   void RecordSafepointWithRegisters(LPointerMap* pointers,
    316                                     int arguments,
    317                                     Safepoint::DeoptMode mode);
    318   void RecordSafepointWithRegistersAndDoubles(LPointerMap* pointers,
    319                                               int arguments,
    320                                               Safepoint::DeoptMode mode);
    321   void RecordPosition(int position);
    322   void RecordAndUpdatePosition(int position);
    323 
    324   static Condition TokenToCondition(Token::Value op, bool is_unsigned);
    325   void EmitGoto(int block);
    326   template<class InstrType>
    327   void EmitBranch(InstrType instr, Condition condition);
    328   template<class InstrType>
    329   void EmitFalseBranch(InstrType instr, Condition condition);
    330   void EmitNumberUntagD(Register input,
    331                         DwVfpRegister result,
    332                         bool allow_undefined_as_nan,
    333                         bool deoptimize_on_minus_zero,
    334                         LEnvironment* env,
    335                         NumberUntagDMode mode);
    336 
    337   // Emits optimized code for typeof x == "y".  Modifies input register.
    338   // Returns the condition on which a final split to
    339   // true and false label should be made, to optimize fallthrough.
    340   Condition EmitTypeofIs(Label* true_label,
    341                          Label* false_label,
    342                          Register input,
    343                          Handle<String> type_name);
    344 
    345   // Emits optimized code for %_IsObject(x).  Preserves input register.
    346   // Returns the condition on which a final split to
    347   // true and false label should be made, to optimize fallthrough.
    348   Condition EmitIsObject(Register input,
    349                          Register temp1,
    350                          Label* is_not_object,
    351                          Label* is_object);
    352 
    353   // Emits optimized code for %_IsString(x).  Preserves input register.
    354   // Returns the condition on which a final split to
    355   // true and false label should be made, to optimize fallthrough.
    356   Condition EmitIsString(Register input,
    357                          Register temp1,
    358                          Label* is_not_string,
    359                          SmiCheck check_needed);
    360 
    361   // Emits optimized code for %_IsConstructCall().
    362   // Caller should branch on equal condition.
    363   void EmitIsConstructCall(Register temp1, Register temp2);
    364 
    365   // Emits optimized code to deep-copy the contents of statically known
    366   // object graphs (e.g. object literal boilerplate).
    367   void EmitDeepCopy(Handle<JSObject> object,
    368                     Register result,
    369                     Register source,
    370                     int* offset,
    371                     AllocationSiteMode mode);
    372 
    373   // Emit optimized code for integer division.
    374   // Inputs are signed.
    375   // All registers are clobbered.
    376   // If 'remainder' is no_reg, it is not computed.
    377   void EmitSignedIntegerDivisionByConstant(Register result,
    378                                            Register dividend,
    379                                            int32_t divisor,
    380                                            Register remainder,
    381                                            Register scratch,
    382                                            LEnvironment* environment);
    383 
    384   void EnsureSpaceForLazyDeopt();
    385   void DoLoadKeyedExternalArray(LLoadKeyed* instr);
    386   void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr);
    387   void DoLoadKeyedFixedArray(LLoadKeyed* instr);
    388   void DoStoreKeyedExternalArray(LStoreKeyed* instr);
    389   void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr);
    390   void DoStoreKeyedFixedArray(LStoreKeyed* instr);
    391 
    392   Zone* zone_;
    393   LPlatformChunk* const chunk_;
    394   MacroAssembler* const masm_;
    395   CompilationInfo* const info_;
    396 
    397   int current_block_;
    398   int current_instruction_;
    399   const ZoneList<LInstruction*>* instructions_;
    400   ZoneList<LEnvironment*> deoptimizations_;
    401   ZoneList<Deoptimizer::JumpTableEntry> deopt_jump_table_;
    402   ZoneList<Handle<Object> > deoptimization_literals_;
    403   int inlined_function_count_;
    404   Scope* const scope_;
    405   Status status_;
    406   TranslationBuffer translations_;
    407   ZoneList<LDeferredCode*> deferred_;
    408   int osr_pc_offset_;
    409   int last_lazy_deopt_pc_;
    410   bool frame_is_built_;
    411 
    412   // Builder that keeps track of safepoints in the code. The table
    413   // itself is emitted at the end of the generated code.
    414   SafepointTableBuilder safepoints_;
    415 
    416   // Compiler from a set of parallel moves to a sequential list of moves.
    417   LGapResolver resolver_;
    418 
    419   Safepoint::Kind expected_safepoint_kind_;
    420 
    421   int old_position_;
    422 
    423   class PushSafepointRegistersScope BASE_EMBEDDED {
    424    public:
    425     PushSafepointRegistersScope(LCodeGen* codegen,
    426                                 Safepoint::Kind kind)
    427         : codegen_(codegen) {
    428       ASSERT(codegen_->info()->is_calling());
    429       ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kSimple);
    430       codegen_->expected_safepoint_kind_ = kind;
    431 
    432       switch (codegen_->expected_safepoint_kind_) {
    433         case Safepoint::kWithRegisters:
    434           codegen_->masm_->PushSafepointRegisters();
    435           break;
    436         case Safepoint::kWithRegistersAndDoubles:
    437           codegen_->masm_->PushSafepointRegistersAndDoubles();
    438           break;
    439         default:
    440           UNREACHABLE();
    441       }
    442     }
    443 
    444     ~PushSafepointRegistersScope() {
    445       Safepoint::Kind kind = codegen_->expected_safepoint_kind_;
    446       ASSERT((kind & Safepoint::kWithRegisters) != 0);
    447       switch (kind) {
    448         case Safepoint::kWithRegisters:
    449           codegen_->masm_->PopSafepointRegisters();
    450           break;
    451         case Safepoint::kWithRegistersAndDoubles:
    452           codegen_->masm_->PopSafepointRegistersAndDoubles();
    453           break;
    454         default:
    455           UNREACHABLE();
    456       }
    457       codegen_->expected_safepoint_kind_ = Safepoint::kSimple;
    458     }
    459 
    460    private:
    461     LCodeGen* codegen_;
    462   };
    463 
    464   friend class LDeferredCode;
    465   friend class LEnvironment;
    466   friend class SafepointGenerator;
    467   DISALLOW_COPY_AND_ASSIGN(LCodeGen);
    468 };
    469 
    470 
    471 class LDeferredCode: public ZoneObject {
    472  public:
    473   explicit LDeferredCode(LCodeGen* codegen)
    474       : codegen_(codegen),
    475         external_exit_(NULL),
    476         instruction_index_(codegen->current_instruction_) {
    477     codegen->AddDeferredCode(this);
    478   }
    479 
    480   virtual ~LDeferredCode() { }
    481   virtual void Generate() = 0;
    482   virtual LInstruction* instr() = 0;
    483 
    484   void SetExit(Label* exit) { external_exit_ = exit; }
    485   Label* entry() { return &entry_; }
    486   Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
    487   int instruction_index() const { return instruction_index_; }
    488 
    489  protected:
    490   LCodeGen* codegen() const { return codegen_; }
    491   MacroAssembler* masm() const { return codegen_->masm(); }
    492 
    493  private:
    494   LCodeGen* codegen_;
    495   Label entry_;
    496   Label exit_;
    497   Label* external_exit_;
    498   int instruction_index_;
    499 };
    500 
    501 } }  // namespace v8::internal
    502 
    503 #endif  // V8_ARM_LITHIUM_CODEGEN_ARM_H_
    504