Home | History | Annotate | Download | only in mips
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 
      6 
      7 #include "src/v8.h"
      8 
      9 #if V8_TARGET_ARCH_MIPS
     10 
     11 #include "src/codegen.h"
     12 #include "src/code-stubs.h"
     13 #include "src/ic-inl.h"
     14 #include "src/runtime.h"
     15 #include "src/stub-cache.h"
     16 
     17 namespace v8 {
     18 namespace internal {
     19 
     20 
     21 // ----------------------------------------------------------------------------
     22 // Static IC stub generators.
     23 //
     24 
     25 #define __ ACCESS_MASM(masm)
     26 
     27 
     28 static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
     29                                             Register type,
     30                                             Label* global_object) {
     31   // Register usage:
     32   //   type: holds the receiver instance type on entry.
     33   __ Branch(global_object, eq, type, Operand(JS_GLOBAL_OBJECT_TYPE));
     34   __ Branch(global_object, eq, type, Operand(JS_BUILTINS_OBJECT_TYPE));
     35   __ Branch(global_object, eq, type, Operand(JS_GLOBAL_PROXY_TYPE));
     36 }
     37 
     38 
     39 // Generated code falls through if the receiver is a regular non-global
     40 // JS object with slow properties and no interceptors.
     41 static void GenerateNameDictionaryReceiverCheck(MacroAssembler* masm,
     42                                                 Register receiver,
     43                                                 Register elements,
     44                                                 Register scratch0,
     45                                                 Register scratch1,
     46                                                 Label* miss) {
     47   // Register usage:
     48   //   receiver: holds the receiver on entry and is unchanged.
     49   //   elements: holds the property dictionary on fall through.
     50   // Scratch registers:
     51   //   scratch0: used to holds the receiver map.
     52   //   scratch1: used to holds the receiver instance type, receiver bit mask
     53   //     and elements map.
     54 
     55   // Check that the receiver isn't a smi.
     56   __ JumpIfSmi(receiver, miss);
     57 
     58   // Check that the receiver is a valid JS object.
     59   __ GetObjectType(receiver, scratch0, scratch1);
     60   __ Branch(miss, lt, scratch1, Operand(FIRST_SPEC_OBJECT_TYPE));
     61 
     62   // If this assert fails, we have to check upper bound too.
     63   STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
     64 
     65   GenerateGlobalInstanceTypeCheck(masm, scratch1, miss);
     66 
     67   // Check that the global object does not require access checks.
     68   __ lbu(scratch1, FieldMemOperand(scratch0, Map::kBitFieldOffset));
     69   __ And(scratch1, scratch1, Operand((1 << Map::kIsAccessCheckNeeded) |
     70                            (1 << Map::kHasNamedInterceptor)));
     71   __ Branch(miss, ne, scratch1, Operand(zero_reg));
     72 
     73   __ lw(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
     74   __ lw(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
     75   __ LoadRoot(scratch0, Heap::kHashTableMapRootIndex);
     76   __ Branch(miss, ne, scratch1, Operand(scratch0));
     77 }
     78 
     79 
     80 // Helper function used from LoadIC GenerateNormal.
     81 //
     82 // elements: Property dictionary. It is not clobbered if a jump to the miss
     83 //           label is done.
     84 // name:     Property name. It is not clobbered if a jump to the miss label is
     85 //           done
     86 // result:   Register for the result. It is only updated if a jump to the miss
     87 //           label is not done. Can be the same as elements or name clobbering
     88 //           one of these in the case of not jumping to the miss label.
     89 // The two scratch registers need to be different from elements, name and
     90 // result.
     91 // The generated code assumes that the receiver has slow properties,
     92 // is not a global object and does not have interceptors.
     93 // The address returned from GenerateStringDictionaryProbes() in scratch2
     94 // is used.
     95 static void GenerateDictionaryLoad(MacroAssembler* masm,
     96                                    Label* miss,
     97                                    Register elements,
     98                                    Register name,
     99                                    Register result,
    100                                    Register scratch1,
    101                                    Register scratch2) {
    102   // Main use of the scratch registers.
    103   // scratch1: Used as temporary and to hold the capacity of the property
    104   //           dictionary.
    105   // scratch2: Used as temporary.
    106   Label done;
    107 
    108   // Probe the dictionary.
    109   NameDictionaryLookupStub::GeneratePositiveLookup(masm,
    110                                                    miss,
    111                                                    &done,
    112                                                    elements,
    113                                                    name,
    114                                                    scratch1,
    115                                                    scratch2);
    116 
    117   // If probing finds an entry check that the value is a normal
    118   // property.
    119   __ bind(&done);  // scratch2 == elements + 4 * index.
    120   const int kElementsStartOffset = NameDictionary::kHeaderSize +
    121       NameDictionary::kElementsStartIndex * kPointerSize;
    122   const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
    123   __ lw(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
    124   __ And(at,
    125          scratch1,
    126          Operand(PropertyDetails::TypeField::kMask << kSmiTagSize));
    127   __ Branch(miss, ne, at, Operand(zero_reg));
    128 
    129   // Get the value at the masked, scaled index and return.
    130   __ lw(result,
    131         FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
    132 }
    133 
    134 
    135 // Helper function used from StoreIC::GenerateNormal.
    136 //
    137 // elements: Property dictionary. It is not clobbered if a jump to the miss
    138 //           label is done.
    139 // name:     Property name. It is not clobbered if a jump to the miss label is
    140 //           done
    141 // value:    The value to store.
    142 // The two scratch registers need to be different from elements, name and
    143 // result.
    144 // The generated code assumes that the receiver has slow properties,
    145 // is not a global object and does not have interceptors.
    146 // The address returned from GenerateStringDictionaryProbes() in scratch2
    147 // is used.
    148 static void GenerateDictionaryStore(MacroAssembler* masm,
    149                                     Label* miss,
    150                                     Register elements,
    151                                     Register name,
    152                                     Register value,
    153                                     Register scratch1,
    154                                     Register scratch2) {
    155   // Main use of the scratch registers.
    156   // scratch1: Used as temporary and to hold the capacity of the property
    157   //           dictionary.
    158   // scratch2: Used as temporary.
    159   Label done;
    160 
    161   // Probe the dictionary.
    162   NameDictionaryLookupStub::GeneratePositiveLookup(masm,
    163                                                    miss,
    164                                                    &done,
    165                                                    elements,
    166                                                    name,
    167                                                    scratch1,
    168                                                    scratch2);
    169 
    170   // If probing finds an entry in the dictionary check that the value
    171   // is a normal property that is not read only.
    172   __ bind(&done);  // scratch2 == elements + 4 * index.
    173   const int kElementsStartOffset = NameDictionary::kHeaderSize +
    174       NameDictionary::kElementsStartIndex * kPointerSize;
    175   const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
    176   const int kTypeAndReadOnlyMask =
    177       (PropertyDetails::TypeField::kMask |
    178        PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
    179   __ lw(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
    180   __ And(at, scratch1, Operand(kTypeAndReadOnlyMask));
    181   __ Branch(miss, ne, at, Operand(zero_reg));
    182 
    183   // Store the value at the masked, scaled index and return.
    184   const int kValueOffset = kElementsStartOffset + kPointerSize;
    185   __ Addu(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag));
    186   __ sw(value, MemOperand(scratch2));
    187 
    188   // Update the write barrier. Make sure not to clobber the value.
    189   __ mov(scratch1, value);
    190   __ RecordWrite(
    191       elements, scratch2, scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs);
    192 }
    193 
    194 
    195 // Checks the receiver for special cases (value type, slow case bits).
    196 // Falls through for regular JS object.
    197 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
    198                                            Register receiver,
    199                                            Register map,
    200                                            Register scratch,
    201                                            int interceptor_bit,
    202                                            Label* slow) {
    203   // Check that the object isn't a smi.
    204   __ JumpIfSmi(receiver, slow);
    205   // Get the map of the receiver.
    206   __ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
    207   // Check bit field.
    208   __ lbu(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
    209   __ And(at, scratch,
    210          Operand((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)));
    211   __ Branch(slow, ne, at, Operand(zero_reg));
    212   // Check that the object is some kind of JS object EXCEPT JS Value type.
    213   // In the case that the object is a value-wrapper object,
    214   // we enter the runtime system to make sure that indexing into string
    215   // objects work as intended.
    216   ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
    217   __ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
    218   __ Branch(slow, lt, scratch, Operand(JS_OBJECT_TYPE));
    219 }
    220 
    221 
    222 // Loads an indexed element from a fast case array.
    223 // If not_fast_array is NULL, doesn't perform the elements map check.
    224 static void GenerateFastArrayLoad(MacroAssembler* masm,
    225                                   Register receiver,
    226                                   Register key,
    227                                   Register elements,
    228                                   Register scratch1,
    229                                   Register scratch2,
    230                                   Register result,
    231                                   Label* not_fast_array,
    232                                   Label* out_of_range) {
    233   // Register use:
    234   //
    235   // receiver - holds the receiver on entry.
    236   //            Unchanged unless 'result' is the same register.
    237   //
    238   // key      - holds the smi key on entry.
    239   //            Unchanged unless 'result' is the same register.
    240   //
    241   // elements - holds the elements of the receiver on exit.
    242   //
    243   // result   - holds the result on exit if the load succeeded.
    244   //            Allowed to be the the same as 'receiver' or 'key'.
    245   //            Unchanged on bailout so 'receiver' and 'key' can be safely
    246   //            used by further computation.
    247   //
    248   // Scratch registers:
    249   //
    250   // scratch1 - used to hold elements map and elements length.
    251   //            Holds the elements map if not_fast_array branch is taken.
    252   //
    253   // scratch2 - used to hold the loaded value.
    254 
    255   __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
    256   if (not_fast_array != NULL) {
    257     // Check that the object is in fast mode (not dictionary).
    258     __ lw(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
    259     __ LoadRoot(at, Heap::kFixedArrayMapRootIndex);
    260     __ Branch(not_fast_array, ne, scratch1, Operand(at));
    261   } else {
    262     __ AssertFastElements(elements);
    263   }
    264 
    265   // Check that the key (index) is within bounds.
    266   __ lw(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset));
    267   __ Branch(out_of_range, hs, key, Operand(scratch1));
    268 
    269   // Fast case: Do the load.
    270   __ Addu(scratch1, elements,
    271           Operand(FixedArray::kHeaderSize - kHeapObjectTag));
    272   // The key is a smi.
    273   STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
    274   __ sll(at, key, kPointerSizeLog2 - kSmiTagSize);
    275   __ addu(at, at, scratch1);
    276   __ lw(scratch2, MemOperand(at));
    277 
    278   __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
    279   // In case the loaded value is the_hole we have to consult GetProperty
    280   // to ensure the prototype chain is searched.
    281   __ Branch(out_of_range, eq, scratch2, Operand(at));
    282   __ mov(result, scratch2);
    283 }
    284 
    285 
    286 // Checks whether a key is an array index string or a unique name.
    287 // Falls through if a key is a unique name.
    288 static void GenerateKeyNameCheck(MacroAssembler* masm,
    289                                  Register key,
    290                                  Register map,
    291                                  Register hash,
    292                                  Label* index_string,
    293                                  Label* not_unique) {
    294   // The key is not a smi.
    295   Label unique;
    296   // Is it a name?
    297   __ GetObjectType(key, map, hash);
    298   __ Branch(not_unique, hi, hash, Operand(LAST_UNIQUE_NAME_TYPE));
    299   STATIC_ASSERT(LAST_UNIQUE_NAME_TYPE == FIRST_NONSTRING_TYPE);
    300   __ Branch(&unique, eq, hash, Operand(LAST_UNIQUE_NAME_TYPE));
    301 
    302   // Is the string an array index, with cached numeric value?
    303   __ lw(hash, FieldMemOperand(key, Name::kHashFieldOffset));
    304   __ And(at, hash, Operand(Name::kContainsCachedArrayIndexMask));
    305   __ Branch(index_string, eq, at, Operand(zero_reg));
    306 
    307   // Is the string internalized? We know it's a string, so a single
    308   // bit test is enough.
    309   // map: key map
    310   __ lbu(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
    311   STATIC_ASSERT(kInternalizedTag == 0);
    312   __ And(at, hash, Operand(kIsNotInternalizedMask));
    313   __ Branch(not_unique, ne, at, Operand(zero_reg));
    314 
    315   __ bind(&unique);
    316 }
    317 
    318 
    319 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
    320   // ----------- S t a t e -------------
    321   //  -- a2    : name
    322   //  -- ra    : return address
    323   //  -- a0    : receiver
    324   // -----------------------------------
    325 
    326   // Probe the stub cache.
    327   Code::Flags flags = Code::ComputeHandlerFlags(Code::LOAD_IC);
    328   masm->isolate()->stub_cache()->GenerateProbe(
    329       masm, flags, a0, a2, a3, t0, t1, t2);
    330 
    331   // Cache miss: Jump to runtime.
    332   GenerateMiss(masm);
    333 }
    334 
    335 
    336 void LoadIC::GenerateNormal(MacroAssembler* masm) {
    337   // ----------- S t a t e -------------
    338   //  -- a2    : name
    339   //  -- lr    : return address
    340   //  -- a0    : receiver
    341   // -----------------------------------
    342   Label miss, slow;
    343 
    344   GenerateNameDictionaryReceiverCheck(masm, a0, a1, a3, t0, &miss);
    345 
    346   // a1: elements
    347   GenerateDictionaryLoad(masm, &slow, a1, a2, v0, a3, t0);
    348   __ Ret();
    349 
    350   // Dictionary load failed, go slow (but don't miss).
    351   __ bind(&slow);
    352   GenerateRuntimeGetProperty(masm);
    353 
    354   // Cache miss: Jump to runtime.
    355   __ bind(&miss);
    356   GenerateMiss(masm);
    357 }
    358 
    359 
    360 void LoadIC::GenerateMiss(MacroAssembler* masm) {
    361   // ----------- S t a t e -------------
    362   //  -- a2    : name
    363   //  -- ra    : return address
    364   //  -- a0    : receiver
    365   // -----------------------------------
    366   Isolate* isolate = masm->isolate();
    367 
    368   __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, a3, t0);
    369 
    370   __ mov(a3, a0);
    371   __ Push(a3, a2);
    372 
    373   // Perform tail call to the entry.
    374   ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss), isolate);
    375   __ TailCallExternalReference(ref, 2, 1);
    376 }
    377 
    378 
    379 void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
    380   // ---------- S t a t e --------------
    381   //  -- a2    : name
    382   //  -- ra    : return address
    383   //  -- a0    : receiver
    384   // -----------------------------------
    385 
    386   __ mov(a3, a0);
    387   __ Push(a3, a2);
    388 
    389   __ TailCallRuntime(Runtime::kGetProperty, 2, 1);
    390 }
    391 
    392 
    393 static MemOperand GenerateMappedArgumentsLookup(MacroAssembler* masm,
    394                                                 Register object,
    395                                                 Register key,
    396                                                 Register scratch1,
    397                                                 Register scratch2,
    398                                                 Register scratch3,
    399                                                 Label* unmapped_case,
    400                                                 Label* slow_case) {
    401   Heap* heap = masm->isolate()->heap();
    402 
    403   // Check that the receiver is a JSObject. Because of the map check
    404   // later, we do not need to check for interceptors or whether it
    405   // requires access checks.
    406   __ JumpIfSmi(object, slow_case);
    407   // Check that the object is some kind of JSObject.
    408   __ GetObjectType(object, scratch1, scratch2);
    409   __ Branch(slow_case, lt, scratch2, Operand(FIRST_JS_RECEIVER_TYPE));
    410 
    411   // Check that the key is a positive smi.
    412   __ And(scratch1, key, Operand(0x80000001));
    413   __ Branch(slow_case, ne, scratch1, Operand(zero_reg));
    414 
    415   // Load the elements into scratch1 and check its map.
    416   Handle<Map> arguments_map(heap->sloppy_arguments_elements_map());
    417   __ lw(scratch1, FieldMemOperand(object, JSObject::kElementsOffset));
    418   __ CheckMap(scratch1,
    419               scratch2,
    420               arguments_map,
    421               slow_case,
    422               DONT_DO_SMI_CHECK);
    423   // Check if element is in the range of mapped arguments. If not, jump
    424   // to the unmapped lookup with the parameter map in scratch1.
    425   __ lw(scratch2, FieldMemOperand(scratch1, FixedArray::kLengthOffset));
    426   __ Subu(scratch2, scratch2, Operand(Smi::FromInt(2)));
    427   __ Branch(unmapped_case, Ugreater_equal, key, Operand(scratch2));
    428 
    429   // Load element index and check whether it is the hole.
    430   const int kOffset =
    431       FixedArray::kHeaderSize + 2 * kPointerSize - kHeapObjectTag;
    432 
    433   __ li(scratch3, Operand(kPointerSize >> 1));
    434   __ Mul(scratch3, key, scratch3);
    435   __ Addu(scratch3, scratch3, Operand(kOffset));
    436 
    437   __ Addu(scratch2, scratch1, scratch3);
    438   __ lw(scratch2, MemOperand(scratch2));
    439   __ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex);
    440   __ Branch(unmapped_case, eq, scratch2, Operand(scratch3));
    441 
    442   // Load value from context and return it. We can reuse scratch1 because
    443   // we do not jump to the unmapped lookup (which requires the parameter
    444   // map in scratch1).
    445   __ lw(scratch1, FieldMemOperand(scratch1, FixedArray::kHeaderSize));
    446   __ li(scratch3, Operand(kPointerSize >> 1));
    447   __ Mul(scratch3, scratch2, scratch3);
    448   __ Addu(scratch3, scratch3, Operand(Context::kHeaderSize - kHeapObjectTag));
    449   __ Addu(scratch2, scratch1, scratch3);
    450   return MemOperand(scratch2);
    451 }
    452 
    453 
    454 static MemOperand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
    455                                                   Register key,
    456                                                   Register parameter_map,
    457                                                   Register scratch,
    458                                                   Label* slow_case) {
    459   // Element is in arguments backing store, which is referenced by the
    460   // second element of the parameter_map. The parameter_map register
    461   // must be loaded with the parameter map of the arguments object and is
    462   // overwritten.
    463   const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
    464   Register backing_store = parameter_map;
    465   __ lw(backing_store, FieldMemOperand(parameter_map, kBackingStoreOffset));
    466   __ CheckMap(backing_store,
    467               scratch,
    468               Heap::kFixedArrayMapRootIndex,
    469               slow_case,
    470               DONT_DO_SMI_CHECK);
    471   __ lw(scratch, FieldMemOperand(backing_store, FixedArray::kLengthOffset));
    472   __ Branch(slow_case, Ugreater_equal, key, Operand(scratch));
    473   __ li(scratch, Operand(kPointerSize >> 1));
    474   __ Mul(scratch, key, scratch);
    475   __ Addu(scratch,
    476           scratch,
    477           Operand(FixedArray::kHeaderSize - kHeapObjectTag));
    478   __ Addu(scratch, backing_store, scratch);
    479   return MemOperand(scratch);
    480 }
    481 
    482 
    483 void KeyedLoadIC::GenerateSloppyArguments(MacroAssembler* masm) {
    484   // ---------- S t a t e --------------
    485   //  -- lr     : return address
    486   //  -- a0     : key
    487   //  -- a1     : receiver
    488   // -----------------------------------
    489   Label slow, notin;
    490   MemOperand mapped_location =
    491       GenerateMappedArgumentsLookup(masm, a1, a0, a2, a3, t0, &notin, &slow);
    492   __ Ret(USE_DELAY_SLOT);
    493   __ lw(v0, mapped_location);
    494   __ bind(&notin);
    495   // The unmapped lookup expects that the parameter map is in a2.
    496   MemOperand unmapped_location =
    497       GenerateUnmappedArgumentsLookup(masm, a0, a2, a3, &slow);
    498   __ lw(a2, unmapped_location);
    499   __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
    500   __ Branch(&slow, eq, a2, Operand(a3));
    501   __ Ret(USE_DELAY_SLOT);
    502   __ mov(v0, a2);
    503   __ bind(&slow);
    504   GenerateMiss(masm);
    505 }
    506 
    507 
    508 void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) {
    509   // ---------- S t a t e --------------
    510   //  -- a0     : value
    511   //  -- a1     : key
    512   //  -- a2     : receiver
    513   //  -- lr     : return address
    514   // -----------------------------------
    515   Label slow, notin;
    516   // Store address is returned in register (of MemOperand) mapped_location.
    517   MemOperand mapped_location =
    518       GenerateMappedArgumentsLookup(masm, a2, a1, a3, t0, t1, &notin, &slow);
    519   __ sw(a0, mapped_location);
    520   __ mov(t5, a0);
    521   ASSERT_EQ(mapped_location.offset(), 0);
    522   __ RecordWrite(a3, mapped_location.rm(), t5,
    523                  kRAHasNotBeenSaved, kDontSaveFPRegs);
    524   __ Ret(USE_DELAY_SLOT);
    525   __ mov(v0, a0);  // (In delay slot) return the value stored in v0.
    526   __ bind(&notin);
    527   // The unmapped lookup expects that the parameter map is in a3.
    528   // Store address is returned in register (of MemOperand) unmapped_location.
    529   MemOperand unmapped_location =
    530       GenerateUnmappedArgumentsLookup(masm, a1, a3, t0, &slow);
    531   __ sw(a0, unmapped_location);
    532   __ mov(t5, a0);
    533   ASSERT_EQ(unmapped_location.offset(), 0);
    534   __ RecordWrite(a3, unmapped_location.rm(), t5,
    535                  kRAHasNotBeenSaved, kDontSaveFPRegs);
    536   __ Ret(USE_DELAY_SLOT);
    537   __ mov(v0, a0);  // (In delay slot) return the value stored in v0.
    538   __ bind(&slow);
    539   GenerateMiss(masm);
    540 }
    541 
    542 
    543 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
    544   // ---------- S t a t e --------------
    545   //  -- ra     : return address
    546   //  -- a0     : key
    547   //  -- a1     : receiver
    548   // -----------------------------------
    549   Isolate* isolate = masm->isolate();
    550 
    551   __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, a3, t0);
    552 
    553   __ Push(a1, a0);
    554 
    555   // Perform tail call to the entry.
    556   ExternalReference ref =
    557       ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
    558 
    559   __ TailCallExternalReference(ref, 2, 1);
    560 }
    561 
    562 
    563 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
    564   // ---------- S t a t e --------------
    565   //  -- ra     : return address
    566   //  -- a0     : key
    567   //  -- a1     : receiver
    568   // -----------------------------------
    569 
    570   __ Push(a1, a0);
    571 
    572   __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
    573 }
    574 
    575 
    576 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
    577   // ---------- S t a t e --------------
    578   //  -- ra     : return address
    579   //  -- a0     : key
    580   //  -- a1     : receiver
    581   // -----------------------------------
    582   Label slow, check_name, index_smi, index_name, property_array_property;
    583   Label probe_dictionary, check_number_dictionary;
    584 
    585   Register key = a0;
    586   Register receiver = a1;
    587 
    588   Isolate* isolate = masm->isolate();
    589 
    590   // Check that the key is a smi.
    591   __ JumpIfNotSmi(key, &check_name);
    592   __ bind(&index_smi);
    593   // Now the key is known to be a smi. This place is also jumped to from below
    594   // where a numeric string is converted to a smi.
    595 
    596   GenerateKeyedLoadReceiverCheck(
    597       masm, receiver, a2, a3, Map::kHasIndexedInterceptor, &slow);
    598 
    599   // Check the receiver's map to see if it has fast elements.
    600   __ CheckFastElements(a2, a3, &check_number_dictionary);
    601 
    602   GenerateFastArrayLoad(
    603       masm, receiver, key, t0, a3, a2, v0, NULL, &slow);
    604 
    605   __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, a2, a3);
    606   __ Ret();
    607 
    608   __ bind(&check_number_dictionary);
    609   __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
    610   __ lw(a3, FieldMemOperand(t0, JSObject::kMapOffset));
    611 
    612   // Check whether the elements is a number dictionary.
    613   // a0: key
    614   // a3: elements map
    615   // t0: elements
    616   __ LoadRoot(at, Heap::kHashTableMapRootIndex);
    617   __ Branch(&slow, ne, a3, Operand(at));
    618   __ sra(a2, a0, kSmiTagSize);
    619   __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
    620   __ Ret();
    621 
    622   // Slow case, key and receiver still in a0 and a1.
    623   __ bind(&slow);
    624   __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(),
    625                       1,
    626                       a2,
    627                       a3);
    628   GenerateRuntimeGetProperty(masm);
    629 
    630   __ bind(&check_name);
    631   GenerateKeyNameCheck(masm, key, a2, a3, &index_name, &slow);
    632 
    633   GenerateKeyedLoadReceiverCheck(
    634        masm, receiver, a2, a3, Map::kHasNamedInterceptor, &slow);
    635 
    636 
    637   // If the receiver is a fast-case object, check the keyed lookup
    638   // cache. Otherwise probe the dictionary.
    639   __ lw(a3, FieldMemOperand(a1, JSObject::kPropertiesOffset));
    640   __ lw(t0, FieldMemOperand(a3, HeapObject::kMapOffset));
    641   __ LoadRoot(at, Heap::kHashTableMapRootIndex);
    642   __ Branch(&probe_dictionary, eq, t0, Operand(at));
    643 
    644   // Load the map of the receiver, compute the keyed lookup cache hash
    645   // based on 32 bits of the map pointer and the name hash.
    646   __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
    647   __ sra(a3, a2, KeyedLookupCache::kMapHashShift);
    648   __ lw(t0, FieldMemOperand(a0, Name::kHashFieldOffset));
    649   __ sra(at, t0, Name::kHashShift);
    650   __ xor_(a3, a3, at);
    651   int mask = KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask;
    652   __ And(a3, a3, Operand(mask));
    653 
    654   // Load the key (consisting of map and unique name) from the cache and
    655   // check for match.
    656   Label load_in_object_property;
    657   static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
    658   Label hit_on_nth_entry[kEntriesPerBucket];
    659   ExternalReference cache_keys =
    660       ExternalReference::keyed_lookup_cache_keys(isolate);
    661   __ li(t0, Operand(cache_keys));
    662   __ sll(at, a3, kPointerSizeLog2 + 1);
    663   __ addu(t0, t0, at);
    664 
    665   for (int i = 0; i < kEntriesPerBucket - 1; i++) {
    666     Label try_next_entry;
    667     __ lw(t1, MemOperand(t0, kPointerSize * i * 2));
    668     __ Branch(&try_next_entry, ne, a2, Operand(t1));
    669     __ lw(t1, MemOperand(t0, kPointerSize * (i * 2 + 1)));
    670     __ Branch(&hit_on_nth_entry[i], eq, a0, Operand(t1));
    671     __ bind(&try_next_entry);
    672   }
    673 
    674   __ lw(t1, MemOperand(t0, kPointerSize * (kEntriesPerBucket - 1) * 2));
    675   __ Branch(&slow, ne, a2, Operand(t1));
    676   __ lw(t1, MemOperand(t0, kPointerSize * ((kEntriesPerBucket - 1) * 2 + 1)));
    677   __ Branch(&slow, ne, a0, Operand(t1));
    678 
    679   // Get field offset.
    680   // a0     : key
    681   // a1     : receiver
    682   // a2     : receiver's map
    683   // a3     : lookup cache index
    684   ExternalReference cache_field_offsets =
    685       ExternalReference::keyed_lookup_cache_field_offsets(isolate);
    686 
    687   // Hit on nth entry.
    688   for (int i = kEntriesPerBucket - 1; i >= 0; i--) {
    689     __ bind(&hit_on_nth_entry[i]);
    690     __ li(t0, Operand(cache_field_offsets));
    691     __ sll(at, a3, kPointerSizeLog2);
    692     __ addu(at, t0, at);
    693     __ lw(t1, MemOperand(at, kPointerSize * i));
    694     __ lbu(t2, FieldMemOperand(a2, Map::kInObjectPropertiesOffset));
    695     __ Subu(t1, t1, t2);
    696     __ Branch(&property_array_property, ge, t1, Operand(zero_reg));
    697     if (i != 0) {
    698       __ Branch(&load_in_object_property);
    699     }
    700   }
    701 
    702   // Load in-object property.
    703   __ bind(&load_in_object_property);
    704   __ lbu(t2, FieldMemOperand(a2, Map::kInstanceSizeOffset));
    705   __ addu(t2, t2, t1);  // Index from start of object.
    706   __ Subu(a1, a1, Operand(kHeapObjectTag));  // Remove the heap tag.
    707   __ sll(at, t2, kPointerSizeLog2);
    708   __ addu(at, a1, at);
    709   __ lw(v0, MemOperand(at));
    710   __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
    711                       1,
    712                       a2,
    713                       a3);
    714   __ Ret();
    715 
    716   // Load property array property.
    717   __ bind(&property_array_property);
    718   __ lw(a1, FieldMemOperand(a1, JSObject::kPropertiesOffset));
    719   __ Addu(a1, a1, FixedArray::kHeaderSize - kHeapObjectTag);
    720   __ sll(t0, t1, kPointerSizeLog2);
    721   __ Addu(t0, t0, a1);
    722   __ lw(v0, MemOperand(t0));
    723   __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
    724                       1,
    725                       a2,
    726                       a3);
    727   __ Ret();
    728 
    729 
    730   // Do a quick inline probe of the receiver's dictionary, if it
    731   // exists.
    732   __ bind(&probe_dictionary);
    733   // a1: receiver
    734   // a0: key
    735   // a3: elements
    736   __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
    737   __ lbu(a2, FieldMemOperand(a2, Map::kInstanceTypeOffset));
    738   GenerateGlobalInstanceTypeCheck(masm, a2, &slow);
    739   // Load the property to v0.
    740   GenerateDictionaryLoad(masm, &slow, a3, a0, v0, a2, t0);
    741   __ IncrementCounter(isolate->counters()->keyed_load_generic_symbol(),
    742                       1,
    743                       a2,
    744                       a3);
    745   __ Ret();
    746 
    747   __ bind(&index_name);
    748   __ IndexFromHash(a3, key);
    749   // Now jump to the place where smi keys are handled.
    750   __ Branch(&index_smi);
    751 }
    752 
    753 
    754 void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
    755   // ---------- S t a t e --------------
    756   //  -- ra     : return address
    757   //  -- a0     : key (index)
    758   //  -- a1     : receiver
    759   // -----------------------------------
    760   Label miss;
    761 
    762   Register receiver = a1;
    763   Register index = a0;
    764   Register scratch = a3;
    765   Register result = v0;
    766 
    767   StringCharAtGenerator char_at_generator(receiver,
    768                                           index,
    769                                           scratch,
    770                                           result,
    771                                           &miss,  // When not a string.
    772                                           &miss,  // When not a number.
    773                                           &miss,  // When index out of range.
    774                                           STRING_INDEX_IS_ARRAY_INDEX);
    775   char_at_generator.GenerateFast(masm);
    776   __ Ret();
    777 
    778   StubRuntimeCallHelper call_helper;
    779   char_at_generator.GenerateSlow(masm, call_helper);
    780 
    781   __ bind(&miss);
    782   GenerateMiss(masm);
    783 }
    784 
    785 
    786 void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
    787                                               StrictMode strict_mode) {
    788   // ---------- S t a t e --------------
    789   //  -- a0     : value
    790   //  -- a1     : key
    791   //  -- a2     : receiver
    792   //  -- ra     : return address
    793   // -----------------------------------
    794 
    795   // Push receiver, key and value for runtime call.
    796   __ Push(a2, a1, a0);
    797   __ li(a1, Operand(Smi::FromInt(NONE)));          // PropertyAttributes.
    798   __ li(a0, Operand(Smi::FromInt(strict_mode)));   // Strict mode.
    799   __ Push(a1, a0);
    800 
    801   __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
    802 }
    803 
    804 
    805 static void KeyedStoreGenerateGenericHelper(
    806     MacroAssembler* masm,
    807     Label* fast_object,
    808     Label* fast_double,
    809     Label* slow,
    810     KeyedStoreCheckMap check_map,
    811     KeyedStoreIncrementLength increment_length,
    812     Register value,
    813     Register key,
    814     Register receiver,
    815     Register receiver_map,
    816     Register elements_map,
    817     Register elements) {
    818   Label transition_smi_elements;
    819   Label finish_object_store, non_double_value, transition_double_elements;
    820   Label fast_double_without_map_check;
    821 
    822   // Fast case: Do the store, could be either Object or double.
    823   __ bind(fast_object);
    824   Register scratch_value = t0;
    825   Register address = t1;
    826   if (check_map == kCheckMap) {
    827     __ lw(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
    828     __ Branch(fast_double, ne, elements_map,
    829               Operand(masm->isolate()->factory()->fixed_array_map()));
    830   }
    831 
    832   // HOLECHECK: guards "A[i] = V"
    833   // We have to go to the runtime if the current value is the hole because
    834   // there may be a callback on the element.
    835   Label holecheck_passed1;
    836   __ Addu(address, elements, FixedArray::kHeaderSize - kHeapObjectTag);
    837   __ sll(at, key, kPointerSizeLog2 - kSmiTagSize);
    838   __ addu(address, address, at);
    839   __ lw(scratch_value, MemOperand(address));
    840   __ Branch(&holecheck_passed1, ne, scratch_value,
    841             Operand(masm->isolate()->factory()->the_hole_value()));
    842   __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch_value,
    843                                       slow);
    844 
    845   __ bind(&holecheck_passed1);
    846 
    847   // Smi stores don't require further checks.
    848   Label non_smi_value;
    849   __ JumpIfNotSmi(value, &non_smi_value);
    850 
    851   if (increment_length == kIncrementLength) {
    852     // Add 1 to receiver->length.
    853     __ Addu(scratch_value, key, Operand(Smi::FromInt(1)));
    854     __ sw(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset));
    855   }
    856   // It's irrelevant whether array is smi-only or not when writing a smi.
    857   __ Addu(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
    858   __ sll(scratch_value, key, kPointerSizeLog2 - kSmiTagSize);
    859   __ Addu(address, address, scratch_value);
    860   __ sw(value, MemOperand(address));
    861   __ Ret();
    862 
    863   __ bind(&non_smi_value);
    864   // Escape to elements kind transition case.
    865   __ CheckFastObjectElements(receiver_map, scratch_value,
    866                              &transition_smi_elements);
    867 
    868   // Fast elements array, store the value to the elements backing store.
    869   __ bind(&finish_object_store);
    870   if (increment_length == kIncrementLength) {
    871     // Add 1 to receiver->length.
    872     __ Addu(scratch_value, key, Operand(Smi::FromInt(1)));
    873     __ sw(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset));
    874   }
    875   __ Addu(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
    876   __ sll(scratch_value, key, kPointerSizeLog2 - kSmiTagSize);
    877   __ Addu(address, address, scratch_value);
    878   __ sw(value, MemOperand(address));
    879   // Update write barrier for the elements array address.
    880   __ mov(scratch_value, value);  // Preserve the value which is returned.
    881   __ RecordWrite(elements,
    882                  address,
    883                  scratch_value,
    884                  kRAHasNotBeenSaved,
    885                  kDontSaveFPRegs,
    886                  EMIT_REMEMBERED_SET,
    887                  OMIT_SMI_CHECK);
    888   __ Ret();
    889 
    890   __ bind(fast_double);
    891   if (check_map == kCheckMap) {
    892     // Check for fast double array case. If this fails, call through to the
    893     // runtime.
    894     __ LoadRoot(at, Heap::kFixedDoubleArrayMapRootIndex);
    895     __ Branch(slow, ne, elements_map, Operand(at));
    896   }
    897 
    898   // HOLECHECK: guards "A[i] double hole?"
    899   // We have to see if the double version of the hole is present. If so
    900   // go to the runtime.
    901   __ Addu(address, elements,
    902           Operand(FixedDoubleArray::kHeaderSize + kHoleNanUpper32Offset
    903                   - kHeapObjectTag));
    904   __ sll(at, key, kPointerSizeLog2);
    905   __ addu(address, address, at);
    906   __ lw(scratch_value, MemOperand(address));
    907   __ Branch(&fast_double_without_map_check, ne, scratch_value,
    908             Operand(kHoleNanUpper32));
    909   __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch_value,
    910                                       slow);
    911 
    912   __ bind(&fast_double_without_map_check);
    913   __ StoreNumberToDoubleElements(value,
    914                                  key,
    915                                  elements,  // Overwritten.
    916                                  a3,        // Scratch regs...
    917                                  t0,
    918                                  t1,
    919                                  &transition_double_elements);
    920   if (increment_length == kIncrementLength) {
    921     // Add 1 to receiver->length.
    922     __ Addu(scratch_value, key, Operand(Smi::FromInt(1)));
    923     __ sw(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset));
    924   }
    925   __ Ret();
    926 
    927   __ bind(&transition_smi_elements);
    928   // Transition the array appropriately depending on the value type.
    929   __ lw(t0, FieldMemOperand(value, HeapObject::kMapOffset));
    930   __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
    931   __ Branch(&non_double_value, ne, t0, Operand(at));
    932 
    933   // Value is a double. Transition FAST_SMI_ELEMENTS ->
    934   // FAST_DOUBLE_ELEMENTS and complete the store.
    935   __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
    936                                          FAST_DOUBLE_ELEMENTS,
    937                                          receiver_map,
    938                                          t0,
    939                                          slow);
    940   ASSERT(receiver_map.is(a3));  // Transition code expects map in a3
    941   AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS,
    942                                                     FAST_DOUBLE_ELEMENTS);
    943   ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, slow);
    944   __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
    945   __ jmp(&fast_double_without_map_check);
    946 
    947   __ bind(&non_double_value);
    948   // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
    949   __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
    950                                          FAST_ELEMENTS,
    951                                          receiver_map,
    952                                          t0,
    953                                          slow);
    954   ASSERT(receiver_map.is(a3));  // Transition code expects map in a3
    955   mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
    956   ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm, mode,
    957                                                                    slow);
    958   __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
    959   __ jmp(&finish_object_store);
    960 
    961   __ bind(&transition_double_elements);
    962   // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
    963   // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
    964   // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
    965   __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
    966                                          FAST_ELEMENTS,
    967                                          receiver_map,
    968                                          t0,
    969                                          slow);
    970   ASSERT(receiver_map.is(a3));  // Transition code expects map in a3
    971   mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
    972   ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, slow);
    973   __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
    974   __ jmp(&finish_object_store);
    975 }
    976 
    977 
    978 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
    979                                    StrictMode strict_mode) {
    980   // ---------- S t a t e --------------
    981   //  -- a0     : value
    982   //  -- a1     : key
    983   //  -- a2     : receiver
    984   //  -- ra     : return address
    985   // -----------------------------------
    986   Label slow, fast_object, fast_object_grow;
    987   Label fast_double, fast_double_grow;
    988   Label array, extra, check_if_double_array;
    989 
    990   // Register usage.
    991   Register value = a0;
    992   Register key = a1;
    993   Register receiver = a2;
    994   Register receiver_map = a3;
    995   Register elements_map = t2;
    996   Register elements = t3;  // Elements array of the receiver.
    997   // t0 and t1 are used as general scratch registers.
    998 
    999   // Check that the key is a smi.
   1000   __ JumpIfNotSmi(key, &slow);
   1001   // Check that the object isn't a smi.
   1002   __ JumpIfSmi(receiver, &slow);
   1003   // Get the map of the object.
   1004   __ lw(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
   1005   // Check that the receiver does not require access checks and is not observed.
   1006   // The generic stub does not perform map checks or handle observed objects.
   1007   __ lbu(t0, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
   1008   __ And(t0, t0, Operand(1 << Map::kIsAccessCheckNeeded |
   1009                          1 << Map::kIsObserved));
   1010   __ Branch(&slow, ne, t0, Operand(zero_reg));
   1011   // Check if the object is a JS array or not.
   1012   __ lbu(t0, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset));
   1013   __ Branch(&array, eq, t0, Operand(JS_ARRAY_TYPE));
   1014   // Check that the object is some kind of JSObject.
   1015   __ Branch(&slow, lt, t0, Operand(FIRST_JS_OBJECT_TYPE));
   1016 
   1017   // Object case: Check key against length in the elements array.
   1018   __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
   1019   // Check array bounds. Both the key and the length of FixedArray are smis.
   1020   __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
   1021   __ Branch(&fast_object, lo, key, Operand(t0));
   1022 
   1023   // Slow case, handle jump to runtime.
   1024   __ bind(&slow);
   1025   // Entry registers are intact.
   1026   // a0: value.
   1027   // a1: key.
   1028   // a2: receiver.
   1029   GenerateRuntimeSetProperty(masm, strict_mode);
   1030 
   1031   // Extra capacity case: Check if there is extra capacity to
   1032   // perform the store and update the length. Used for adding one
   1033   // element to the array by writing to array[array.length].
   1034   __ bind(&extra);
   1035   // Condition code from comparing key and array length is still available.
   1036   // Only support writing to array[array.length].
   1037   __ Branch(&slow, ne, key, Operand(t0));
   1038   // Check for room in the elements backing store.
   1039   // Both the key and the length of FixedArray are smis.
   1040   __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
   1041   __ Branch(&slow, hs, key, Operand(t0));
   1042   __ lw(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
   1043   __ Branch(
   1044       &check_if_double_array, ne, elements_map, Heap::kFixedArrayMapRootIndex);
   1045 
   1046   __ jmp(&fast_object_grow);
   1047 
   1048   __ bind(&check_if_double_array);
   1049   __ Branch(&slow, ne, elements_map, Heap::kFixedDoubleArrayMapRootIndex);
   1050   __ jmp(&fast_double_grow);
   1051 
   1052   // Array case: Get the length and the elements array from the JS
   1053   // array. Check that the array is in fast mode (and writable); if it
   1054   // is the length is always a smi.
   1055   __ bind(&array);
   1056   __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
   1057 
   1058   // Check the key against the length in the array.
   1059   __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
   1060   __ Branch(&extra, hs, key, Operand(t0));
   1061 
   1062   KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double,
   1063                                   &slow, kCheckMap, kDontIncrementLength,
   1064                                   value, key, receiver, receiver_map,
   1065                                   elements_map, elements);
   1066   KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
   1067                                   &slow, kDontCheckMap, kIncrementLength,
   1068                                   value, key, receiver, receiver_map,
   1069                                   elements_map, elements);
   1070 }
   1071 
   1072 
   1073 void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
   1074   // ---------- S t a t e --------------
   1075   //  -- ra     : return address
   1076   //  -- a0     : key
   1077   //  -- a1     : receiver
   1078   // -----------------------------------
   1079   Label slow;
   1080 
   1081   // Check that the receiver isn't a smi.
   1082   __ JumpIfSmi(a1, &slow);
   1083 
   1084   // Check that the key is an array index, that is Uint32.
   1085   __ And(t0, a0, Operand(kSmiTagMask | kSmiSignMask));
   1086   __ Branch(&slow, ne, t0, Operand(zero_reg));
   1087 
   1088   // Get the map of the receiver.
   1089   __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
   1090 
   1091   // Check that it has indexed interceptor and access checks
   1092   // are not enabled for this object.
   1093   __ lbu(a3, FieldMemOperand(a2, Map::kBitFieldOffset));
   1094   __ And(a3, a3, Operand(kSlowCaseBitFieldMask));
   1095   __ Branch(&slow, ne, a3, Operand(1 << Map::kHasIndexedInterceptor));
   1096   // Everything is fine, call runtime.
   1097   __ Push(a1, a0);  // Receiver, key.
   1098 
   1099   // Perform tail call to the entry.
   1100   __ TailCallExternalReference(ExternalReference(
   1101        IC_Utility(kKeyedLoadPropertyWithInterceptor), masm->isolate()), 2, 1);
   1102 
   1103   __ bind(&slow);
   1104   GenerateMiss(masm);
   1105 }
   1106 
   1107 
   1108 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
   1109   // ---------- S t a t e --------------
   1110   //  -- a0     : value
   1111   //  -- a1     : key
   1112   //  -- a2     : receiver
   1113   //  -- ra     : return address
   1114   // -----------------------------------
   1115 
   1116   // Push receiver, key and value for runtime call.
   1117   __ Push(a2, a1, a0);
   1118 
   1119   ExternalReference ref =
   1120       ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
   1121   __ TailCallExternalReference(ref, 3, 1);
   1122 }
   1123 
   1124 
   1125 void StoreIC::GenerateSlow(MacroAssembler* masm) {
   1126   // ---------- S t a t e --------------
   1127   //  -- a0     : value
   1128   //  -- a2     : key
   1129   //  -- a1     : receiver
   1130   //  -- ra     : return address
   1131   // -----------------------------------
   1132 
   1133   // Push receiver, key and value for runtime call.
   1134   __ Push(a1, a2, a0);
   1135 
   1136   // The slow case calls into the runtime to complete the store without causing
   1137   // an IC miss that would otherwise cause a transition to the generic stub.
   1138   ExternalReference ref =
   1139       ExternalReference(IC_Utility(kStoreIC_Slow), masm->isolate());
   1140   __ TailCallExternalReference(ref, 3, 1);
   1141 }
   1142 
   1143 
   1144 void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
   1145   // ---------- S t a t e --------------
   1146   //  -- a0     : value
   1147   //  -- a1     : key
   1148   //  -- a2     : receiver
   1149   //  -- ra     : return address
   1150   // -----------------------------------
   1151 
   1152   // Push receiver, key and value for runtime call.
   1153   // We can't use MultiPush as the order of the registers is important.
   1154   __ Push(a2, a1, a0);
   1155 
   1156   // The slow case calls into the runtime to complete the store without causing
   1157   // an IC miss that would otherwise cause a transition to the generic stub.
   1158   ExternalReference ref =
   1159       ExternalReference(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
   1160 
   1161   __ TailCallExternalReference(ref, 3, 1);
   1162 }
   1163 
   1164 
   1165 void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
   1166   // ----------- S t a t e -------------
   1167   //  -- a0    : value
   1168   //  -- a1    : receiver
   1169   //  -- a2    : name
   1170   //  -- ra    : return address
   1171   // -----------------------------------
   1172 
   1173   // Get the receiver from the stack and probe the stub cache.
   1174   Code::Flags flags = Code::ComputeHandlerFlags(Code::STORE_IC);
   1175   masm->isolate()->stub_cache()->GenerateProbe(
   1176       masm, flags, a1, a2, a3, t0, t1, t2);
   1177 
   1178   // Cache miss: Jump to runtime.
   1179   GenerateMiss(masm);
   1180 }
   1181 
   1182 
   1183 void StoreIC::GenerateMiss(MacroAssembler* masm) {
   1184   // ----------- S t a t e -------------
   1185   //  -- a0    : value
   1186   //  -- a1    : receiver
   1187   //  -- a2    : name
   1188   //  -- ra    : return address
   1189   // -----------------------------------
   1190 
   1191   __ Push(a1, a2, a0);
   1192   // Perform tail call to the entry.
   1193   ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss),
   1194                                             masm->isolate());
   1195   __ TailCallExternalReference(ref, 3, 1);
   1196 }
   1197 
   1198 
   1199 void StoreIC::GenerateNormal(MacroAssembler* masm) {
   1200   // ----------- S t a t e -------------
   1201   //  -- a0    : value
   1202   //  -- a1    : receiver
   1203   //  -- a2    : name
   1204   //  -- ra    : return address
   1205   // -----------------------------------
   1206   Label miss;
   1207 
   1208   GenerateNameDictionaryReceiverCheck(masm, a1, a3, t0, t1, &miss);
   1209 
   1210   GenerateDictionaryStore(masm, &miss, a3, a2, a0, t0, t1);
   1211   Counters* counters = masm->isolate()->counters();
   1212   __ IncrementCounter(counters->store_normal_hit(), 1, t0, t1);
   1213   __ Ret();
   1214 
   1215   __ bind(&miss);
   1216   __ IncrementCounter(counters->store_normal_miss(), 1, t0, t1);
   1217   GenerateMiss(masm);
   1218 }
   1219 
   1220 
   1221 void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
   1222                                          StrictMode strict_mode) {
   1223   // ----------- S t a t e -------------
   1224   //  -- a0    : value
   1225   //  -- a1    : receiver
   1226   //  -- a2    : name
   1227   //  -- ra    : return address
   1228   // -----------------------------------
   1229 
   1230   __ Push(a1, a2, a0);
   1231 
   1232   __ li(a1, Operand(Smi::FromInt(NONE)));  // PropertyAttributes.
   1233   __ li(a0, Operand(Smi::FromInt(strict_mode)));
   1234   __ Push(a1, a0);
   1235 
   1236   // Do tail-call to runtime routine.
   1237   __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
   1238 }
   1239 
   1240 
   1241 #undef __
   1242 
   1243 
   1244 Condition CompareIC::ComputeCondition(Token::Value op) {
   1245   switch (op) {
   1246     case Token::EQ_STRICT:
   1247     case Token::EQ:
   1248       return eq;
   1249     case Token::LT:
   1250       return lt;
   1251     case Token::GT:
   1252       return gt;
   1253     case Token::LTE:
   1254       return le;
   1255     case Token::GTE:
   1256       return ge;
   1257     default:
   1258       UNREACHABLE();
   1259       return kNoCondition;
   1260   }
   1261 }
   1262 
   1263 
   1264 bool CompareIC::HasInlinedSmiCode(Address address) {
   1265   // The address of the instruction following the call.
   1266   Address andi_instruction_address =
   1267       address + Assembler::kCallTargetAddressOffset;
   1268 
   1269   // If the instruction following the call is not a andi at, rx, #yyy, nothing
   1270   // was inlined.
   1271   Instr instr = Assembler::instr_at(andi_instruction_address);
   1272   return Assembler::IsAndImmediate(instr) &&
   1273       Assembler::GetRt(instr) == static_cast<uint32_t>(zero_reg.code());
   1274 }
   1275 
   1276 
   1277 void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) {
   1278   Address andi_instruction_address =
   1279       address + Assembler::kCallTargetAddressOffset;
   1280 
   1281   // If the instruction following the call is not a andi at, rx, #yyy, nothing
   1282   // was inlined.
   1283   Instr instr = Assembler::instr_at(andi_instruction_address);
   1284   if (!(Assembler::IsAndImmediate(instr) &&
   1285         Assembler::GetRt(instr) == static_cast<uint32_t>(zero_reg.code()))) {
   1286     return;
   1287   }
   1288 
   1289   // The delta to the start of the map check instruction and the
   1290   // condition code uses at the patched jump.
   1291   int delta = Assembler::GetImmediate16(instr);
   1292   delta += Assembler::GetRs(instr) * kImm16Mask;
   1293   // If the delta is 0 the instruction is andi at, zero_reg, #0 which also
   1294   // signals that nothing was inlined.
   1295   if (delta == 0) {
   1296     return;
   1297   }
   1298 
   1299   if (FLAG_trace_ic) {
   1300     PrintF("[  patching ic at %p, andi=%p, delta=%d\n",
   1301            address, andi_instruction_address, delta);
   1302   }
   1303 
   1304   Address patch_address =
   1305       andi_instruction_address - delta * Instruction::kInstrSize;
   1306   Instr instr_at_patch = Assembler::instr_at(patch_address);
   1307   Instr branch_instr =
   1308       Assembler::instr_at(patch_address + Instruction::kInstrSize);
   1309   // This is patching a conditional "jump if not smi/jump if smi" site.
   1310   // Enabling by changing from
   1311   //   andi at, rx, 0
   1312   //   Branch <target>, eq, at, Operand(zero_reg)
   1313   // to:
   1314   //   andi at, rx, #kSmiTagMask
   1315   //   Branch <target>, ne, at, Operand(zero_reg)
   1316   // and vice-versa to be disabled again.
   1317   CodePatcher patcher(patch_address, 2);
   1318   Register reg = Register::from_code(Assembler::GetRs(instr_at_patch));
   1319   if (check == ENABLE_INLINED_SMI_CHECK) {
   1320     ASSERT(Assembler::IsAndImmediate(instr_at_patch));
   1321     ASSERT_EQ(0, Assembler::GetImmediate16(instr_at_patch));
   1322     patcher.masm()->andi(at, reg, kSmiTagMask);
   1323   } else {
   1324     ASSERT(check == DISABLE_INLINED_SMI_CHECK);
   1325     ASSERT(Assembler::IsAndImmediate(instr_at_patch));
   1326     patcher.masm()->andi(at, reg, 0);
   1327   }
   1328   ASSERT(Assembler::IsBranch(branch_instr));
   1329   if (Assembler::IsBeq(branch_instr)) {
   1330     patcher.ChangeBranchCondition(ne);
   1331   } else {
   1332     ASSERT(Assembler::IsBne(branch_instr));
   1333     patcher.ChangeBranchCondition(eq);
   1334   }
   1335 }
   1336 
   1337 
   1338 } }  // namespace v8::internal
   1339 
   1340 #endif  // V8_TARGET_ARCH_MIPS
   1341