Home | History | Annotate | Download | only in ia32
      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_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         last_lazy_deopt_pc_(0),
     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 
     81   bool IsInteger32(LConstantOperand* op) const;
     82   Immediate ToInteger32Immediate(LOperand* op) const {
     83     return Immediate(ToInteger32(LConstantOperand::cast(op)));
     84   }
     85 
     86   Handle<Object> ToHandle(LConstantOperand* op) const;
     87 
     88   // The operand denoting the second word (the one with a higher address) of
     89   // a double stack slot.
     90   Operand HighOperand(LOperand* op);
     91 
     92   // Try to generate code for the entire chunk, but it may fail if the
     93   // chunk contains constructs we cannot handle. Returns true if the
     94   // code generation attempt succeeded.
     95   bool GenerateCode();
     96 
     97   // Finish the code by setting stack height, safepoint, and bailout
     98   // information on it.
     99   void FinishCode(Handle<Code> code);
    100 
    101   // Deferred code support.
    102   void DoDeferredNumberTagD(LNumberTagD* instr);
    103   void DoDeferredNumberTagI(LNumberTagI* instr);
    104   void DoDeferredTaggedToI(LTaggedToI* instr);
    105   void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
    106   void DoDeferredStackCheck(LStackCheck* instr);
    107   void DoDeferredRandom(LRandom* instr);
    108   void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
    109   void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
    110   void DoDeferredAllocateObject(LAllocateObject* instr);
    111   void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
    112                                        Label* map_check);
    113 
    114   void DoCheckMapCommon(Register reg, Handle<Map> map,
    115                         CompareMapMode mode, LEnvironment* env);
    116 
    117   // Parallel move support.
    118   void DoParallelMove(LParallelMove* move);
    119   void DoGap(LGap* instr);
    120 
    121   // Emit frame translation commands for an environment.
    122   void WriteTranslation(LEnvironment* environment, Translation* translation);
    123 
    124   void EnsureRelocSpaceForDeoptimization();
    125 
    126   // Declare methods that deal with the individual node types.
    127 #define DECLARE_DO(type) void Do##type(L##type* node);
    128   LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
    129 #undef DECLARE_DO
    130 
    131  private:
    132   enum Status {
    133     UNUSED,
    134     GENERATING,
    135     DONE,
    136     ABORTED
    137   };
    138 
    139   bool is_unused() const { return status_ == UNUSED; }
    140   bool is_generating() const { return status_ == GENERATING; }
    141   bool is_done() const { return status_ == DONE; }
    142   bool is_aborted() const { return status_ == ABORTED; }
    143 
    144   StrictModeFlag strict_mode_flag() const {
    145     return info()->is_classic_mode() ? kNonStrictMode : kStrictMode;
    146   }
    147 
    148   LChunk* chunk() const { return chunk_; }
    149   Scope* scope() const { return scope_; }
    150   HGraph* graph() const { return chunk_->graph(); }
    151 
    152   int GetNextEmittedBlock(int block);
    153 
    154   void EmitClassOfTest(Label* if_true,
    155                        Label* if_false,
    156                        Handle<String> class_name,
    157                        Register input,
    158                        Register temporary,
    159                        Register temporary2);
    160 
    161   int GetStackSlotCount() const { return chunk()->spill_slot_count(); }
    162   int GetParameterCount() const { return scope()->num_parameters(); }
    163 
    164   void Abort(const char* format, ...);
    165   void Comment(const char* format, ...);
    166 
    167   void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code); }
    168 
    169   // Code generation passes.  Returns true if code generation should
    170   // continue.
    171   bool GeneratePrologue();
    172   bool GenerateBody();
    173   bool GenerateDeferredCode();
    174   // Pad the reloc info to ensure that we have enough space to patch during
    175   // deoptimization.
    176   bool GenerateRelocPadding();
    177   bool GenerateSafepointTable();
    178 
    179   enum SafepointMode {
    180     RECORD_SIMPLE_SAFEPOINT,
    181     RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS
    182   };
    183 
    184   void CallCode(Handle<Code> code,
    185                 RelocInfo::Mode mode,
    186                 LInstruction* instr);
    187 
    188   void CallCodeGeneric(Handle<Code> code,
    189                        RelocInfo::Mode mode,
    190                        LInstruction* instr,
    191                        SafepointMode safepoint_mode);
    192 
    193   void CallRuntime(const Runtime::Function* fun,
    194                    int argc,
    195                    LInstruction* instr);
    196 
    197   void CallRuntime(Runtime::FunctionId id,
    198                    int argc,
    199                    LInstruction* instr) {
    200     const Runtime::Function* function = Runtime::FunctionForId(id);
    201     CallRuntime(function, argc, instr);
    202   }
    203 
    204   void CallRuntimeFromDeferred(Runtime::FunctionId id,
    205                                int argc,
    206                                LInstruction* instr,
    207                                LOperand* context);
    208 
    209   // Generate a direct call to a known function.  Expects the function
    210   // to be in edi.
    211   void CallKnownFunction(Handle<JSFunction> function,
    212                          int arity,
    213                          LInstruction* instr,
    214                          CallKind call_kind);
    215 
    216   void RecordSafepointWithLazyDeopt(LInstruction* instr,
    217                                     SafepointMode safepoint_mode);
    218 
    219   void RegisterEnvironmentForDeoptimization(LEnvironment* environment,
    220                                             Safepoint::DeoptMode mode);
    221   void DeoptimizeIf(Condition cc, LEnvironment* environment);
    222 
    223   void AddToTranslation(Translation* translation,
    224                         LOperand* op,
    225                         bool is_tagged);
    226   void PopulateDeoptimizationData(Handle<Code> code);
    227   int DefineDeoptimizationLiteral(Handle<Object> literal);
    228 
    229   void PopulateDeoptimizationLiteralsWithInlinedFunctions();
    230 
    231   Register ToRegister(int index) const;
    232   XMMRegister ToDoubleRegister(int index) const;
    233   int ToInteger32(LConstantOperand* op) const;
    234 
    235   double ToDouble(LConstantOperand* op) const;
    236   Operand BuildFastArrayOperand(LOperand* elements_pointer,
    237                                 LOperand* key,
    238                                 ElementsKind elements_kind,
    239                                 uint32_t offset);
    240 
    241   // Specific math operations - used from DoUnaryMathOperation.
    242   void EmitIntegerMathAbs(LUnaryMathOperation* instr);
    243   void DoMathAbs(LUnaryMathOperation* instr);
    244   void DoMathFloor(LUnaryMathOperation* instr);
    245   void DoMathRound(LUnaryMathOperation* instr);
    246   void DoMathSqrt(LUnaryMathOperation* instr);
    247   void DoMathLog(LUnaryMathOperation* instr);
    248   void DoMathTan(LUnaryMathOperation* instr);
    249   void DoMathCos(LUnaryMathOperation* instr);
    250   void DoMathSin(LUnaryMathOperation* instr);
    251 
    252   // Support for recording safepoint and position information.
    253   void RecordSafepoint(LPointerMap* pointers,
    254                        Safepoint::Kind kind,
    255                        int arguments,
    256                        Safepoint::DeoptMode mode);
    257   void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode);
    258   void RecordSafepoint(Safepoint::DeoptMode mode);
    259   void RecordSafepointWithRegisters(LPointerMap* pointers,
    260                                     int arguments,
    261                                     Safepoint::DeoptMode mode);
    262   void RecordPosition(int position);
    263 
    264   static Condition TokenToCondition(Token::Value op, bool is_unsigned);
    265   void EmitGoto(int block);
    266   void EmitBranch(int left_block, int right_block, Condition cc);
    267   void EmitNumberUntagD(Register input,
    268                         Register temp,
    269                         XMMRegister result,
    270                         bool deoptimize_on_undefined,
    271                         bool deoptimize_on_minus_zero,
    272                         LEnvironment* env);
    273 
    274   // Emits optimized code for typeof x == "y".  Modifies input register.
    275   // Returns the condition on which a final split to
    276   // true and false label should be made, to optimize fallthrough.
    277   Condition EmitTypeofIs(Label* true_label,
    278                          Label* false_label,
    279                          Register input,
    280                          Handle<String> type_name);
    281 
    282   // Emits optimized code for %_IsObject(x).  Preserves input register.
    283   // Returns the condition on which a final split to
    284   // true and false label should be made, to optimize fallthrough.
    285   Condition EmitIsObject(Register input,
    286                          Register temp1,
    287                          Label* is_not_object,
    288                          Label* is_object);
    289 
    290   // Emits optimized code for %_IsString(x).  Preserves input register.
    291   // Returns the condition on which a final split to
    292   // true and false label should be made, to optimize fallthrough.
    293   Condition EmitIsString(Register input,
    294                          Register temp1,
    295                          Label* is_not_string);
    296 
    297   // Emits optimized code for %_IsConstructCall().
    298   // Caller should branch on equal condition.
    299   void EmitIsConstructCall(Register temp);
    300 
    301   void EmitLoadFieldOrConstantFunction(Register result,
    302                                        Register object,
    303                                        Handle<Map> type,
    304                                        Handle<String> name);
    305 
    306   // Emits optimized code to deep-copy the contents of statically known
    307   // object graphs (e.g. object literal boilerplate).
    308   void EmitDeepCopy(Handle<JSObject> object,
    309                     Register result,
    310                     Register source,
    311                     int* offset);
    312 
    313   void EnsureSpaceForLazyDeopt();
    314 
    315   // Emits code for pushing either a tagged constant, a (non-double)
    316   // register, or a stack slot operand.
    317   void EmitPushTaggedOperand(LOperand* operand);
    318 
    319   LChunk* const chunk_;
    320   MacroAssembler* const masm_;
    321   CompilationInfo* const info_;
    322 
    323   int current_block_;
    324   int current_instruction_;
    325   const ZoneList<LInstruction*>* instructions_;
    326   ZoneList<LEnvironment*> deoptimizations_;
    327   ZoneList<Handle<Object> > deoptimization_literals_;
    328   int inlined_function_count_;
    329   Scope* const scope_;
    330   Status status_;
    331   TranslationBuffer translations_;
    332   ZoneList<LDeferredCode*> deferred_;
    333   int osr_pc_offset_;
    334   int last_lazy_deopt_pc_;
    335 
    336   // Builder that keeps track of safepoints in the code. The table
    337   // itself is emitted at the end of the generated code.
    338   SafepointTableBuilder safepoints_;
    339 
    340   // Compiler from a set of parallel moves to a sequential list of moves.
    341   LGapResolver resolver_;
    342 
    343   Safepoint::Kind expected_safepoint_kind_;
    344 
    345   class PushSafepointRegistersScope BASE_EMBEDDED {
    346    public:
    347     explicit PushSafepointRegistersScope(LCodeGen* codegen)
    348         : codegen_(codegen) {
    349       ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kSimple);
    350       codegen_->masm_->PushSafepointRegisters();
    351       codegen_->expected_safepoint_kind_ = Safepoint::kWithRegisters;
    352     }
    353 
    354     ~PushSafepointRegistersScope() {
    355       ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kWithRegisters);
    356       codegen_->masm_->PopSafepointRegisters();
    357       codegen_->expected_safepoint_kind_ = Safepoint::kSimple;
    358     }
    359 
    360    private:
    361     LCodeGen* codegen_;
    362   };
    363 
    364   friend class LDeferredCode;
    365   friend class LEnvironment;
    366   friend class SafepointGenerator;
    367   DISALLOW_COPY_AND_ASSIGN(LCodeGen);
    368 };
    369 
    370 
    371 class LDeferredCode: public ZoneObject {
    372  public:
    373   explicit LDeferredCode(LCodeGen* codegen)
    374       : codegen_(codegen),
    375         external_exit_(NULL),
    376         instruction_index_(codegen->current_instruction_) {
    377     codegen->AddDeferredCode(this);
    378   }
    379 
    380   virtual ~LDeferredCode() { }
    381   virtual void Generate() = 0;
    382   virtual LInstruction* instr() = 0;
    383 
    384   void SetExit(Label* exit) { external_exit_ = exit; }
    385   Label* entry() { return &entry_; }
    386   Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
    387   int instruction_index() const { return instruction_index_; }
    388 
    389  protected:
    390   LCodeGen* codegen() const { return codegen_; }
    391   MacroAssembler* masm() const { return codegen_->masm(); }
    392 
    393  private:
    394   LCodeGen* codegen_;
    395   Label entry_;
    396   Label exit_;
    397   Label* external_exit_;
    398   int instruction_index_;
    399 };
    400 
    401 } }  // namespace v8::internal
    402 
    403 #endif  // V8_IA32_LITHIUM_CODEGEN_IA32_H_
    404