Home | History | Annotate | Download | only in x64
      1 // Copyright 2011 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_X64_LITHIUM_CODEGEN_X64_H_
     29 #define V8_X64_LITHIUM_CODEGEN_X64_H_
     30 
     31 #include "x64/lithium-x64.h"
     32 
     33 #include "checks.h"
     34 #include "deoptimizer.h"
     35 #include "safepoint-table.h"
     36 #include "scopes.h"
     37 #include "x64/lithium-gap-resolver-x64.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       : chunk_(chunk),
     50         masm_(assembler),
     51         info_(info),
     52         current_block_(-1),
     53         current_instruction_(-1),
     54         instructions_(chunk->instructions()),
     55         deoptimizations_(4),
     56         jump_table_(4),
     57         deoptimization_literals_(8),
     58         inlined_function_count_(0),
     59         scope_(info->scope()),
     60         status_(UNUSED),
     61         deferred_(8),
     62         osr_pc_offset_(-1),
     63         resolver_(this),
     64         expected_safepoint_kind_(Safepoint::kSimple) {
     65     PopulateDeoptimizationLiteralsWithInlinedFunctions();
     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   Register ToRegister(LOperand* op) const;
     77   XMMRegister ToDoubleRegister(LOperand* op) const;
     78   bool IsInteger32Constant(LConstantOperand* op) const;
     79   int ToInteger32(LConstantOperand* op) const;
     80   bool IsTaggedConstant(LConstantOperand* op) const;
     81   Handle<Object> ToHandle(LConstantOperand* op) const;
     82   Operand ToOperand(LOperand* op) const;
     83 
     84   // Try to generate code for the entire chunk, but it may fail if the
     85   // chunk contains constructs we cannot handle. Returns true if the
     86   // code generation attempt succeeded.
     87   bool GenerateCode();
     88 
     89   // Finish the code by setting stack height, safepoint, and bailout
     90   // information on it.
     91   void FinishCode(Handle<Code> code);
     92 
     93   // Deferred code support.
     94   void DoDeferredNumberTagD(LNumberTagD* instr);
     95   void DoDeferredTaggedToI(LTaggedToI* instr);
     96   void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
     97   void DoDeferredStackCheck(LGoto* instr);
     98   void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
     99   void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
    100   void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
    101                                         Label* map_check);
    102 
    103   // Parallel move support.
    104   void DoParallelMove(LParallelMove* move);
    105 
    106   // Emit frame translation commands for an environment.
    107   void WriteTranslation(LEnvironment* environment, Translation* translation);
    108 
    109   // Declare methods that deal with the individual node types.
    110 #define DECLARE_DO(type) void Do##type(L##type* node);
    111   LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
    112 #undef DECLARE_DO
    113 
    114  private:
    115   enum Status {
    116     UNUSED,
    117     GENERATING,
    118     DONE,
    119     ABORTED
    120   };
    121 
    122   bool is_unused() const { return status_ == UNUSED; }
    123   bool is_generating() const { return status_ == GENERATING; }
    124   bool is_done() const { return status_ == DONE; }
    125   bool is_aborted() const { return status_ == ABORTED; }
    126 
    127   int strict_mode_flag() const {
    128     return info()->is_strict_mode() ? kStrictMode : kNonStrictMode;
    129   }
    130 
    131   LChunk* chunk() const { return chunk_; }
    132   Scope* scope() const { return scope_; }
    133   HGraph* graph() const { return chunk_->graph(); }
    134 
    135   int GetNextEmittedBlock(int block);
    136   LInstruction* GetNextInstruction();
    137 
    138   void EmitClassOfTest(Label* if_true,
    139                        Label* if_false,
    140                        Handle<String> class_name,
    141                        Register input,
    142                        Register temporary);
    143 
    144   int StackSlotCount() const { return chunk()->spill_slot_count(); }
    145   int ParameterCount() const { return scope()->num_parameters(); }
    146 
    147   void Abort(const char* format, ...);
    148   void Comment(const char* format, ...);
    149 
    150   void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code); }
    151 
    152   // Code generation passes.  Returns true if code generation should
    153   // continue.
    154   bool GeneratePrologue();
    155   bool GenerateBody();
    156   bool GenerateDeferredCode();
    157   bool GenerateJumpTable();
    158   bool GenerateSafepointTable();
    159 
    160   enum SafepointMode {
    161     RECORD_SIMPLE_SAFEPOINT,
    162     RECORD_SAFEPOINT_WITH_REGISTERS
    163   };
    164 
    165   void CallCodeGeneric(Handle<Code> code,
    166                        RelocInfo::Mode mode,
    167                        LInstruction* instr,
    168                        SafepointMode safepoint_mode,
    169                        int argc);
    170 
    171 
    172   void CallCode(Handle<Code> code,
    173                 RelocInfo::Mode mode,
    174                 LInstruction* instr);
    175 
    176   void CallRuntime(const Runtime::Function* function,
    177                    int num_arguments,
    178                    LInstruction* instr);
    179 
    180   void CallRuntime(Runtime::FunctionId id,
    181                    int num_arguments,
    182                    LInstruction* instr) {
    183     const Runtime::Function* function = Runtime::FunctionForId(id);
    184     CallRuntime(function, num_arguments, instr);
    185   }
    186 
    187   void CallRuntimeFromDeferred(Runtime::FunctionId id,
    188                                int argc,
    189                                LInstruction* instr);
    190 
    191 
    192   // Generate a direct call to a known function.  Expects the function
    193   // to be in edi.
    194   void CallKnownFunction(Handle<JSFunction> function,
    195                          int arity,
    196                          LInstruction* instr);
    197 
    198   void LoadHeapObject(Register result, Handle<HeapObject> object);
    199 
    200   void RegisterLazyDeoptimization(LInstruction* instr,
    201                                   SafepointMode safepoint_mode,
    202                                   int argc);
    203   void RegisterEnvironmentForDeoptimization(LEnvironment* environment);
    204   void DeoptimizeIf(Condition cc, LEnvironment* environment);
    205 
    206   void AddToTranslation(Translation* translation,
    207                         LOperand* op,
    208                         bool is_tagged);
    209   void PopulateDeoptimizationData(Handle<Code> code);
    210   int DefineDeoptimizationLiteral(Handle<Object> literal);
    211 
    212   void PopulateDeoptimizationLiteralsWithInlinedFunctions();
    213 
    214   Register ToRegister(int index) const;
    215   XMMRegister ToDoubleRegister(int index) const;
    216 
    217   // Specific math operations - used from DoUnaryMathOperation.
    218   void EmitIntegerMathAbs(LUnaryMathOperation* instr);
    219   void DoMathAbs(LUnaryMathOperation* instr);
    220   void DoMathFloor(LUnaryMathOperation* instr);
    221   void DoMathRound(LUnaryMathOperation* instr);
    222   void DoMathSqrt(LUnaryMathOperation* instr);
    223   void DoMathPowHalf(LUnaryMathOperation* instr);
    224   void DoMathLog(LUnaryMathOperation* instr);
    225   void DoMathCos(LUnaryMathOperation* instr);
    226   void DoMathSin(LUnaryMathOperation* instr);
    227 
    228   // Support for recording safepoint and position information.
    229   void RecordSafepoint(LPointerMap* pointers,
    230                        Safepoint::Kind kind,
    231                        int arguments,
    232                        int deoptimization_index);
    233   void RecordSafepoint(LPointerMap* pointers, int deoptimization_index);
    234   void RecordSafepoint(int deoptimization_index);
    235   void RecordSafepointWithRegisters(LPointerMap* pointers,
    236                                     int arguments,
    237                                     int deoptimization_index);
    238   void RecordPosition(int position);
    239   int LastSafepointEnd() {
    240     return static_cast<int>(safepoints_.GetPcAfterGap());
    241   }
    242 
    243   static Condition TokenToCondition(Token::Value op, bool is_unsigned);
    244   void EmitGoto(int block, LDeferredCode* deferred_stack_check = NULL);
    245   void EmitBranch(int left_block, int right_block, Condition cc);
    246   void EmitCmpI(LOperand* left, LOperand* right);
    247   void EmitNumberUntagD(Register input,
    248                         XMMRegister result,
    249                         bool deoptimize_on_undefined,
    250                         LEnvironment* env);
    251 
    252   // Emits optimized code for typeof x == "y".  Modifies input register.
    253   // Returns the condition on which a final split to
    254   // true and false label should be made, to optimize fallthrough.
    255   Condition EmitTypeofIs(Label* true_label, Label* false_label,
    256                          Register input, Handle<String> type_name);
    257 
    258   // Emits optimized code for %_IsObject(x).  Preserves input register.
    259   // Returns the condition on which a final split to
    260   // true and false label should be made, to optimize fallthrough.
    261   Condition EmitIsObject(Register input,
    262                          Label* is_not_object,
    263                          Label* is_object);
    264 
    265   // Emits optimized code for %_IsConstructCall().
    266   // Caller should branch on equal condition.
    267   void EmitIsConstructCall(Register temp);
    268 
    269   void EmitLoadField(Register result,
    270                      Register object,
    271                      Handle<Map> type,
    272                      Handle<String> name);
    273 
    274   // Emits code for pushing a constant operand.
    275   void EmitPushConstantOperand(LOperand* operand);
    276 
    277   struct JumpTableEntry {
    278     explicit inline JumpTableEntry(Address entry)
    279         : label(),
    280           address(entry) { }
    281     Label label;
    282     Address address;
    283   };
    284 
    285   LChunk* const chunk_;
    286   MacroAssembler* const masm_;
    287   CompilationInfo* const info_;
    288 
    289   int current_block_;
    290   int current_instruction_;
    291   const ZoneList<LInstruction*>* instructions_;
    292   ZoneList<LEnvironment*> deoptimizations_;
    293   ZoneList<JumpTableEntry> jump_table_;
    294   ZoneList<Handle<Object> > deoptimization_literals_;
    295   int inlined_function_count_;
    296   Scope* const scope_;
    297   Status status_;
    298   TranslationBuffer translations_;
    299   ZoneList<LDeferredCode*> deferred_;
    300   int osr_pc_offset_;
    301 
    302   // Builder that keeps track of safepoints in the code. The table
    303   // itself is emitted at the end of the generated code.
    304   SafepointTableBuilder safepoints_;
    305 
    306   // Compiler from a set of parallel moves to a sequential list of moves.
    307   LGapResolver resolver_;
    308 
    309   Safepoint::Kind expected_safepoint_kind_;
    310 
    311   class PushSafepointRegistersScope BASE_EMBEDDED {
    312    public:
    313     explicit PushSafepointRegistersScope(LCodeGen* codegen)
    314         : codegen_(codegen) {
    315       ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kSimple);
    316       codegen_->masm_->PushSafepointRegisters();
    317       codegen_->expected_safepoint_kind_ = Safepoint::kWithRegisters;
    318     }
    319 
    320     ~PushSafepointRegistersScope() {
    321       ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kWithRegisters);
    322       codegen_->masm_->PopSafepointRegisters();
    323       codegen_->expected_safepoint_kind_ = Safepoint::kSimple;
    324     }
    325 
    326    private:
    327     LCodeGen* codegen_;
    328   };
    329 
    330   friend class LDeferredCode;
    331   friend class LEnvironment;
    332   friend class SafepointGenerator;
    333   DISALLOW_COPY_AND_ASSIGN(LCodeGen);
    334 };
    335 
    336 
    337 class LDeferredCode: public ZoneObject {
    338  public:
    339   explicit LDeferredCode(LCodeGen* codegen)
    340       : codegen_(codegen), external_exit_(NULL) {
    341     codegen->AddDeferredCode(this);
    342   }
    343 
    344   virtual ~LDeferredCode() { }
    345   virtual void Generate() = 0;
    346 
    347   void SetExit(Label *exit) { external_exit_ = exit; }
    348   Label* entry() { return &entry_; }
    349   Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
    350 
    351  protected:
    352   LCodeGen* codegen() const { return codegen_; }
    353   MacroAssembler* masm() const { return codegen_->masm(); }
    354 
    355  private:
    356   LCodeGen* codegen_;
    357   Label entry_;
    358   Label exit_;
    359   Label* external_exit_;
    360 };
    361 
    362 } }  // namespace v8::internal
    363 
    364 #endif  // V8_X64_LITHIUM_CODEGEN_X64_H_
    365