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 #include "arm/lithium-gap-resolver-arm.h"
     33 #include "deoptimizer.h"
     34 #include "safepoint-table.h"
     35 #include "scopes.h"
     36 
     37 namespace v8 {
     38 namespace internal {
     39 
     40 // Forward declarations.
     41 class LDeferredCode;
     42 class SafepointGenerator;
     43 
     44 class LCodeGen BASE_EMBEDDED {
     45  public:
     46   LCodeGen(LChunk* chunk, MacroAssembler* assembler, CompilationInfo* info)
     47       : chunk_(chunk),
     48         masm_(assembler),
     49         info_(info),
     50         current_block_(-1),
     51         current_instruction_(-1),
     52         instructions_(chunk->instructions()),
     53         deoptimizations_(4),
     54         deopt_jump_table_(4),
     55         deoptimization_literals_(8),
     56         inlined_function_count_(0),
     57         scope_(info->scope()),
     58         status_(UNUSED),
     59         deferred_(8),
     60         osr_pc_offset_(-1),
     61         last_lazy_deopt_pc_(0),
     62         resolver_(this),
     63         expected_safepoint_kind_(Safepoint::kSimple) {
     64     PopulateDeoptimizationLiteralsWithInlinedFunctions();
     65   }
     66 
     67 
     68   // Simple accessors.
     69   MacroAssembler* masm() const { return masm_; }
     70   CompilationInfo* info() const { return info_; }
     71   Isolate* isolate() const { return info_->isolate(); }
     72   Factory* factory() const { return isolate()->factory(); }
     73   Heap* heap() const { return isolate()->heap(); }
     74 
     75   // Support for converting LOperands to assembler types.
     76   // LOperand must be a register.
     77   Register ToRegister(LOperand* op) const;
     78 
     79   // LOperand is loaded into scratch, unless already a register.
     80   Register EmitLoadRegister(LOperand* op, Register scratch);
     81 
     82   // LOperand must be a double register.
     83   DoubleRegister ToDoubleRegister(LOperand* op) const;
     84 
     85   // LOperand is loaded into dbl_scratch, unless already a double register.
     86   DoubleRegister EmitLoadDoubleRegister(LOperand* op,
     87                                         SwVfpRegister flt_scratch,
     88                                         DoubleRegister dbl_scratch);
     89   int ToInteger32(LConstantOperand* op) const;
     90   double ToDouble(LConstantOperand* op) const;
     91   Operand ToOperand(LOperand* op);
     92   MemOperand ToMemOperand(LOperand* op) const;
     93   // Returns a MemOperand pointing to the high word of a DoubleStackSlot.
     94   MemOperand ToHighMemOperand(LOperand* op) const;
     95 
     96   bool IsInteger32(LConstantOperand* op) const;
     97   Handle<Object> ToHandle(LConstantOperand* op) const;
     98 
     99   // Try to generate code for the entire chunk, but it may fail if the
    100   // chunk contains constructs we cannot handle. Returns true if the
    101   // code generation attempt succeeded.
    102   bool GenerateCode();
    103 
    104   // Finish the code by setting stack height, safepoint, and bailout
    105   // information on it.
    106   void FinishCode(Handle<Code> code);
    107 
    108   // Deferred code support.
    109   template<int T>
    110   void DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr,
    111                               Token::Value op);
    112   void DoDeferredNumberTagD(LNumberTagD* instr);
    113   void DoDeferredNumberTagI(LNumberTagI* instr);
    114   void DoDeferredTaggedToI(LTaggedToI* instr);
    115   void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
    116   void DoDeferredStackCheck(LStackCheck* instr);
    117   void DoDeferredRandom(LRandom* instr);
    118   void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
    119   void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
    120   void DoDeferredAllocateObject(LAllocateObject* instr);
    121   void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
    122                                        Label* map_check);
    123 
    124   void DoCheckMapCommon(Register reg, Register scratch, Handle<Map> map,
    125                         CompareMapMode mode, LEnvironment* env);
    126 
    127   // Parallel move support.
    128   void DoParallelMove(LParallelMove* move);
    129   void DoGap(LGap* instr);
    130 
    131   // Emit frame translation commands for an environment.
    132   void WriteTranslation(LEnvironment* environment, Translation* translation);
    133 
    134   // Declare methods that deal with the individual node types.
    135 #define DECLARE_DO(type) void Do##type(L##type* node);
    136   LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
    137 #undef DECLARE_DO
    138 
    139  private:
    140   enum Status {
    141     UNUSED,
    142     GENERATING,
    143     DONE,
    144     ABORTED
    145   };
    146 
    147   bool is_unused() const { return status_ == UNUSED; }
    148   bool is_generating() const { return status_ == GENERATING; }
    149   bool is_done() const { return status_ == DONE; }
    150   bool is_aborted() const { return status_ == ABORTED; }
    151 
    152   StrictModeFlag strict_mode_flag() const {
    153     return info()->is_classic_mode() ? kNonStrictMode : kStrictMode;
    154   }
    155 
    156   LChunk* chunk() const { return chunk_; }
    157   Scope* scope() const { return scope_; }
    158   HGraph* graph() const { return chunk_->graph(); }
    159 
    160   Register scratch0() { return r9; }
    161   DwVfpRegister double_scratch0() { return kScratchDoubleReg; }
    162 
    163   int GetNextEmittedBlock(int block);
    164   LInstruction* GetNextInstruction();
    165 
    166   void EmitClassOfTest(Label* if_true,
    167                        Label* if_false,
    168                        Handle<String> class_name,
    169                        Register input,
    170                        Register temporary,
    171                        Register temporary2);
    172 
    173   int GetStackSlotCount() const { return chunk()->spill_slot_count(); }
    174   int GetParameterCount() const { return scope()->num_parameters(); }
    175 
    176   void Abort(const char* format, ...);
    177   void Comment(const char* format, ...);
    178 
    179   void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code); }
    180 
    181   // Code generation passes.  Returns true if code generation should
    182   // continue.
    183   bool GeneratePrologue();
    184   bool GenerateBody();
    185   bool GenerateDeferredCode();
    186   bool GenerateDeoptJumpTable();
    187   bool GenerateSafepointTable();
    188 
    189   enum SafepointMode {
    190     RECORD_SIMPLE_SAFEPOINT,
    191     RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS
    192   };
    193 
    194   void CallCode(Handle<Code> code,
    195                 RelocInfo::Mode mode,
    196                 LInstruction* instr);
    197 
    198   void CallCodeGeneric(Handle<Code> code,
    199                        RelocInfo::Mode mode,
    200                        LInstruction* instr,
    201                        SafepointMode safepoint_mode);
    202 
    203   void CallRuntime(const Runtime::Function* function,
    204                    int num_arguments,
    205                    LInstruction* instr);
    206 
    207   void CallRuntime(Runtime::FunctionId id,
    208                    int num_arguments,
    209                    LInstruction* instr) {
    210     const Runtime::Function* function = Runtime::FunctionForId(id);
    211     CallRuntime(function, num_arguments, instr);
    212   }
    213 
    214   void CallRuntimeFromDeferred(Runtime::FunctionId id,
    215                                int argc,
    216                                LInstruction* instr);
    217 
    218   // Generate a direct call to a known function.  Expects the function
    219   // to be in r1.
    220   void CallKnownFunction(Handle<JSFunction> function,
    221                          int arity,
    222                          LInstruction* instr,
    223                          CallKind call_kind);
    224 
    225   void LoadHeapObject(Register result, Handle<HeapObject> object);
    226 
    227   void RecordSafepointWithLazyDeopt(LInstruction* instr,
    228                                     SafepointMode safepoint_mode);
    229 
    230   void RegisterEnvironmentForDeoptimization(LEnvironment* environment,
    231                                             Safepoint::DeoptMode mode);
    232   void DeoptimizeIf(Condition cc, LEnvironment* environment);
    233 
    234   void AddToTranslation(Translation* translation,
    235                         LOperand* op,
    236                         bool is_tagged);
    237   void PopulateDeoptimizationData(Handle<Code> code);
    238   int DefineDeoptimizationLiteral(Handle<Object> literal);
    239 
    240   void PopulateDeoptimizationLiteralsWithInlinedFunctions();
    241 
    242   Register ToRegister(int index) const;
    243   DoubleRegister ToDoubleRegister(int index) const;
    244 
    245   // Specific math operations - used from DoUnaryMathOperation.
    246   void EmitIntegerMathAbs(LUnaryMathOperation* instr);
    247   void DoMathAbs(LUnaryMathOperation* instr);
    248   void DoMathFloor(LUnaryMathOperation* instr);
    249   void DoMathRound(LUnaryMathOperation* instr);
    250   void DoMathSqrt(LUnaryMathOperation* instr);
    251   void DoMathPowHalf(LUnaryMathOperation* instr);
    252   void DoMathLog(LUnaryMathOperation* instr);
    253   void DoMathTan(LUnaryMathOperation* instr);
    254   void DoMathCos(LUnaryMathOperation* instr);
    255   void DoMathSin(LUnaryMathOperation* instr);
    256 
    257   // Support for recording safepoint and position information.
    258   void RecordSafepoint(LPointerMap* pointers,
    259                        Safepoint::Kind kind,
    260                        int arguments,
    261                        Safepoint::DeoptMode mode);
    262   void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode);
    263   void RecordSafepoint(Safepoint::DeoptMode mode);
    264   void RecordSafepointWithRegisters(LPointerMap* pointers,
    265                                     int arguments,
    266                                     Safepoint::DeoptMode mode);
    267   void RecordSafepointWithRegistersAndDoubles(LPointerMap* pointers,
    268                                               int arguments,
    269                                               Safepoint::DeoptMode mode);
    270   void RecordPosition(int position);
    271 
    272   static Condition TokenToCondition(Token::Value op, bool is_unsigned);
    273   void EmitGoto(int block);
    274   void EmitBranch(int left_block, int right_block, Condition cc);
    275   void EmitNumberUntagD(Register input,
    276                         DoubleRegister result,
    277                         bool deoptimize_on_undefined,
    278                         bool deoptimize_on_minus_zero,
    279                         LEnvironment* env);
    280 
    281   // Emits optimized code for typeof x == "y".  Modifies input register.
    282   // Returns the condition on which a final split to
    283   // true and false label should be made, to optimize fallthrough.
    284   Condition EmitTypeofIs(Label* true_label,
    285                          Label* false_label,
    286                          Register input,
    287                          Handle<String> type_name);
    288 
    289   // Emits optimized code for %_IsObject(x).  Preserves input register.
    290   // Returns the condition on which a final split to
    291   // true and false label should be made, to optimize fallthrough.
    292   Condition EmitIsObject(Register input,
    293                          Register temp1,
    294                          Label* is_not_object,
    295                          Label* is_object);
    296 
    297   // Emits optimized code for %_IsString(x).  Preserves input register.
    298   // Returns the condition on which a final split to
    299   // true and false label should be made, to optimize fallthrough.
    300   Condition EmitIsString(Register input,
    301                          Register temp1,
    302                          Label* is_not_string);
    303 
    304   // Emits optimized code for %_IsConstructCall().
    305   // Caller should branch on equal condition.
    306   void EmitIsConstructCall(Register temp1, Register temp2);
    307 
    308   void EmitLoadFieldOrConstantFunction(Register result,
    309                                        Register object,
    310                                        Handle<Map> type,
    311                                        Handle<String> name);
    312 
    313   // Emits optimized code to deep-copy the contents of statically known
    314   // object graphs (e.g. object literal boilerplate).
    315   void EmitDeepCopy(Handle<JSObject> object,
    316                     Register result,
    317                     Register source,
    318                     int* offset);
    319 
    320   struct JumpTableEntry {
    321     explicit inline JumpTableEntry(Address entry)
    322         : label(),
    323           address(entry) { }
    324     Label label;
    325     Address address;
    326   };
    327 
    328   void EnsureSpaceForLazyDeopt();
    329 
    330   LChunk* const chunk_;
    331   MacroAssembler* const masm_;
    332   CompilationInfo* const info_;
    333 
    334   int current_block_;
    335   int current_instruction_;
    336   const ZoneList<LInstruction*>* instructions_;
    337   ZoneList<LEnvironment*> deoptimizations_;
    338   ZoneList<JumpTableEntry> deopt_jump_table_;
    339   ZoneList<Handle<Object> > deoptimization_literals_;
    340   int inlined_function_count_;
    341   Scope* const scope_;
    342   Status status_;
    343   TranslationBuffer translations_;
    344   ZoneList<LDeferredCode*> deferred_;
    345   int osr_pc_offset_;
    346   int last_lazy_deopt_pc_;
    347 
    348   // Builder that keeps track of safepoints in the code. The table
    349   // itself is emitted at the end of the generated code.
    350   SafepointTableBuilder safepoints_;
    351 
    352   // Compiler from a set of parallel moves to a sequential list of moves.
    353   LGapResolver resolver_;
    354 
    355   Safepoint::Kind expected_safepoint_kind_;
    356 
    357   class PushSafepointRegistersScope BASE_EMBEDDED {
    358    public:
    359     PushSafepointRegistersScope(LCodeGen* codegen,
    360                                 Safepoint::Kind kind)
    361         : codegen_(codegen) {
    362       ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kSimple);
    363       codegen_->expected_safepoint_kind_ = kind;
    364 
    365       switch (codegen_->expected_safepoint_kind_) {
    366         case Safepoint::kWithRegisters:
    367           codegen_->masm_->PushSafepointRegisters();
    368           break;
    369         case Safepoint::kWithRegistersAndDoubles:
    370           codegen_->masm_->PushSafepointRegistersAndDoubles();
    371           break;
    372         default:
    373           UNREACHABLE();
    374       }
    375     }
    376 
    377     ~PushSafepointRegistersScope() {
    378       Safepoint::Kind kind = codegen_->expected_safepoint_kind_;
    379       ASSERT((kind & Safepoint::kWithRegisters) != 0);
    380       switch (kind) {
    381         case Safepoint::kWithRegisters:
    382           codegen_->masm_->PopSafepointRegisters();
    383           break;
    384         case Safepoint::kWithRegistersAndDoubles:
    385           codegen_->masm_->PopSafepointRegistersAndDoubles();
    386           break;
    387         default:
    388           UNREACHABLE();
    389       }
    390       codegen_->expected_safepoint_kind_ = Safepoint::kSimple;
    391     }
    392 
    393    private:
    394     LCodeGen* codegen_;
    395   };
    396 
    397   friend class LDeferredCode;
    398   friend class LEnvironment;
    399   friend class SafepointGenerator;
    400   DISALLOW_COPY_AND_ASSIGN(LCodeGen);
    401 };
    402 
    403 
    404 class LDeferredCode: public ZoneObject {
    405  public:
    406   explicit LDeferredCode(LCodeGen* codegen)
    407       : codegen_(codegen),
    408         external_exit_(NULL),
    409         instruction_index_(codegen->current_instruction_) {
    410     codegen->AddDeferredCode(this);
    411   }
    412 
    413   virtual ~LDeferredCode() { }
    414   virtual void Generate() = 0;
    415   virtual LInstruction* instr() = 0;
    416 
    417   void SetExit(Label* exit) { external_exit_ = exit; }
    418   Label* entry() { return &entry_; }
    419   Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
    420   int instruction_index() const { return instruction_index_; }
    421 
    422  protected:
    423   LCodeGen* codegen() const { return codegen_; }
    424   MacroAssembler* masm() const { return codegen_->masm(); }
    425 
    426  private:
    427   LCodeGen* codegen_;
    428   Label entry_;
    429   Label exit_;
    430   Label* external_exit_;
    431   int instruction_index_;
    432 };
    433 
    434 } }  // namespace v8::internal
    435 
    436 #endif  // V8_ARM_LITHIUM_CODEGEN_ARM_H_
    437