Home | History | Annotate | Download | only in src
      1 // Copyright 2006-2008 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_CODEGEN_H_
     29 #define V8_CODEGEN_H_
     30 
     31 #include "ast.h"
     32 #include "code-stubs.h"
     33 #include "runtime.h"
     34 #include "number-info.h"
     35 
     36 // Include the declaration of the architecture defined class CodeGenerator.
     37 // The contract  to the shared code is that the the CodeGenerator is a subclass
     38 // of Visitor and that the following methods are available publicly:
     39 //   MakeCode
     40 //   MakeCodePrologue
     41 //   MakeCodeEpilogue
     42 //   masm
     43 //   frame
     44 //   script
     45 //   has_valid_frame
     46 //   SetFrame
     47 //   DeleteFrame
     48 //   allocator
     49 //   AddDeferred
     50 //   in_spilled_code
     51 //   set_in_spilled_code
     52 //   RecordPositions
     53 //
     54 // These methods are either used privately by the shared code or implemented as
     55 // shared code:
     56 //   CodeGenerator
     57 //   ~CodeGenerator
     58 //   ProcessDeferred
     59 //   Generate
     60 //   ComputeLazyCompile
     61 //   BuildBoilerplate
     62 //   ComputeCallInitialize
     63 //   ComputeCallInitializeInLoop
     64 //   ProcessDeclarations
     65 //   DeclareGlobals
     66 //   FindInlineRuntimeLUT
     67 //   CheckForInlineRuntimeCall
     68 //   PatchInlineRuntimeEntry
     69 //   AnalyzeCondition
     70 //   CodeForFunctionPosition
     71 //   CodeForReturnPosition
     72 //   CodeForStatementPosition
     73 //   CodeForDoWhileConditionPosition
     74 //   CodeForSourcePosition
     75 
     76 
     77 // Mode to overwrite BinaryExpression values.
     78 enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
     79 
     80 // Types of uncatchable exceptions.
     81 enum UncatchableExceptionType { OUT_OF_MEMORY, TERMINATION };
     82 
     83 
     84 #if V8_TARGET_ARCH_IA32
     85 #include "ia32/codegen-ia32.h"
     86 #elif V8_TARGET_ARCH_X64
     87 #include "x64/codegen-x64.h"
     88 #elif V8_TARGET_ARCH_ARM
     89 #include "arm/codegen-arm.h"
     90 #elif V8_TARGET_ARCH_MIPS
     91 #include "mips/codegen-mips.h"
     92 #else
     93 #error Unsupported target architecture.
     94 #endif
     95 
     96 #include "register-allocator.h"
     97 
     98 namespace v8 {
     99 namespace internal {
    100 
    101 
    102 // Support for "structured" code comments.
    103 #ifdef DEBUG
    104 
    105 class Comment BASE_EMBEDDED {
    106  public:
    107   Comment(MacroAssembler* masm, const char* msg);
    108   ~Comment();
    109 
    110  private:
    111   MacroAssembler* masm_;
    112   const char* msg_;
    113 };
    114 
    115 #else
    116 
    117 class Comment BASE_EMBEDDED {
    118  public:
    119   Comment(MacroAssembler*, const char*)  {}
    120 };
    121 
    122 #endif  // DEBUG
    123 
    124 
    125 // Code generation can be nested.  Code generation scopes form a stack
    126 // of active code generators.
    127 class CodeGeneratorScope BASE_EMBEDDED {
    128  public:
    129   explicit CodeGeneratorScope(CodeGenerator* cgen) {
    130     previous_ = top_;
    131     top_ = cgen;
    132   }
    133 
    134   ~CodeGeneratorScope() {
    135     top_ = previous_;
    136   }
    137 
    138   static CodeGenerator* Current() {
    139     ASSERT(top_ != NULL);
    140     return top_;
    141   }
    142 
    143  private:
    144   static CodeGenerator* top_;
    145   CodeGenerator* previous_;
    146 };
    147 
    148 
    149 // Deferred code objects are small pieces of code that are compiled
    150 // out of line. They are used to defer the compilation of uncommon
    151 // paths thereby avoiding expensive jumps around uncommon code parts.
    152 class DeferredCode: public ZoneObject {
    153  public:
    154   DeferredCode();
    155   virtual ~DeferredCode() { }
    156 
    157   virtual void Generate() = 0;
    158 
    159   MacroAssembler* masm() { return masm_; }
    160 
    161   int statement_position() const { return statement_position_; }
    162   int position() const { return position_; }
    163 
    164   Label* entry_label() { return &entry_label_; }
    165   Label* exit_label() { return &exit_label_; }
    166 
    167 #ifdef DEBUG
    168   void set_comment(const char* comment) { comment_ = comment; }
    169   const char* comment() const { return comment_; }
    170 #else
    171   void set_comment(const char* comment) { }
    172   const char* comment() const { return ""; }
    173 #endif
    174 
    175   inline void Jump();
    176   inline void Branch(Condition cc);
    177   void BindExit() { masm_->bind(&exit_label_); }
    178 
    179   void SaveRegisters();
    180   void RestoreRegisters();
    181 
    182  protected:
    183   MacroAssembler* masm_;
    184 
    185  private:
    186   // Constants indicating special actions.  They should not be multiples
    187   // of kPointerSize so they will not collide with valid offsets from
    188   // the frame pointer.
    189   static const int kIgnore = -1;
    190   static const int kPush = 1;
    191 
    192   // This flag is ored with a valid offset from the frame pointer, so
    193   // it should fit in the low zero bits of a valid offset.
    194   static const int kSyncedFlag = 2;
    195 
    196   int statement_position_;
    197   int position_;
    198 
    199   Label entry_label_;
    200   Label exit_label_;
    201 
    202   int registers_[RegisterAllocator::kNumRegisters];
    203 
    204 #ifdef DEBUG
    205   const char* comment_;
    206 #endif
    207   DISALLOW_COPY_AND_ASSIGN(DeferredCode);
    208 };
    209 
    210 class StackCheckStub : public CodeStub {
    211  public:
    212   StackCheckStub() { }
    213 
    214   void Generate(MacroAssembler* masm);
    215 
    216  private:
    217 
    218   const char* GetName() { return "StackCheckStub"; }
    219 
    220   Major MajorKey() { return StackCheck; }
    221   int MinorKey() { return 0; }
    222 };
    223 
    224 
    225 class FastNewClosureStub : public CodeStub {
    226  public:
    227   void Generate(MacroAssembler* masm);
    228 
    229  private:
    230   const char* GetName() { return "FastNewClosureStub"; }
    231   Major MajorKey() { return FastNewClosure; }
    232   int MinorKey() { return 0; }
    233 };
    234 
    235 
    236 class FastNewContextStub : public CodeStub {
    237  public:
    238   static const int kMaximumSlots = 64;
    239 
    240   explicit FastNewContextStub(int slots) : slots_(slots) {
    241     ASSERT(slots_ > 0 && slots <= kMaximumSlots);
    242   }
    243 
    244   void Generate(MacroAssembler* masm);
    245 
    246  private:
    247   int slots_;
    248 
    249   const char* GetName() { return "FastNewContextStub"; }
    250   Major MajorKey() { return FastNewContext; }
    251   int MinorKey() { return slots_; }
    252 };
    253 
    254 
    255 class FastCloneShallowArrayStub : public CodeStub {
    256  public:
    257   static const int kMaximumLength = 8;
    258 
    259   explicit FastCloneShallowArrayStub(int length) : length_(length) {
    260     ASSERT(length >= 0 && length <= kMaximumLength);
    261   }
    262 
    263   void Generate(MacroAssembler* masm);
    264 
    265  private:
    266   int length_;
    267 
    268   const char* GetName() { return "FastCloneShallowArrayStub"; }
    269   Major MajorKey() { return FastCloneShallowArray; }
    270   int MinorKey() { return length_; }
    271 };
    272 
    273 
    274 class InstanceofStub: public CodeStub {
    275  public:
    276   InstanceofStub() { }
    277 
    278   void Generate(MacroAssembler* masm);
    279 
    280  private:
    281   Major MajorKey() { return Instanceof; }
    282   int MinorKey() { return 0; }
    283 };
    284 
    285 
    286 class GenericUnaryOpStub : public CodeStub {
    287  public:
    288   GenericUnaryOpStub(Token::Value op, bool overwrite)
    289       : op_(op), overwrite_(overwrite) { }
    290 
    291  private:
    292   Token::Value op_;
    293   bool overwrite_;
    294 
    295   class OverwriteField: public BitField<int, 0, 1> {};
    296   class OpField: public BitField<Token::Value, 1, kMinorBits - 1> {};
    297 
    298   Major MajorKey() { return GenericUnaryOp; }
    299   int MinorKey() {
    300     return OpField::encode(op_) | OverwriteField::encode(overwrite_);
    301   }
    302 
    303   void Generate(MacroAssembler* masm);
    304 
    305   const char* GetName();
    306 };
    307 
    308 
    309 enum NaNInformation {
    310   kBothCouldBeNaN,
    311   kCantBothBeNaN
    312 };
    313 
    314 
    315 class CompareStub: public CodeStub {
    316  public:
    317   CompareStub(Condition cc,
    318               bool strict,
    319               NaNInformation nan_info = kBothCouldBeNaN) :
    320       cc_(cc), strict_(strict), never_nan_nan_(nan_info == kCantBothBeNaN) { }
    321 
    322   void Generate(MacroAssembler* masm);
    323 
    324  private:
    325   Condition cc_;
    326   bool strict_;
    327   // Only used for 'equal' comparisons.  Tells the stub that we already know
    328   // that at least one side of the comparison is not NaN.  This allows the
    329   // stub to use object identity in the positive case.  We ignore it when
    330   // generating the minor key for other comparisons to avoid creating more
    331   // stubs.
    332   bool never_nan_nan_;
    333 
    334   Major MajorKey() { return Compare; }
    335 
    336   int MinorKey();
    337 
    338   // Branch to the label if the given object isn't a symbol.
    339   void BranchIfNonSymbol(MacroAssembler* masm,
    340                          Label* label,
    341                          Register object,
    342                          Register scratch);
    343 
    344   // Unfortunately you have to run without snapshots to see most of these
    345   // names in the profile since most compare stubs end up in the snapshot.
    346   const char* GetName();
    347 #ifdef DEBUG
    348   void Print() {
    349     PrintF("CompareStub (cc %d), (strict %s)\n",
    350            static_cast<int>(cc_),
    351            strict_ ? "true" : "false");
    352   }
    353 #endif
    354 };
    355 
    356 
    357 class CEntryStub : public CodeStub {
    358  public:
    359   explicit CEntryStub(int result_size,
    360                       ExitFrame::Mode mode = ExitFrame::MODE_NORMAL)
    361       : result_size_(result_size), mode_(mode) { }
    362 
    363   void Generate(MacroAssembler* masm);
    364 
    365  private:
    366   void GenerateCore(MacroAssembler* masm,
    367                     Label* throw_normal_exception,
    368                     Label* throw_termination_exception,
    369                     Label* throw_out_of_memory_exception,
    370                     bool do_gc,
    371                     bool always_allocate_scope);
    372   void GenerateThrowTOS(MacroAssembler* masm);
    373   void GenerateThrowUncatchable(MacroAssembler* masm,
    374                                 UncatchableExceptionType type);
    375 
    376   // Number of pointers/values returned.
    377   const int result_size_;
    378   const ExitFrame::Mode mode_;
    379 
    380   // Minor key encoding
    381   class ExitFrameModeBits: public BitField<ExitFrame::Mode, 0, 1> {};
    382   class IndirectResultBits: public BitField<bool, 1, 1> {};
    383 
    384   Major MajorKey() { return CEntry; }
    385   // Minor key must differ if different result_size_ values means different
    386   // code is generated.
    387   int MinorKey();
    388 
    389   const char* GetName() { return "CEntryStub"; }
    390 };
    391 
    392 
    393 class ApiGetterEntryStub : public CodeStub {
    394  public:
    395   ApiGetterEntryStub(Handle<AccessorInfo> info,
    396                      ApiFunction* fun)
    397       : info_(info),
    398         fun_(fun) { }
    399   void Generate(MacroAssembler* masm);
    400   virtual bool has_custom_cache() { return true; }
    401   virtual bool GetCustomCache(Code** code_out);
    402   virtual void SetCustomCache(Code* value);
    403 
    404   static const int kStackSpace = 6;
    405   static const int kArgc = 4;
    406  private:
    407   Handle<AccessorInfo> info() { return info_; }
    408   ApiFunction* fun() { return fun_; }
    409   Major MajorKey() { return NoCache; }
    410   int MinorKey() { return 0; }
    411   const char* GetName() { return "ApiEntryStub"; }
    412   // The accessor info associated with the function.
    413   Handle<AccessorInfo> info_;
    414   // The function to be called.
    415   ApiFunction* fun_;
    416 };
    417 
    418 
    419 class JSEntryStub : public CodeStub {
    420  public:
    421   JSEntryStub() { }
    422 
    423   void Generate(MacroAssembler* masm) { GenerateBody(masm, false); }
    424 
    425  protected:
    426   void GenerateBody(MacroAssembler* masm, bool is_construct);
    427 
    428  private:
    429   Major MajorKey() { return JSEntry; }
    430   int MinorKey() { return 0; }
    431 
    432   const char* GetName() { return "JSEntryStub"; }
    433 };
    434 
    435 
    436 class JSConstructEntryStub : public JSEntryStub {
    437  public:
    438   JSConstructEntryStub() { }
    439 
    440   void Generate(MacroAssembler* masm) { GenerateBody(masm, true); }
    441 
    442  private:
    443   int MinorKey() { return 1; }
    444 
    445   const char* GetName() { return "JSConstructEntryStub"; }
    446 };
    447 
    448 
    449 class ArgumentsAccessStub: public CodeStub {
    450  public:
    451   enum Type {
    452     READ_LENGTH,
    453     READ_ELEMENT,
    454     NEW_OBJECT
    455   };
    456 
    457   explicit ArgumentsAccessStub(Type type) : type_(type) { }
    458 
    459  private:
    460   Type type_;
    461 
    462   Major MajorKey() { return ArgumentsAccess; }
    463   int MinorKey() { return type_; }
    464 
    465   void Generate(MacroAssembler* masm);
    466   void GenerateReadLength(MacroAssembler* masm);
    467   void GenerateReadElement(MacroAssembler* masm);
    468   void GenerateNewObject(MacroAssembler* masm);
    469 
    470   const char* GetName() { return "ArgumentsAccessStub"; }
    471 
    472 #ifdef DEBUG
    473   void Print() {
    474     PrintF("ArgumentsAccessStub (type %d)\n", type_);
    475   }
    476 #endif
    477 };
    478 
    479 
    480 class RegExpExecStub: public CodeStub {
    481  public:
    482   RegExpExecStub() { }
    483 
    484  private:
    485   Major MajorKey() { return RegExpExec; }
    486   int MinorKey() { return 0; }
    487 
    488   void Generate(MacroAssembler* masm);
    489 
    490   const char* GetName() { return "RegExpExecStub"; }
    491 
    492 #ifdef DEBUG
    493   void Print() {
    494     PrintF("RegExpExecStub\n");
    495   }
    496 #endif
    497 };
    498 
    499 
    500 class CallFunctionStub: public CodeStub {
    501  public:
    502   CallFunctionStub(int argc, InLoopFlag in_loop, CallFunctionFlags flags)
    503       : argc_(argc), in_loop_(in_loop), flags_(flags) { }
    504 
    505   void Generate(MacroAssembler* masm);
    506 
    507  private:
    508   int argc_;
    509   InLoopFlag in_loop_;
    510   CallFunctionFlags flags_;
    511 
    512 #ifdef DEBUG
    513   void Print() {
    514     PrintF("CallFunctionStub (args %d, in_loop %d, flags %d)\n",
    515            argc_,
    516            static_cast<int>(in_loop_),
    517            static_cast<int>(flags_));
    518   }
    519 #endif
    520 
    521   // Minor key encoding in 32 bits with Bitfield <Type, shift, size>.
    522   class InLoopBits: public BitField<InLoopFlag, 0, 1> {};
    523   class FlagBits: public BitField<CallFunctionFlags, 1, 1> {};
    524   class ArgcBits: public BitField<int, 2, 32 - 2> {};
    525 
    526   Major MajorKey() { return CallFunction; }
    527   int MinorKey() {
    528     // Encode the parameters in a unique 32 bit value.
    529     return InLoopBits::encode(in_loop_)
    530            | FlagBits::encode(flags_)
    531            | ArgcBits::encode(argc_);
    532   }
    533 
    534   InLoopFlag InLoop() { return in_loop_; }
    535   bool ReceiverMightBeValue() {
    536     return (flags_ & RECEIVER_MIGHT_BE_VALUE) != 0;
    537   }
    538 
    539  public:
    540   static int ExtractArgcFromMinorKey(int minor_key) {
    541     return ArgcBits::decode(minor_key);
    542   }
    543 };
    544 
    545 
    546 class ToBooleanStub: public CodeStub {
    547  public:
    548   ToBooleanStub() { }
    549 
    550   void Generate(MacroAssembler* masm);
    551 
    552  private:
    553   Major MajorKey() { return ToBoolean; }
    554   int MinorKey() { return 0; }
    555 };
    556 
    557 
    558 }  // namespace internal
    559 }  // namespace v8
    560 
    561 #endif  // V8_CODEGEN_H_
    562