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