Home | History | Annotate | Download | only in mips
      1 // Copyright 2010 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_MIPS_CODE_STUBS_ARM_H_
     29 #define V8_MIPS_CODE_STUBS_ARM_H_
     30 
     31 #include "ic-inl.h"
     32 
     33 
     34 namespace v8 {
     35 namespace internal {
     36 
     37 
     38 // Compute a transcendental math function natively, or call the
     39 // TranscendentalCache runtime function.
     40 class TranscendentalCacheStub: public CodeStub {
     41  public:
     42   explicit TranscendentalCacheStub(TranscendentalCache::Type type)
     43       : type_(type) {}
     44   void Generate(MacroAssembler* masm);
     45  private:
     46   TranscendentalCache::Type type_;
     47   Major MajorKey() { return TranscendentalCache; }
     48   int MinorKey() { return type_; }
     49   Runtime::FunctionId RuntimeFunction();
     50 };
     51 
     52 
     53 class ToBooleanStub: public CodeStub {
     54  public:
     55   explicit ToBooleanStub(Register tos) : tos_(tos) { }
     56 
     57   void Generate(MacroAssembler* masm);
     58 
     59  private:
     60   Register tos_;
     61   Major MajorKey() { return ToBoolean; }
     62   int MinorKey() { return tos_.code(); }
     63 };
     64 
     65 
     66 class GenericBinaryOpStub : public CodeStub {
     67  public:
     68   static const int kUnknownIntValue = -1;
     69 
     70   GenericBinaryOpStub(Token::Value op,
     71                       OverwriteMode mode,
     72                       Register lhs,
     73                       Register rhs,
     74                       int constant_rhs = kUnknownIntValue)
     75       : op_(op),
     76         mode_(mode),
     77         lhs_(lhs),
     78         rhs_(rhs),
     79         constant_rhs_(constant_rhs),
     80         specialized_on_rhs_(RhsIsOneWeWantToOptimizeFor(op, constant_rhs)),
     81         runtime_operands_type_(BinaryOpIC::UNINIT_OR_SMI),
     82         name_(NULL) { }
     83 
     84   GenericBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info)
     85       : op_(OpBits::decode(key)),
     86         mode_(ModeBits::decode(key)),
     87         lhs_(LhsRegister(RegisterBits::decode(key))),
     88         rhs_(RhsRegister(RegisterBits::decode(key))),
     89         constant_rhs_(KnownBitsForMinorKey(KnownIntBits::decode(key))),
     90         specialized_on_rhs_(RhsIsOneWeWantToOptimizeFor(op_, constant_rhs_)),
     91         runtime_operands_type_(type_info),
     92         name_(NULL) { }
     93 
     94  private:
     95   Token::Value op_;
     96   OverwriteMode mode_;
     97   Register lhs_;
     98   Register rhs_;
     99   int constant_rhs_;
    100   bool specialized_on_rhs_;
    101   BinaryOpIC::TypeInfo runtime_operands_type_;
    102   char* name_;
    103 
    104   static const int kMaxKnownRhs = 0x40000000;
    105   static const int kKnownRhsKeyBits = 6;
    106 
    107   // Minor key encoding in 16 bits.
    108   class ModeBits: public BitField<OverwriteMode, 0, 2> {};
    109   class OpBits: public BitField<Token::Value, 2, 6> {};
    110   class TypeInfoBits: public BitField<int, 8, 3> {};
    111   class RegisterBits: public BitField<bool, 11, 1> {};
    112   class KnownIntBits: public BitField<int, 12, kKnownRhsKeyBits> {};
    113 
    114   Major MajorKey() { return GenericBinaryOp; }
    115   int MinorKey() {
    116     ASSERT((lhs_.is(a0) && rhs_.is(a1)) ||
    117            (lhs_.is(a1) && rhs_.is(a0)));
    118     // Encode the parameters in a unique 16 bit value.
    119     return OpBits::encode(op_)
    120            | ModeBits::encode(mode_)
    121            | KnownIntBits::encode(MinorKeyForKnownInt())
    122            | TypeInfoBits::encode(runtime_operands_type_)
    123            | RegisterBits::encode(lhs_.is(a0));
    124   }
    125 
    126   void Generate(MacroAssembler* masm);
    127   void HandleNonSmiBitwiseOp(MacroAssembler* masm,
    128                              Register lhs,
    129                              Register rhs);
    130   void HandleBinaryOpSlowCases(MacroAssembler* masm,
    131                                Label* not_smi,
    132                                Register lhs,
    133                                Register rhs,
    134                                const Builtins::JavaScript& builtin);
    135   void GenerateTypeTransition(MacroAssembler* masm);
    136 
    137   static bool RhsIsOneWeWantToOptimizeFor(Token::Value op, int constant_rhs) {
    138     if (constant_rhs == kUnknownIntValue) return false;
    139     if (op == Token::DIV) return constant_rhs >= 2 && constant_rhs <= 3;
    140     if (op == Token::MOD) {
    141       if (constant_rhs <= 1) return false;
    142       if (constant_rhs <= 10) return true;
    143       if (constant_rhs <= kMaxKnownRhs && IsPowerOf2(constant_rhs)) return true;
    144       return false;
    145     }
    146     return false;
    147   }
    148 
    149   int MinorKeyForKnownInt() {
    150     if (!specialized_on_rhs_) return 0;
    151     if (constant_rhs_ <= 10) return constant_rhs_ + 1;
    152     ASSERT(IsPowerOf2(constant_rhs_));
    153     int key = 12;
    154     int d = constant_rhs_;
    155     while ((d & 1) == 0) {
    156       key++;
    157       d >>= 1;
    158     }
    159     ASSERT(key >= 0 && key < (1 << kKnownRhsKeyBits));
    160     return key;
    161   }
    162 
    163   int KnownBitsForMinorKey(int key) {
    164     if (!key) return 0;
    165     if (key <= 11) return key - 1;
    166     int d = 1;
    167     while (key != 12) {
    168       key--;
    169       d <<= 1;
    170     }
    171     return d;
    172   }
    173 
    174   Register LhsRegister(bool lhs_is_a0) {
    175     return lhs_is_a0 ? a0 : a1;
    176   }
    177 
    178   Register RhsRegister(bool lhs_is_a0) {
    179     return lhs_is_a0 ? a1 : a0;
    180   }
    181 
    182   bool HasSmiSmiFastPath() {
    183     return op_ != Token::DIV;
    184   }
    185 
    186   bool ShouldGenerateSmiCode() {
    187     return ((op_ != Token::DIV && op_ != Token::MOD) || specialized_on_rhs_) &&
    188         runtime_operands_type_ != BinaryOpIC::HEAP_NUMBERS &&
    189         runtime_operands_type_ != BinaryOpIC::STRINGS;
    190   }
    191 
    192   bool ShouldGenerateFPCode() {
    193     return runtime_operands_type_ != BinaryOpIC::STRINGS;
    194   }
    195 
    196   virtual int GetCodeKind() { return Code::BINARY_OP_IC; }
    197 
    198   virtual InlineCacheState GetICState() {
    199     return BinaryOpIC::ToState(runtime_operands_type_);
    200   }
    201 
    202   const char* GetName();
    203 
    204   virtual void FinishCode(Code* code) {
    205     code->set_binary_op_type(runtime_operands_type_);
    206   }
    207 
    208 #ifdef DEBUG
    209   void Print() {
    210     if (!specialized_on_rhs_) {
    211       PrintF("GenericBinaryOpStub (%s)\n", Token::String(op_));
    212     } else {
    213       PrintF("GenericBinaryOpStub (%s by %d)\n",
    214              Token::String(op_),
    215              constant_rhs_);
    216     }
    217   }
    218 #endif
    219 };
    220 
    221 class TypeRecordingBinaryOpStub: public CodeStub {
    222  public:
    223   TypeRecordingBinaryOpStub(Token::Value op, OverwriteMode mode)
    224       : op_(op),
    225         mode_(mode),
    226         operands_type_(TRBinaryOpIC::UNINITIALIZED),
    227         result_type_(TRBinaryOpIC::UNINITIALIZED),
    228         name_(NULL) {
    229     UNIMPLEMENTED_MIPS();
    230   }
    231 
    232   TypeRecordingBinaryOpStub(
    233       int key,
    234       TRBinaryOpIC::TypeInfo operands_type,
    235       TRBinaryOpIC::TypeInfo result_type = TRBinaryOpIC::UNINITIALIZED)
    236       : op_(OpBits::decode(key)),
    237         mode_(ModeBits::decode(key)),
    238         use_fpu_(FPUBits::decode(key)),
    239         operands_type_(operands_type),
    240         result_type_(result_type),
    241         name_(NULL) { }
    242 
    243  private:
    244   enum SmiCodeGenerateHeapNumberResults {
    245     ALLOW_HEAPNUMBER_RESULTS,
    246     NO_HEAPNUMBER_RESULTS
    247   };
    248 
    249   Token::Value op_;
    250   OverwriteMode mode_;
    251   bool use_fpu_;
    252 
    253   // Operand type information determined at runtime.
    254   TRBinaryOpIC::TypeInfo operands_type_;
    255   TRBinaryOpIC::TypeInfo result_type_;
    256 
    257   char* name_;
    258 
    259   const char* GetName();
    260 
    261 #ifdef DEBUG
    262   void Print() {
    263     PrintF("TypeRecordingBinaryOpStub %d (op %s), "
    264            "(mode %d, runtime_type_info %s)\n",
    265            MinorKey(),
    266            Token::String(op_),
    267            static_cast<int>(mode_),
    268            TRBinaryOpIC::GetName(operands_type_));
    269   }
    270 #endif
    271 
    272   // Minor key encoding in 16 bits RRRTTTVOOOOOOOMM.
    273   class ModeBits: public BitField<OverwriteMode, 0, 2> {};
    274   class OpBits: public BitField<Token::Value, 2, 7> {};
    275   class FPUBits: public BitField<bool, 9, 1> {};
    276   class OperandTypeInfoBits: public BitField<TRBinaryOpIC::TypeInfo, 10, 3> {};
    277   class ResultTypeInfoBits: public BitField<TRBinaryOpIC::TypeInfo, 13, 3> {};
    278 
    279   Major MajorKey() { return TypeRecordingBinaryOp; }
    280   int MinorKey() {
    281     return OpBits::encode(op_)
    282            | ModeBits::encode(mode_)
    283            | FPUBits::encode(use_fpu_)
    284            | OperandTypeInfoBits::encode(operands_type_)
    285            | ResultTypeInfoBits::encode(result_type_);
    286   }
    287 
    288   void Generate(MacroAssembler* masm);
    289   void GenerateGeneric(MacroAssembler* masm);
    290   void GenerateSmiSmiOperation(MacroAssembler* masm);
    291   void GenerateFPOperation(MacroAssembler* masm,
    292                            bool smi_operands,
    293                            Label* not_numbers,
    294                            Label* gc_required);
    295   void GenerateSmiCode(MacroAssembler* masm,
    296                        Label* gc_required,
    297                        SmiCodeGenerateHeapNumberResults heapnumber_results);
    298   void GenerateLoadArguments(MacroAssembler* masm);
    299   void GenerateReturn(MacroAssembler* masm);
    300   void GenerateUninitializedStub(MacroAssembler* masm);
    301   void GenerateSmiStub(MacroAssembler* masm);
    302   void GenerateInt32Stub(MacroAssembler* masm);
    303   void GenerateHeapNumberStub(MacroAssembler* masm);
    304   void GenerateStringStub(MacroAssembler* masm);
    305   void GenerateGenericStub(MacroAssembler* masm);
    306   void GenerateAddStrings(MacroAssembler* masm);
    307   void GenerateCallRuntime(MacroAssembler* masm);
    308 
    309   void GenerateHeapResultAllocation(MacroAssembler* masm,
    310                                     Register result,
    311                                     Register heap_number_map,
    312                                     Register scratch1,
    313                                     Register scratch2,
    314                                     Label* gc_required);
    315   void GenerateRegisterArgsPush(MacroAssembler* masm);
    316   void GenerateTypeTransition(MacroAssembler* masm);
    317   void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm);
    318 
    319   virtual int GetCodeKind() { return Code::TYPE_RECORDING_BINARY_OP_IC; }
    320 
    321   virtual InlineCacheState GetICState() {
    322     return TRBinaryOpIC::ToState(operands_type_);
    323   }
    324 
    325   virtual void FinishCode(Code* code) {
    326     code->set_type_recording_binary_op_type(operands_type_);
    327     code->set_type_recording_binary_op_result_type(result_type_);
    328   }
    329 
    330   friend class CodeGenerator;
    331 };
    332 
    333 
    334 // Flag that indicates how to generate code for the stub StringAddStub.
    335 enum StringAddFlags {
    336   NO_STRING_ADD_FLAGS = 0,
    337   NO_STRING_CHECK_IN_STUB = 1 << 0  // Omit string check in stub.
    338 };
    339 
    340 
    341 class StringAddStub: public CodeStub {
    342  public:
    343   explicit StringAddStub(StringAddFlags flags) {
    344     string_check_ = ((flags & NO_STRING_CHECK_IN_STUB) == 0);
    345   }
    346 
    347  private:
    348   Major MajorKey() { return StringAdd; }
    349   int MinorKey() { return string_check_ ? 0 : 1; }
    350 
    351   void Generate(MacroAssembler* masm);
    352 
    353   // Should the stub check whether arguments are strings?
    354   bool string_check_;
    355 };
    356 
    357 
    358 class SubStringStub: public CodeStub {
    359  public:
    360   SubStringStub() {}
    361 
    362  private:
    363   Major MajorKey() { return SubString; }
    364   int MinorKey() { return 0; }
    365 
    366   void Generate(MacroAssembler* masm);
    367 };
    368 
    369 
    370 class StringCompareStub: public CodeStub {
    371  public:
    372   StringCompareStub() { }
    373 
    374   // Compare two flat ASCII strings and returns result in v0.
    375   // Does not use the stack.
    376   static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
    377                                               Register left,
    378                                               Register right,
    379                                               Register scratch1,
    380                                               Register scratch2,
    381                                               Register scratch3,
    382                                               Register scratch4);
    383 
    384  private:
    385   Major MajorKey() { return StringCompare; }
    386   int MinorKey() { return 0; }
    387 
    388   void Generate(MacroAssembler* masm);
    389 };
    390 
    391 
    392 // This stub can convert a signed int32 to a heap number (double).  It does
    393 // not work for int32s that are in Smi range!  No GC occurs during this stub
    394 // so you don't have to set up the frame.
    395 class WriteInt32ToHeapNumberStub : public CodeStub {
    396  public:
    397   WriteInt32ToHeapNumberStub(Register the_int,
    398                              Register the_heap_number,
    399                              Register scratch,
    400                              Register scratch2)
    401       : the_int_(the_int),
    402         the_heap_number_(the_heap_number),
    403         scratch_(scratch),
    404         sign_(scratch2) { }
    405 
    406  private:
    407   Register the_int_;
    408   Register the_heap_number_;
    409   Register scratch_;
    410   Register sign_;
    411 
    412   // Minor key encoding in 16 bits.
    413   class IntRegisterBits: public BitField<int, 0, 4> {};
    414   class HeapNumberRegisterBits: public BitField<int, 4, 4> {};
    415   class ScratchRegisterBits: public BitField<int, 8, 4> {};
    416 
    417   Major MajorKey() { return WriteInt32ToHeapNumber; }
    418   int MinorKey() {
    419     // Encode the parameters in a unique 16 bit value.
    420     return IntRegisterBits::encode(the_int_.code())
    421            | HeapNumberRegisterBits::encode(the_heap_number_.code())
    422            | ScratchRegisterBits::encode(scratch_.code());
    423   }
    424 
    425   void Generate(MacroAssembler* masm);
    426 
    427   const char* GetName() { return "WriteInt32ToHeapNumberStub"; }
    428 
    429 #ifdef DEBUG
    430   void Print() { PrintF("WriteInt32ToHeapNumberStub\n"); }
    431 #endif
    432 };
    433 
    434 
    435 class NumberToStringStub: public CodeStub {
    436  public:
    437   NumberToStringStub() { }
    438 
    439   // Generate code to do a lookup in the number string cache. If the number in
    440   // the register object is found in the cache the generated code falls through
    441   // with the result in the result register. The object and the result register
    442   // can be the same. If the number is not found in the cache the code jumps to
    443   // the label not_found with only the content of register object unchanged.
    444   static void GenerateLookupNumberStringCache(MacroAssembler* masm,
    445                                               Register object,
    446                                               Register result,
    447                                               Register scratch1,
    448                                               Register scratch2,
    449                                               Register scratch3,
    450                                               bool object_is_smi,
    451                                               Label* not_found);
    452 
    453  private:
    454   Major MajorKey() { return NumberToString; }
    455   int MinorKey() { return 0; }
    456 
    457   void Generate(MacroAssembler* masm);
    458 
    459   const char* GetName() { return "NumberToStringStub"; }
    460 
    461 #ifdef DEBUG
    462   void Print() {
    463     PrintF("NumberToStringStub\n");
    464   }
    465 #endif
    466 };
    467 
    468 
    469 // Enter C code from generated RegExp code in a way that allows
    470 // the C code to fix the return address in case of a GC.
    471 // Currently only needed on ARM and MIPS.
    472 class RegExpCEntryStub: public CodeStub {
    473  public:
    474   RegExpCEntryStub() {}
    475   virtual ~RegExpCEntryStub() {}
    476   void Generate(MacroAssembler* masm);
    477 
    478  private:
    479   Major MajorKey() { return RegExpCEntry; }
    480   int MinorKey() { return 0; }
    481 
    482   bool NeedsImmovableCode() { return true; }
    483 
    484   const char* GetName() { return "RegExpCEntryStub"; }
    485 };
    486 
    487 
    488 // Generate code the to load an element from a pixel array. The receiver is
    489 // assumed to not be a smi and to have elements, the caller must guarantee this
    490 // precondition. If the receiver does not have elements that are pixel arrays,
    491 // the generated code jumps to not_pixel_array. If key is not a smi, then the
    492 // generated code branches to key_not_smi. Callers can specify NULL for
    493 // key_not_smi to signal that a smi check has already been performed on key so
    494 // that the smi check is not generated . If key is not a valid index within the
    495 // bounds of the pixel array, the generated code jumps to out_of_range.
    496 void GenerateFastPixelArrayLoad(MacroAssembler* masm,
    497                                 Register receiver,
    498                                 Register key,
    499                                 Register elements_map,
    500                                 Register elements,
    501                                 Register scratch1,
    502                                 Register scratch2,
    503                                 Register result,
    504                                 Label* not_pixel_array,
    505                                 Label* key_not_smi,
    506                                 Label* out_of_range);
    507 
    508 
    509 } }  // namespace v8::internal
    510 
    511 #endif  // V8_MIPS_CODE_STUBS_ARM_H_
    512