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