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 #if V8_TARGET_ARCH_MIPS
      6 
      7 #include "src/codegen.h"
      8 #include "src/ic/ic.h"
      9 #include "src/ic/ic-compiler.h"
     10 #include "src/ic/stub-cache.h"
     11 
     12 namespace v8 {
     13 namespace internal {
     14 
     15 
     16 // ----------------------------------------------------------------------------
     17 // Static IC stub generators.
     18 //
     19 
     20 #define __ ACCESS_MASM(masm)
     21 
     22 
     23 static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm, Register type,
     24                                             Label* global_object) {
     25   // Register usage:
     26   //   type: holds the receiver instance type on entry.
     27   __ Branch(global_object, eq, type, Operand(JS_GLOBAL_OBJECT_TYPE));
     28   __ Branch(global_object, eq, type, Operand(JS_GLOBAL_PROXY_TYPE));
     29 }
     30 
     31 
     32 // Helper function used from LoadIC GenerateNormal.
     33 //
     34 // elements: Property dictionary. It is not clobbered if a jump to the miss
     35 //           label is done.
     36 // name:     Property name. It is not clobbered if a jump to the miss label is
     37 //           done
     38 // result:   Register for the result. It is only updated if a jump to the miss
     39 //           label is not done. Can be the same as elements or name clobbering
     40 //           one of these in the case of not jumping to the miss label.
     41 // The two scratch registers need to be different from elements, name and
     42 // result.
     43 // The generated code assumes that the receiver has slow properties,
     44 // is not a global object and does not have interceptors.
     45 // The address returned from GenerateStringDictionaryProbes() in scratch2
     46 // is used.
     47 static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss,
     48                                    Register elements, Register name,
     49                                    Register result, Register scratch1,
     50                                    Register scratch2) {
     51   // Main use of the scratch registers.
     52   // scratch1: Used as temporary and to hold the capacity of the property
     53   //           dictionary.
     54   // scratch2: Used as temporary.
     55   Label done;
     56 
     57   // Probe the dictionary.
     58   NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
     59                                                    name, scratch1, scratch2);
     60 
     61   // If probing finds an entry check that the value is a normal
     62   // property.
     63   __ bind(&done);  // scratch2 == elements + 4 * index.
     64   const int kElementsStartOffset =
     65       NameDictionary::kHeaderSize +
     66       NameDictionary::kElementsStartIndex * kPointerSize;
     67   const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
     68   __ lw(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
     69   __ And(at, scratch1,
     70          Operand(PropertyDetails::TypeField::kMask << kSmiTagSize));
     71   __ Branch(miss, ne, at, Operand(zero_reg));
     72 
     73   // Get the value at the masked, scaled index and return.
     74   __ lw(result,
     75         FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
     76 }
     77 
     78 
     79 // Helper function used from StoreIC::GenerateNormal.
     80 //
     81 // elements: Property dictionary. It is not clobbered if a jump to the miss
     82 //           label is done.
     83 // name:     Property name. It is not clobbered if a jump to the miss label is
     84 //           done
     85 // value:    The value to store.
     86 // The two scratch registers need to be different from elements, name and
     87 // result.
     88 // The generated code assumes that the receiver has slow properties,
     89 // is not a global object and does not have interceptors.
     90 // The address returned from GenerateStringDictionaryProbes() in scratch2
     91 // is used.
     92 static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss,
     93                                     Register elements, Register name,
     94                                     Register value, Register scratch1,
     95                                     Register scratch2) {
     96   // Main use of the scratch registers.
     97   // scratch1: Used as temporary and to hold the capacity of the property
     98   //           dictionary.
     99   // scratch2: Used as temporary.
    100   Label done;
    101 
    102   // Probe the dictionary.
    103   NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
    104                                                    name, scratch1, scratch2);
    105 
    106   // If probing finds an entry in the dictionary check that the value
    107   // is a normal property that is not read only.
    108   __ bind(&done);  // scratch2 == elements + 4 * index.
    109   const int kElementsStartOffset =
    110       NameDictionary::kHeaderSize +
    111       NameDictionary::kElementsStartIndex * kPointerSize;
    112   const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
    113   const int kTypeAndReadOnlyMask =
    114       (PropertyDetails::TypeField::kMask |
    115        PropertyDetails::AttributesField::encode(READ_ONLY))
    116       << kSmiTagSize;
    117   __ lw(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
    118   __ And(at, scratch1, Operand(kTypeAndReadOnlyMask));
    119   __ Branch(miss, ne, at, Operand(zero_reg));
    120 
    121   // Store the value at the masked, scaled index and return.
    122   const int kValueOffset = kElementsStartOffset + kPointerSize;
    123   __ Addu(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag));
    124   __ sw(value, MemOperand(scratch2));
    125 
    126   // Update the write barrier. Make sure not to clobber the value.
    127   __ mov(scratch1, value);
    128   __ RecordWrite(elements, scratch2, scratch1, kRAHasNotBeenSaved,
    129                  kDontSaveFPRegs);
    130 }
    131 
    132 
    133 // Checks the receiver for special cases (value type, slow case bits).
    134 // Falls through for regular JS object.
    135 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
    136                                            Register receiver, Register map,
    137                                            Register scratch,
    138                                            int interceptor_bit, Label* slow) {
    139   // Check that the object isn't a smi.
    140   __ JumpIfSmi(receiver, slow);
    141   // Get the map of the receiver.
    142   __ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
    143   // Check bit field.
    144   __ lbu(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
    145   __ And(at, scratch,
    146          Operand((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)));
    147   __ Branch(slow, ne, at, Operand(zero_reg));
    148   // Check that the object is some kind of JS object EXCEPT JS Value type.
    149   // In the case that the object is a value-wrapper object,
    150   // we enter the runtime system to make sure that indexing into string
    151   // objects work as intended.
    152   DCHECK(JS_OBJECT_TYPE > JS_VALUE_TYPE);
    153   __ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
    154   __ Branch(slow, lt, scratch, Operand(JS_OBJECT_TYPE));
    155 }
    156 
    157 
    158 // Loads an indexed element from a fast case array.
    159 static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver,
    160                                   Register key, Register elements,
    161                                   Register scratch1, Register scratch2,
    162                                   Register result, Label* slow) {
    163   // Register use:
    164   //
    165   // receiver - holds the receiver on entry.
    166   //            Unchanged unless 'result' is the same register.
    167   //
    168   // key      - holds the smi key on entry.
    169   //            Unchanged unless 'result' is the same register.
    170   //
    171   // result   - holds the result on exit if the load succeeded.
    172   //            Allowed to be the the same as 'receiver' or 'key'.
    173   //            Unchanged on bailout so 'receiver' and 'key' can be safely
    174   //            used by further computation.
    175   //
    176   // Scratch registers:
    177   //
    178   // elements - holds the elements of the receiver and its prototypes.
    179   //
    180   // scratch1 - used to hold elements length, bit fields, base addresses.
    181   //
    182   // scratch2 - used to hold maps, prototypes, and the loaded value.
    183   Label check_prototypes, check_next_prototype;
    184   Label done, in_bounds, absent;
    185 
    186   __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
    187   __ AssertFastElements(elements);
    188 
    189   // Check that the key (index) is within bounds.
    190   __ lw(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset));
    191   __ Branch(&in_bounds, lo, key, Operand(scratch1));
    192   // Out-of-bounds. Check the prototype chain to see if we can just return
    193   // 'undefined'.
    194   // Negative keys can't take the fast OOB path.
    195   __ Branch(slow, lt, key, Operand(zero_reg));
    196   __ bind(&check_prototypes);
    197   __ lw(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset));
    198   __ bind(&check_next_prototype);
    199   __ lw(scratch2, FieldMemOperand(scratch2, Map::kPrototypeOffset));
    200   // scratch2: current prototype
    201   __ LoadRoot(at, Heap::kNullValueRootIndex);
    202   __ Branch(&absent, eq, scratch2, Operand(at));
    203   __ lw(elements, FieldMemOperand(scratch2, JSObject::kElementsOffset));
    204   __ lw(scratch2, FieldMemOperand(scratch2, HeapObject::kMapOffset));
    205   // elements: elements of current prototype
    206   // scratch2: map of current prototype
    207   __ lbu(scratch1, FieldMemOperand(scratch2, Map::kInstanceTypeOffset));
    208   __ Branch(slow, lo, scratch1, Operand(JS_OBJECT_TYPE));
    209   __ lbu(scratch1, FieldMemOperand(scratch2, Map::kBitFieldOffset));
    210   __ And(at, scratch1, Operand((1 << Map::kIsAccessCheckNeeded) |
    211                                (1 << Map::kHasIndexedInterceptor)));
    212   __ Branch(slow, ne, at, Operand(zero_reg));
    213   __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
    214   __ Branch(slow, ne, elements, Operand(at));
    215   __ Branch(&check_next_prototype);
    216 
    217   __ bind(&absent);
    218   __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
    219   __ Branch(&done);
    220 
    221   __ bind(&in_bounds);
    222   // Fast case: Do the load.
    223   __ Addu(scratch1, elements,
    224           Operand(FixedArray::kHeaderSize - kHeapObjectTag));
    225   // The key is a smi.
    226   STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
    227   __ Lsa(at, scratch1, key, kPointerSizeLog2 - kSmiTagSize);
    228   __ lw(scratch2, MemOperand(at));
    229 
    230   __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
    231   // In case the loaded value is the_hole we have to check the prototype chain.
    232   __ Branch(&check_prototypes, eq, scratch2, Operand(at));
    233   __ Move(result, scratch2);
    234   __ bind(&done);
    235 }
    236 
    237 
    238 // Checks whether a key is an array index string or a unique name.
    239 // Falls through if a key is a unique name.
    240 static void GenerateKeyNameCheck(MacroAssembler* masm, Register key,
    241                                  Register map, Register hash,
    242                                  Label* index_string, Label* not_unique) {
    243   // The key is not a smi.
    244   Label unique;
    245   // Is it a name?
    246   __ GetObjectType(key, map, hash);
    247   __ Branch(not_unique, hi, hash, Operand(LAST_UNIQUE_NAME_TYPE));
    248   STATIC_ASSERT(LAST_UNIQUE_NAME_TYPE == FIRST_NONSTRING_TYPE);
    249   __ Branch(&unique, eq, hash, Operand(LAST_UNIQUE_NAME_TYPE));
    250 
    251   // Is the string an array index, with cached numeric value?
    252   __ lw(hash, FieldMemOperand(key, Name::kHashFieldOffset));
    253   __ And(at, hash, Operand(Name::kContainsCachedArrayIndexMask));
    254   __ Branch(index_string, eq, at, Operand(zero_reg));
    255 
    256   // Is the string internalized? We know it's a string, so a single
    257   // bit test is enough.
    258   // map: key map
    259   __ lbu(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
    260   STATIC_ASSERT(kInternalizedTag == 0);
    261   __ And(at, hash, Operand(kIsNotInternalizedMask));
    262   __ Branch(not_unique, ne, at, Operand(zero_reg));
    263 
    264   __ bind(&unique);
    265 }
    266 
    267 void LoadIC::GenerateNormal(MacroAssembler* masm) {
    268   Register dictionary = a0;
    269   DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
    270   DCHECK(!dictionary.is(LoadDescriptor::NameRegister()));
    271 
    272   Label slow;
    273 
    274   __ lw(dictionary, FieldMemOperand(LoadDescriptor::ReceiverRegister(),
    275                                     JSObject::kPropertiesOffset));
    276   GenerateDictionaryLoad(masm, &slow, dictionary,
    277                          LoadDescriptor::NameRegister(), v0, a3, t0);
    278   __ Ret();
    279 
    280   // Dictionary load failed, go slow (but don't miss).
    281   __ bind(&slow);
    282   GenerateRuntimeGetProperty(masm);
    283 }
    284 
    285 
    286 // A register that isn't one of the parameters to the load ic.
    287 static const Register LoadIC_TempRegister() { return a3; }
    288 
    289 
    290 static void LoadIC_PushArgs(MacroAssembler* masm) {
    291   Register receiver = LoadDescriptor::ReceiverRegister();
    292   Register name = LoadDescriptor::NameRegister();
    293   Register slot = LoadDescriptor::SlotRegister();
    294   Register vector = LoadWithVectorDescriptor::VectorRegister();
    295 
    296   __ Push(receiver, name, slot, vector);
    297 }
    298 
    299 
    300 void LoadIC::GenerateMiss(MacroAssembler* masm) {
    301   // The return address is in ra.
    302   Isolate* isolate = masm->isolate();
    303 
    304   DCHECK(!AreAliased(t0, t1, LoadWithVectorDescriptor::SlotRegister(),
    305                      LoadWithVectorDescriptor::VectorRegister()));
    306   __ IncrementCounter(isolate->counters()->ic_load_miss(), 1, t0, t1);
    307 
    308   LoadIC_PushArgs(masm);
    309 
    310   // Perform tail call to the entry.
    311   __ TailCallRuntime(Runtime::kLoadIC_Miss);
    312 }
    313 
    314 void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
    315   // The return address is in ra.
    316 
    317   __ mov(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister());
    318   __ Push(LoadIC_TempRegister(), LoadDescriptor::NameRegister());
    319 
    320   // Do tail-call to runtime routine.
    321   __ TailCallRuntime(Runtime::kGetProperty);
    322 }
    323 
    324 
    325 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
    326   // The return address is in ra.
    327   Isolate* isolate = masm->isolate();
    328 
    329   DCHECK(!AreAliased(t0, t1, LoadWithVectorDescriptor::SlotRegister(),
    330                      LoadWithVectorDescriptor::VectorRegister()));
    331   __ IncrementCounter(isolate->counters()->ic_keyed_load_miss(), 1, t0, t1);
    332 
    333   LoadIC_PushArgs(masm);
    334 
    335   // Perform tail call to the entry.
    336   __ TailCallRuntime(Runtime::kKeyedLoadIC_Miss);
    337 }
    338 
    339 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
    340   // The return address is in ra.
    341 
    342   __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister());
    343 
    344   // Do tail-call to runtime routine.
    345   __ TailCallRuntime(Runtime::kKeyedGetProperty);
    346 }
    347 
    348 void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) {
    349   // The return address is in ra.
    350   Label slow, check_name, index_smi, index_name, property_array_property;
    351   Label probe_dictionary, check_number_dictionary;
    352 
    353   Register key = LoadDescriptor::NameRegister();
    354   Register receiver = LoadDescriptor::ReceiverRegister();
    355   DCHECK(key.is(a2));
    356   DCHECK(receiver.is(a1));
    357 
    358   Isolate* isolate = masm->isolate();
    359 
    360   // Check that the key is a smi.
    361   __ JumpIfNotSmi(key, &check_name);
    362   __ bind(&index_smi);
    363   // Now the key is known to be a smi. This place is also jumped to from below
    364   // where a numeric string is converted to a smi.
    365 
    366   GenerateKeyedLoadReceiverCheck(masm, receiver, a0, a3,
    367                                  Map::kHasIndexedInterceptor, &slow);
    368 
    369   // Check the receiver's map to see if it has fast elements.
    370   __ CheckFastElements(a0, a3, &check_number_dictionary);
    371 
    372   GenerateFastArrayLoad(masm, receiver, key, a0, a3, t0, v0, &slow);
    373   __ IncrementCounter(isolate->counters()->ic_keyed_load_generic_smi(), 1, t0,
    374                       a3);
    375   __ Ret();
    376 
    377   __ bind(&check_number_dictionary);
    378   __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
    379   __ lw(a3, FieldMemOperand(t0, JSObject::kMapOffset));
    380 
    381   // Check whether the elements is a number dictionary.
    382   // a3: elements map
    383   // t0: elements
    384   __ LoadRoot(at, Heap::kHashTableMapRootIndex);
    385   __ Branch(&slow, ne, a3, Operand(at));
    386   __ sra(a0, key, kSmiTagSize);
    387   __ LoadFromNumberDictionary(&slow, t0, key, v0, a0, a3, t1);
    388   __ Ret();
    389 
    390   // Slow case, key and receiver still in a2 and a1.
    391   __ bind(&slow);
    392   __ IncrementCounter(isolate->counters()->ic_keyed_load_generic_slow(), 1, t0,
    393                       a3);
    394   GenerateRuntimeGetProperty(masm);
    395 
    396   __ bind(&check_name);
    397   GenerateKeyNameCheck(masm, key, a0, a3, &index_name, &slow);
    398 
    399   GenerateKeyedLoadReceiverCheck(masm, receiver, a0, a3,
    400                                  Map::kHasNamedInterceptor, &slow);
    401 
    402 
    403   // If the receiver is a fast-case object, check the stub cache. Otherwise
    404   // probe the dictionary.
    405   __ lw(a3, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
    406   __ lw(t0, FieldMemOperand(a3, HeapObject::kMapOffset));
    407   __ LoadRoot(at, Heap::kHashTableMapRootIndex);
    408   __ Branch(&probe_dictionary, eq, t0, Operand(at));
    409 
    410   // The handlers in the stub cache expect a vector and slot. Since we won't
    411   // change the IC from any downstream misses, a dummy vector can be used.
    412   Register vector = LoadWithVectorDescriptor::VectorRegister();
    413   Register slot = LoadWithVectorDescriptor::SlotRegister();
    414   DCHECK(!AreAliased(vector, slot, t0, t1, t2, t5));
    415   Handle<TypeFeedbackVector> dummy_vector =
    416       TypeFeedbackVector::DummyVector(masm->isolate());
    417   int slot_index = dummy_vector->GetIndex(
    418       FeedbackVectorSlot(TypeFeedbackVector::kDummyKeyedLoadICSlot));
    419   __ LoadRoot(vector, Heap::kDummyVectorRootIndex);
    420   __ li(slot, Operand(Smi::FromInt(slot_index)));
    421 
    422   Code::Flags flags =
    423       Code::RemoveHolderFromFlags(Code::ComputeHandlerFlags(Code::LOAD_IC));
    424   masm->isolate()->stub_cache()->GenerateProbe(masm, Code::KEYED_LOAD_IC, flags,
    425                                                receiver, key, t0, t1, t2, t5);
    426   // Cache miss.
    427   GenerateMiss(masm);
    428 
    429   // Do a quick inline probe of the receiver's dictionary, if it
    430   // exists.
    431   __ bind(&probe_dictionary);
    432   // a3: elements
    433   __ lw(a0, FieldMemOperand(receiver, HeapObject::kMapOffset));
    434   __ lbu(a0, FieldMemOperand(a0, Map::kInstanceTypeOffset));
    435   GenerateGlobalInstanceTypeCheck(masm, a0, &slow);
    436   // Load the property to v0.
    437   GenerateDictionaryLoad(masm, &slow, a3, key, v0, t1, t0);
    438   __ IncrementCounter(isolate->counters()->ic_keyed_load_generic_symbol(), 1,
    439                       t0, a3);
    440   __ Ret();
    441 
    442   __ bind(&index_name);
    443   __ IndexFromHash(a3, key);
    444   // Now jump to the place where smi keys are handled.
    445   __ Branch(&index_smi);
    446 }
    447 
    448 
    449 static void KeyedStoreGenerateMegamorphicHelper(
    450     MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow,
    451     KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length,
    452     Register value, Register key, Register receiver, Register receiver_map,
    453     Register elements_map, Register elements) {
    454   Label transition_smi_elements;
    455   Label finish_object_store, non_double_value, transition_double_elements;
    456   Label fast_double_without_map_check;
    457 
    458   // Fast case: Do the store, could be either Object or double.
    459   __ bind(fast_object);
    460   Register scratch = t0;
    461   Register scratch2 = t4;
    462   Register scratch3 = t5;
    463   Register address = t1;
    464   DCHECK(!AreAliased(value, key, receiver, receiver_map, elements_map, elements,
    465                      scratch, scratch2, scratch3, address));
    466 
    467   if (check_map == kCheckMap) {
    468     __ lw(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
    469     __ Branch(fast_double, ne, elements_map,
    470               Operand(masm->isolate()->factory()->fixed_array_map()));
    471   }
    472 
    473   // HOLECHECK: guards "A[i] = V"
    474   // We have to go to the runtime if the current value is the hole because
    475   // there may be a callback on the element.
    476   Label holecheck_passed1;
    477   __ Addu(address, elements, FixedArray::kHeaderSize - kHeapObjectTag);
    478   __ Lsa(address, address, key, kPointerSizeLog2 - kSmiTagSize);
    479   __ lw(scratch, MemOperand(address));
    480   __ Branch(&holecheck_passed1, ne, scratch,
    481             Operand(masm->isolate()->factory()->the_hole_value()));
    482   __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch, slow);
    483 
    484   __ bind(&holecheck_passed1);
    485 
    486   // Smi stores don't require further checks.
    487   Label non_smi_value;
    488   __ JumpIfNotSmi(value, &non_smi_value);
    489 
    490   if (increment_length == kIncrementLength) {
    491     // Add 1 to receiver->length.
    492     __ Addu(scratch, key, Operand(Smi::FromInt(1)));
    493     __ sw(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
    494   }
    495   // It's irrelevant whether array is smi-only or not when writing a smi.
    496   __ Addu(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
    497   __ Lsa(address, address, key, kPointerSizeLog2 - kSmiTagSize);
    498   __ sw(value, MemOperand(address));
    499   __ Ret();
    500 
    501   __ bind(&non_smi_value);
    502   // Escape to elements kind transition case.
    503   __ CheckFastObjectElements(receiver_map, scratch, &transition_smi_elements);
    504 
    505   // Fast elements array, store the value to the elements backing store.
    506   __ bind(&finish_object_store);
    507   if (increment_length == kIncrementLength) {
    508     // Add 1 to receiver->length.
    509     __ Addu(scratch, key, Operand(Smi::FromInt(1)));
    510     __ sw(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
    511   }
    512   __ Addu(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
    513   __ Lsa(address, address, key, kPointerSizeLog2 - kSmiTagSize);
    514   __ sw(value, MemOperand(address));
    515   // Update write barrier for the elements array address.
    516   __ mov(scratch, value);  // Preserve the value which is returned.
    517   __ RecordWrite(elements, address, scratch, kRAHasNotBeenSaved,
    518                  kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
    519   __ Ret();
    520 
    521   __ bind(fast_double);
    522   if (check_map == kCheckMap) {
    523     // Check for fast double array case. If this fails, call through to the
    524     // runtime.
    525     __ LoadRoot(at, Heap::kFixedDoubleArrayMapRootIndex);
    526     __ Branch(slow, ne, elements_map, Operand(at));
    527   }
    528 
    529   // HOLECHECK: guards "A[i] double hole?"
    530   // We have to see if the double version of the hole is present. If so
    531   // go to the runtime.
    532   __ Addu(address, elements, Operand(FixedDoubleArray::kHeaderSize +
    533                                      kHoleNanUpper32Offset - kHeapObjectTag));
    534   __ Lsa(address, address, key, kPointerSizeLog2);
    535   __ lw(scratch, MemOperand(address));
    536   __ Branch(&fast_double_without_map_check, ne, scratch,
    537             Operand(kHoleNanUpper32));
    538   __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch, slow);
    539 
    540   __ bind(&fast_double_without_map_check);
    541   __ StoreNumberToDoubleElements(value, key, elements, scratch, scratch2,
    542                                  scratch3, &transition_double_elements);
    543   if (increment_length == kIncrementLength) {
    544     // Add 1 to receiver->length.
    545     __ Addu(scratch, key, Operand(Smi::FromInt(1)));
    546     __ sw(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
    547   }
    548   __ Ret();
    549 
    550   __ bind(&transition_smi_elements);
    551   // Transition the array appropriately depending on the value type.
    552   __ lw(scratch, FieldMemOperand(value, HeapObject::kMapOffset));
    553   __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
    554   __ Branch(&non_double_value, ne, scratch, Operand(at));
    555 
    556   // Value is a double. Transition FAST_SMI_ELEMENTS ->
    557   // FAST_DOUBLE_ELEMENTS and complete the store.
    558   __ LoadTransitionedArrayMapConditional(
    559       FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS, receiver_map, scratch, slow);
    560   AllocationSiteMode mode =
    561       AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS);
    562   ElementsTransitionGenerator::GenerateSmiToDouble(masm, receiver, key, value,
    563                                                    receiver_map, mode, slow);
    564   __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
    565   __ jmp(&fast_double_without_map_check);
    566 
    567   __ bind(&non_double_value);
    568   // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
    569   __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, FAST_ELEMENTS,
    570                                          receiver_map, scratch, slow);
    571   mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
    572   ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
    573       masm, receiver, key, value, receiver_map, mode, slow);
    574   __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
    575   __ jmp(&finish_object_store);
    576 
    577   __ bind(&transition_double_elements);
    578   // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
    579   // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
    580   // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
    581   __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS,
    582                                          receiver_map, scratch, slow);
    583   mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
    584   ElementsTransitionGenerator::GenerateDoubleToObject(
    585       masm, receiver, key, value, receiver_map, mode, slow);
    586   __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
    587   __ jmp(&finish_object_store);
    588 }
    589 
    590 
    591 void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
    592                                        LanguageMode language_mode) {
    593   // ---------- S t a t e --------------
    594   //  -- a0     : value
    595   //  -- a1     : key
    596   //  -- a2     : receiver
    597   //  -- ra     : return address
    598   // -----------------------------------
    599   Label slow, fast_object, fast_object_grow;
    600   Label fast_double, fast_double_grow;
    601   Label array, extra, check_if_double_array, maybe_name_key, miss;
    602 
    603   // Register usage.
    604   Register value = StoreDescriptor::ValueRegister();
    605   Register key = StoreDescriptor::NameRegister();
    606   Register receiver = StoreDescriptor::ReceiverRegister();
    607   DCHECK(value.is(a0));
    608   Register receiver_map = a3;
    609   Register elements_map = t2;
    610   Register elements = t3;  // Elements array of the receiver.
    611   // t0 and t1 are used as general scratch registers.
    612 
    613   // Check that the key is a smi.
    614   __ JumpIfNotSmi(key, &maybe_name_key);
    615   // Check that the object isn't a smi.
    616   __ JumpIfSmi(receiver, &slow);
    617   // Get the map of the object.
    618   __ lw(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
    619   // Check that the receiver does not require access checks.
    620   // The generic stub does not perform map checks.
    621   __ lbu(t0, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
    622   __ And(t0, t0, Operand(1 << Map::kIsAccessCheckNeeded));
    623   __ Branch(&slow, ne, t0, Operand(zero_reg));
    624   // Check if the object is a JS array or not.
    625   __ lbu(t0, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset));
    626   __ Branch(&array, eq, t0, Operand(JS_ARRAY_TYPE));
    627   // Check that the object is some kind of JS object EXCEPT JS Value type. In
    628   // the case that the object is a value-wrapper object, we enter the runtime
    629   // system to make sure that indexing into string objects works as intended.
    630   STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE);
    631   __ Branch(&slow, lo, t0, Operand(JS_OBJECT_TYPE));
    632 
    633   // Object case: Check key against length in the elements array.
    634   __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
    635   // Check array bounds. Both the key and the length of FixedArray are smis.
    636   __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
    637   __ Branch(&fast_object, lo, key, Operand(t0));
    638 
    639   // Slow case, handle jump to runtime.
    640   __ bind(&slow);
    641   // Entry registers are intact.
    642   // a0: value.
    643   // a1: key.
    644   // a2: receiver.
    645   PropertyICCompiler::GenerateRuntimeSetProperty(masm, language_mode);
    646   // Never returns to here.
    647 
    648   __ bind(&maybe_name_key);
    649   __ lw(t0, FieldMemOperand(key, HeapObject::kMapOffset));
    650   __ lb(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset));
    651   __ JumpIfNotUniqueNameInstanceType(t0, &slow);
    652 
    653   // The handlers in the stub cache expect a vector and slot. Since we won't
    654   // change the IC from any downstream misses, a dummy vector can be used.
    655   Register vector = VectorStoreICDescriptor::VectorRegister();
    656   Register slot = VectorStoreICDescriptor::SlotRegister();
    657   DCHECK(!AreAliased(vector, slot, t1, t2, t4, t5));
    658   Handle<TypeFeedbackVector> dummy_vector =
    659       TypeFeedbackVector::DummyVector(masm->isolate());
    660   int slot_index = dummy_vector->GetIndex(
    661       FeedbackVectorSlot(TypeFeedbackVector::kDummyKeyedStoreICSlot));
    662   __ LoadRoot(vector, Heap::kDummyVectorRootIndex);
    663   __ li(slot, Operand(Smi::FromInt(slot_index)));
    664 
    665   Code::Flags flags =
    666       Code::RemoveHolderFromFlags(Code::ComputeHandlerFlags(Code::STORE_IC));
    667   masm->isolate()->stub_cache()->GenerateProbe(
    668       masm, Code::KEYED_STORE_IC, flags, receiver, key, t1, t2, t4, t5);
    669   // Cache miss.
    670   __ Branch(&miss);
    671 
    672   // Extra capacity case: Check if there is extra capacity to
    673   // perform the store and update the length. Used for adding one
    674   // element to the array by writing to array[array.length].
    675   __ bind(&extra);
    676   // Condition code from comparing key and array length is still available.
    677   // Only support writing to array[array.length].
    678   __ Branch(&slow, ne, key, Operand(t0));
    679   // Check for room in the elements backing store.
    680   // Both the key and the length of FixedArray are smis.
    681   __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
    682   __ Branch(&slow, hs, key, Operand(t0));
    683   __ lw(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
    684   __ Branch(&check_if_double_array, ne, elements_map,
    685             Heap::kFixedArrayMapRootIndex);
    686 
    687   __ jmp(&fast_object_grow);
    688 
    689   __ bind(&check_if_double_array);
    690   __ Branch(&slow, ne, elements_map, Heap::kFixedDoubleArrayMapRootIndex);
    691   __ jmp(&fast_double_grow);
    692 
    693   // Array case: Get the length and the elements array from the JS
    694   // array. Check that the array is in fast mode (and writable); if it
    695   // is the length is always a smi.
    696   __ bind(&array);
    697   __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
    698 
    699   // Check the key against the length in the array.
    700   __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
    701   __ Branch(&extra, hs, key, Operand(t0));
    702 
    703   KeyedStoreGenerateMegamorphicHelper(
    704       masm, &fast_object, &fast_double, &slow, kCheckMap, kDontIncrementLength,
    705       value, key, receiver, receiver_map, elements_map, elements);
    706   KeyedStoreGenerateMegamorphicHelper(masm, &fast_object_grow,
    707                                       &fast_double_grow, &slow, kDontCheckMap,
    708                                       kIncrementLength, value, key, receiver,
    709                                       receiver_map, elements_map, elements);
    710 
    711   __ bind(&miss);
    712   GenerateMiss(masm);
    713 }
    714 
    715 
    716 static void StoreIC_PushArgs(MacroAssembler* masm) {
    717   __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
    718           StoreDescriptor::ValueRegister(),
    719           VectorStoreICDescriptor::SlotRegister(),
    720           VectorStoreICDescriptor::VectorRegister());
    721 }
    722 
    723 
    724 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
    725   StoreIC_PushArgs(masm);
    726 
    727   __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss);
    728 }
    729 
    730 void StoreIC::GenerateMiss(MacroAssembler* masm) {
    731   StoreIC_PushArgs(masm);
    732 
    733   // Perform tail call to the entry.
    734   __ TailCallRuntime(Runtime::kStoreIC_Miss);
    735 }
    736 
    737 
    738 void StoreIC::GenerateNormal(MacroAssembler* masm) {
    739   Label miss;
    740   Register receiver = StoreDescriptor::ReceiverRegister();
    741   Register name = StoreDescriptor::NameRegister();
    742   Register value = StoreDescriptor::ValueRegister();
    743   Register dictionary = t1;
    744   DCHECK(receiver.is(a1));
    745   DCHECK(name.is(a2));
    746   DCHECK(value.is(a0));
    747   DCHECK(VectorStoreICDescriptor::VectorRegister().is(a3));
    748   DCHECK(VectorStoreICDescriptor::SlotRegister().is(t0));
    749 
    750   __ lw(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
    751 
    752   GenerateDictionaryStore(masm, &miss, dictionary, name, value, t2, t5);
    753   Counters* counters = masm->isolate()->counters();
    754   __ IncrementCounter(counters->ic_store_normal_hit(), 1, t2, t5);
    755   __ Ret();
    756 
    757   __ bind(&miss);
    758   __ IncrementCounter(counters->ic_store_normal_miss(), 1, t2, t5);
    759   GenerateMiss(masm);
    760 }
    761 
    762 
    763 #undef __
    764 
    765 
    766 Condition CompareIC::ComputeCondition(Token::Value op) {
    767   switch (op) {
    768     case Token::EQ_STRICT:
    769     case Token::EQ:
    770       return eq;
    771     case Token::LT:
    772       return lt;
    773     case Token::GT:
    774       return gt;
    775     case Token::LTE:
    776       return le;
    777     case Token::GTE:
    778       return ge;
    779     default:
    780       UNREACHABLE();
    781       return kNoCondition;
    782   }
    783 }
    784 
    785 
    786 bool CompareIC::HasInlinedSmiCode(Address address) {
    787   // The address of the instruction following the call.
    788   Address andi_instruction_address =
    789       address + Assembler::kCallTargetAddressOffset;
    790 
    791   // If the instruction following the call is not a andi at, rx, #yyy, nothing
    792   // was inlined.
    793   Instr instr = Assembler::instr_at(andi_instruction_address);
    794   return Assembler::IsAndImmediate(instr) &&
    795          Assembler::GetRt(instr) == static_cast<uint32_t>(zero_reg.code());
    796 }
    797 
    798 
    799 void PatchInlinedSmiCode(Isolate* isolate, Address address,
    800                          InlinedSmiCheck check) {
    801   Address andi_instruction_address =
    802       address + Assembler::kCallTargetAddressOffset;
    803 
    804   // If the instruction following the call is not a andi at, rx, #yyy, nothing
    805   // was inlined.
    806   Instr instr = Assembler::instr_at(andi_instruction_address);
    807   if (!(Assembler::IsAndImmediate(instr) &&
    808         Assembler::GetRt(instr) == static_cast<uint32_t>(zero_reg.code()))) {
    809     return;
    810   }
    811 
    812   // The delta to the start of the map check instruction and the
    813   // condition code uses at the patched jump.
    814   int delta = Assembler::GetImmediate16(instr);
    815   delta += Assembler::GetRs(instr) * kImm16Mask;
    816   // If the delta is 0 the instruction is andi at, zero_reg, #0 which also
    817   // signals that nothing was inlined.
    818   if (delta == 0) {
    819     return;
    820   }
    821 
    822   if (FLAG_trace_ic) {
    823     PrintF("[  patching ic at %p, andi=%p, delta=%d\n",
    824            static_cast<void*>(address),
    825            static_cast<void*>(andi_instruction_address), delta);
    826   }
    827 
    828   Address patch_address =
    829       andi_instruction_address - delta * Instruction::kInstrSize;
    830   Instr instr_at_patch = Assembler::instr_at(patch_address);
    831   // This is patching a conditional "jump if not smi/jump if smi" site.
    832   // Enabling by changing from
    833   //   andi at, rx, 0
    834   //   Branch <target>, eq, at, Operand(zero_reg)
    835   // to:
    836   //   andi at, rx, #kSmiTagMask
    837   //   Branch <target>, ne, at, Operand(zero_reg)
    838   // and vice-versa to be disabled again.
    839   CodePatcher patcher(isolate, patch_address, 2);
    840   Register reg = Register::from_code(Assembler::GetRs(instr_at_patch));
    841   if (check == ENABLE_INLINED_SMI_CHECK) {
    842     DCHECK(Assembler::IsAndImmediate(instr_at_patch));
    843     DCHECK_EQ(0u, Assembler::GetImmediate16(instr_at_patch));
    844     patcher.masm()->andi(at, reg, kSmiTagMask);
    845   } else {
    846     DCHECK_EQ(check, DISABLE_INLINED_SMI_CHECK);
    847     DCHECK(Assembler::IsAndImmediate(instr_at_patch));
    848     patcher.masm()->andi(at, reg, 0);
    849   }
    850   Instr branch_instr =
    851       Assembler::instr_at(patch_address + Instruction::kInstrSize);
    852   DCHECK(Assembler::IsBranch(branch_instr));
    853 
    854   uint32_t opcode = Assembler::GetOpcodeField(branch_instr);
    855   // Currently only the 'eq' and 'ne' cond values are supported and the simple
    856   // branch instructions and their r6 variants (with opcode being the branch
    857   // type). There are some special cases (see Assembler::IsBranch()) so
    858   // extending this would be tricky.
    859   DCHECK(opcode == BEQ ||    // BEQ
    860          opcode == BNE ||    // BNE
    861          opcode == POP10 ||  // BEQC
    862          opcode == POP30 ||  // BNEC
    863          opcode == POP66 ||  // BEQZC
    864          opcode == POP76);   // BNEZC
    865   switch (opcode) {
    866     case BEQ:
    867       opcode = BNE;  // change BEQ to BNE.
    868       break;
    869     case POP10:
    870       opcode = POP30;  // change BEQC to BNEC.
    871       break;
    872     case POP66:
    873       opcode = POP76;  // change BEQZC to BNEZC.
    874       break;
    875     case BNE:
    876       opcode = BEQ;  // change BNE to BEQ.
    877       break;
    878     case POP30:
    879       opcode = POP10;  // change BNEC to BEQC.
    880       break;
    881     case POP76:
    882       opcode = POP66;  // change BNEZC to BEQZC.
    883       break;
    884     default:
    885       UNIMPLEMENTED();
    886   }
    887   patcher.ChangeBranchCondition(branch_instr, opcode);
    888 }
    889 }  // namespace internal
    890 }  // namespace v8
    891 
    892 #endif  // V8_TARGET_ARCH_MIPS
    893