Home | History | Annotate | Download | only in mips
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 
     29 
     30 #include "v8.h"
     31 
     32 #if defined(V8_TARGET_ARCH_MIPS)
     33 
     34 #include "codegen.h"
     35 #include "code-stubs.h"
     36 #include "ic-inl.h"
     37 #include "runtime.h"
     38 #include "stub-cache.h"
     39 
     40 namespace v8 {
     41 namespace internal {
     42 
     43 
     44 // ----------------------------------------------------------------------------
     45 // Static IC stub generators.
     46 //
     47 
     48 #define __ ACCESS_MASM(masm)
     49 
     50 
     51 static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
     52                                             Register type,
     53                                             Label* global_object) {
     54   // Register usage:
     55   //   type: holds the receiver instance type on entry.
     56   __ Branch(global_object, eq, type, Operand(JS_GLOBAL_OBJECT_TYPE));
     57   __ Branch(global_object, eq, type, Operand(JS_BUILTINS_OBJECT_TYPE));
     58   __ Branch(global_object, eq, type, Operand(JS_GLOBAL_PROXY_TYPE));
     59 }
     60 
     61 
     62 // Generated code falls through if the receiver is a regular non-global
     63 // JS object with slow properties and no interceptors.
     64 static void GenerateStringDictionaryReceiverCheck(MacroAssembler* masm,
     65                                                   Register receiver,
     66                                                   Register elements,
     67                                                   Register scratch0,
     68                                                   Register scratch1,
     69                                                   Label* miss) {
     70   // Register usage:
     71   //   receiver: holds the receiver on entry and is unchanged.
     72   //   elements: holds the property dictionary on fall through.
     73   // Scratch registers:
     74   //   scratch0: used to holds the receiver map.
     75   //   scratch1: used to holds the receiver instance type, receiver bit mask
     76   //     and elements map.
     77 
     78   // Check that the receiver isn't a smi.
     79   __ JumpIfSmi(receiver, miss);
     80 
     81   // Check that the receiver is a valid JS object.
     82   __ GetObjectType(receiver, scratch0, scratch1);
     83   __ Branch(miss, lt, scratch1, Operand(FIRST_SPEC_OBJECT_TYPE));
     84 
     85   // If this assert fails, we have to check upper bound too.
     86   STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
     87 
     88   GenerateGlobalInstanceTypeCheck(masm, scratch1, miss);
     89 
     90   // Check that the global object does not require access checks.
     91   __ lbu(scratch1, FieldMemOperand(scratch0, Map::kBitFieldOffset));
     92   __ And(scratch1, scratch1, Operand((1 << Map::kIsAccessCheckNeeded) |
     93                            (1 << Map::kHasNamedInterceptor)));
     94   __ Branch(miss, ne, scratch1, Operand(zero_reg));
     95 
     96   __ lw(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
     97   __ lw(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
     98   __ LoadRoot(scratch0, Heap::kHashTableMapRootIndex);
     99   __ Branch(miss, ne, scratch1, Operand(scratch0));
    100 }
    101 
    102 
    103 // Helper function used from LoadIC/CallIC GenerateNormal.
    104 //
    105 // elements: Property dictionary. It is not clobbered if a jump to the miss
    106 //           label is done.
    107 // name:     Property name. It is not clobbered if a jump to the miss label is
    108 //           done
    109 // result:   Register for the result. It is only updated if a jump to the miss
    110 //           label is not done. Can be the same as elements or name clobbering
    111 //           one of these in the case of not jumping to the miss label.
    112 // The two scratch registers need to be different from elements, name and
    113 // result.
    114 // The generated code assumes that the receiver has slow properties,
    115 // is not a global object and does not have interceptors.
    116 // The address returned from GenerateStringDictionaryProbes() in scratch2
    117 // is used.
    118 static void GenerateDictionaryLoad(MacroAssembler* masm,
    119                                    Label* miss,
    120                                    Register elements,
    121                                    Register name,
    122                                    Register result,
    123                                    Register scratch1,
    124                                    Register scratch2) {
    125   // Main use of the scratch registers.
    126   // scratch1: Used as temporary and to hold the capacity of the property
    127   //           dictionary.
    128   // scratch2: Used as temporary.
    129   Label done;
    130 
    131   // Probe the dictionary.
    132   StringDictionaryLookupStub::GeneratePositiveLookup(masm,
    133                                                      miss,
    134                                                      &done,
    135                                                      elements,
    136                                                      name,
    137                                                      scratch1,
    138                                                      scratch2);
    139 
    140   // If probing finds an entry check that the value is a normal
    141   // property.
    142   __ bind(&done);  // scratch2 == elements + 4 * index.
    143   const int kElementsStartOffset = StringDictionary::kHeaderSize +
    144       StringDictionary::kElementsStartIndex * kPointerSize;
    145   const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
    146   __ lw(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
    147   __ And(at,
    148          scratch1,
    149          Operand(PropertyDetails::TypeField::kMask << kSmiTagSize));
    150   __ Branch(miss, ne, at, Operand(zero_reg));
    151 
    152   // Get the value at the masked, scaled index and return.
    153   __ lw(result,
    154         FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
    155 }
    156 
    157 
    158 // Helper function used from StoreIC::GenerateNormal.
    159 //
    160 // elements: Property dictionary. It is not clobbered if a jump to the miss
    161 //           label is done.
    162 // name:     Property name. It is not clobbered if a jump to the miss label is
    163 //           done
    164 // value:    The value to store.
    165 // The two scratch registers need to be different from elements, name and
    166 // result.
    167 // The generated code assumes that the receiver has slow properties,
    168 // is not a global object and does not have interceptors.
    169 // The address returned from GenerateStringDictionaryProbes() in scratch2
    170 // is used.
    171 static void GenerateDictionaryStore(MacroAssembler* masm,
    172                                     Label* miss,
    173                                     Register elements,
    174                                     Register name,
    175                                     Register value,
    176                                     Register scratch1,
    177                                     Register scratch2) {
    178   // Main use of the scratch registers.
    179   // scratch1: Used as temporary and to hold the capacity of the property
    180   //           dictionary.
    181   // scratch2: Used as temporary.
    182   Label done;
    183 
    184   // Probe the dictionary.
    185   StringDictionaryLookupStub::GeneratePositiveLookup(masm,
    186                                                      miss,
    187                                                      &done,
    188                                                      elements,
    189                                                      name,
    190                                                      scratch1,
    191                                                      scratch2);
    192 
    193   // If probing finds an entry in the dictionary check that the value
    194   // is a normal property that is not read only.
    195   __ bind(&done);  // scratch2 == elements + 4 * index.
    196   const int kElementsStartOffset = StringDictionary::kHeaderSize +
    197       StringDictionary::kElementsStartIndex * kPointerSize;
    198   const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
    199   const int kTypeAndReadOnlyMask =
    200       (PropertyDetails::TypeField::kMask |
    201        PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
    202   __ lw(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
    203   __ And(at, scratch1, Operand(kTypeAndReadOnlyMask));
    204   __ Branch(miss, ne, at, Operand(zero_reg));
    205 
    206   // Store the value at the masked, scaled index and return.
    207   const int kValueOffset = kElementsStartOffset + kPointerSize;
    208   __ Addu(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag));
    209   __ sw(value, MemOperand(scratch2));
    210 
    211   // Update the write barrier. Make sure not to clobber the value.
    212   __ mov(scratch1, value);
    213   __ RecordWrite(
    214       elements, scratch2, scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs);
    215 }
    216 
    217 
    218 void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
    219   // ----------- S t a t e -------------
    220   //  -- a2    : name
    221   //  -- ra    : return address
    222   //  -- a0    : receiver
    223   //  -- sp[0] : receiver
    224   // -----------------------------------
    225   Label miss;
    226 
    227   StubCompiler::GenerateLoadArrayLength(masm, a0, a3, &miss);
    228   __ bind(&miss);
    229   StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
    230 }
    231 
    232 
    233 void LoadIC::GenerateStringLength(MacroAssembler* masm, bool support_wrappers) {
    234   // ----------- S t a t e -------------
    235   //  -- a2    : name
    236   //  -- lr    : return address
    237   //  -- a0    : receiver
    238   //  -- sp[0] : receiver
    239   // -----------------------------------
    240   Label miss;
    241 
    242   StubCompiler::GenerateLoadStringLength(masm, a0, a1, a3, &miss,
    243                                          support_wrappers);
    244   // Cache miss: Jump to runtime.
    245   __ bind(&miss);
    246   StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
    247 }
    248 
    249 
    250 void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
    251   // ----------- S t a t e -------------
    252   //  -- a2    : name
    253   //  -- lr    : return address
    254   //  -- a0    : receiver
    255   //  -- sp[0] : receiver
    256   // -----------------------------------
    257   Label miss;
    258 
    259   StubCompiler::GenerateLoadFunctionPrototype(masm, a0, a1, a3, &miss);
    260   __ bind(&miss);
    261   StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
    262 }
    263 
    264 
    265 // Checks the receiver for special cases (value type, slow case bits).
    266 // Falls through for regular JS object.
    267 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
    268                                            Register receiver,
    269                                            Register map,
    270                                            Register scratch,
    271                                            int interceptor_bit,
    272                                            Label* slow) {
    273   // Check that the object isn't a smi.
    274   __ JumpIfSmi(receiver, slow);
    275   // Get the map of the receiver.
    276   __ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
    277   // Check bit field.
    278   __ lbu(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
    279   __ And(at, scratch, Operand(KeyedLoadIC::kSlowCaseBitFieldMask));
    280   __ Branch(slow, ne, at, Operand(zero_reg));
    281   // Check that the object is some kind of JS object EXCEPT JS Value type.
    282   // In the case that the object is a value-wrapper object,
    283   // we enter the runtime system to make sure that indexing into string
    284   // objects work as intended.
    285   ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
    286   __ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
    287   __ Branch(slow, lt, scratch, Operand(JS_OBJECT_TYPE));
    288 }
    289 
    290 
    291 // Loads an indexed element from a fast case array.
    292 // If not_fast_array is NULL, doesn't perform the elements map check.
    293 static void GenerateFastArrayLoad(MacroAssembler* masm,
    294                                   Register receiver,
    295                                   Register key,
    296                                   Register elements,
    297                                   Register scratch1,
    298                                   Register scratch2,
    299                                   Register result,
    300                                   Label* not_fast_array,
    301                                   Label* out_of_range) {
    302   // Register use:
    303   //
    304   // receiver - holds the receiver on entry.
    305   //            Unchanged unless 'result' is the same register.
    306   //
    307   // key      - holds the smi key on entry.
    308   //            Unchanged unless 'result' is the same register.
    309   //
    310   // elements - holds the elements of the receiver on exit.
    311   //
    312   // result   - holds the result on exit if the load succeeded.
    313   //            Allowed to be the the same as 'receiver' or 'key'.
    314   //            Unchanged on bailout so 'receiver' and 'key' can be safely
    315   //            used by further computation.
    316   //
    317   // Scratch registers:
    318   //
    319   // scratch1 - used to hold elements map and elements length.
    320   //            Holds the elements map if not_fast_array branch is taken.
    321   //
    322   // scratch2 - used to hold the loaded value.
    323 
    324   __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
    325   if (not_fast_array != NULL) {
    326     // Check that the object is in fast mode (not dictionary).
    327     __ lw(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
    328     __ LoadRoot(at, Heap::kFixedArrayMapRootIndex);
    329     __ Branch(not_fast_array, ne, scratch1, Operand(at));
    330   } else {
    331     __ AssertFastElements(elements);
    332   }
    333 
    334   // Check that the key (index) is within bounds.
    335   __ lw(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset));
    336   __ Branch(out_of_range, hs, key, Operand(scratch1));
    337 
    338   // Fast case: Do the load.
    339   __ Addu(scratch1, elements,
    340           Operand(FixedArray::kHeaderSize - kHeapObjectTag));
    341   // The key is a smi.
    342   STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
    343   __ sll(at, key, kPointerSizeLog2 - kSmiTagSize);
    344   __ addu(at, at, scratch1);
    345   __ lw(scratch2, MemOperand(at));
    346 
    347   __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
    348   // In case the loaded value is the_hole we have to consult GetProperty
    349   // to ensure the prototype chain is searched.
    350   __ Branch(out_of_range, eq, scratch2, Operand(at));
    351   __ mov(result, scratch2);
    352 }
    353 
    354 
    355 // Checks whether a key is an array index string or a symbol string.
    356 // Falls through if a key is a symbol.
    357 static void GenerateKeyStringCheck(MacroAssembler* masm,
    358                                    Register key,
    359                                    Register map,
    360                                    Register hash,
    361                                    Label* index_string,
    362                                    Label* not_symbol) {
    363   // The key is not a smi.
    364   // Is it a string?
    365   __ GetObjectType(key, map, hash);
    366   __ Branch(not_symbol, ge, hash, Operand(FIRST_NONSTRING_TYPE));
    367 
    368   // Is the string an array index, with cached numeric value?
    369   __ lw(hash, FieldMemOperand(key, String::kHashFieldOffset));
    370   __ And(at, hash, Operand(String::kContainsCachedArrayIndexMask));
    371   __ Branch(index_string, eq, at, Operand(zero_reg));
    372 
    373   // Is the string a symbol?
    374   // map: key map
    375   __ lbu(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
    376   STATIC_ASSERT(kSymbolTag != 0);
    377   __ And(at, hash, Operand(kIsSymbolMask));
    378   __ Branch(not_symbol, eq, at, Operand(zero_reg));
    379 }
    380 
    381 
    382 // Defined in ic.cc.
    383 Object* CallIC_Miss(Arguments args);
    384 
    385 // The generated code does not accept smi keys.
    386 // The generated code falls through if both probes miss.
    387 void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm,
    388                                                int argc,
    389                                                Code::Kind kind,
    390                                                Code::ExtraICState extra_state) {
    391   // ----------- S t a t e -------------
    392   //  -- a1    : receiver
    393   //  -- a2    : name
    394   // -----------------------------------
    395   Label number, non_number, non_string, boolean, probe, miss;
    396 
    397   // Probe the stub cache.
    398   Code::Flags flags = Code::ComputeFlags(kind,
    399                                          MONOMORPHIC,
    400                                          extra_state,
    401                                          NORMAL,
    402                                          argc);
    403   Isolate::Current()->stub_cache()->GenerateProbe(
    404       masm, flags, a1, a2, a3, t0, t1, t2);
    405 
    406   // If the stub cache probing failed, the receiver might be a value.
    407   // For value objects, we use the map of the prototype objects for
    408   // the corresponding JSValue for the cache and that is what we need
    409   // to probe.
    410   //
    411   // Check for number.
    412   __ JumpIfSmi(a1, &number, t1);
    413   __ GetObjectType(a1, a3, a3);
    414   __ Branch(&non_number, ne, a3, Operand(HEAP_NUMBER_TYPE));
    415   __ bind(&number);
    416   StubCompiler::GenerateLoadGlobalFunctionPrototype(
    417       masm, Context::NUMBER_FUNCTION_INDEX, a1);
    418   __ Branch(&probe);
    419 
    420   // Check for string.
    421   __ bind(&non_number);
    422   __ Branch(&non_string, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
    423   StubCompiler::GenerateLoadGlobalFunctionPrototype(
    424       masm, Context::STRING_FUNCTION_INDEX, a1);
    425   __ Branch(&probe);
    426 
    427   // Check for boolean.
    428   __ bind(&non_string);
    429   __ LoadRoot(t0, Heap::kTrueValueRootIndex);
    430   __ Branch(&boolean, eq, a1, Operand(t0));
    431   __ LoadRoot(t1, Heap::kFalseValueRootIndex);
    432   __ Branch(&miss, ne, a1, Operand(t1));
    433   __ bind(&boolean);
    434   StubCompiler::GenerateLoadGlobalFunctionPrototype(
    435       masm, Context::BOOLEAN_FUNCTION_INDEX, a1);
    436 
    437   // Probe the stub cache for the value object.
    438   __ bind(&probe);
    439   Isolate::Current()->stub_cache()->GenerateProbe(
    440       masm, flags, a1, a2, a3, t0, t1, t2);
    441 
    442   __ bind(&miss);
    443 }
    444 
    445 
    446 static void GenerateFunctionTailCall(MacroAssembler* masm,
    447                                      int argc,
    448                                      Label* miss,
    449                                      Register scratch) {
    450   // a1: function
    451 
    452   // Check that the value isn't a smi.
    453   __ JumpIfSmi(a1, miss);
    454 
    455   // Check that the value is a JSFunction.
    456   __ GetObjectType(a1, scratch, scratch);
    457   __ Branch(miss, ne, scratch, Operand(JS_FUNCTION_TYPE));
    458 
    459   // Invoke the function.
    460   ParameterCount actual(argc);
    461   __ InvokeFunction(a1, actual, JUMP_FUNCTION,
    462                     NullCallWrapper(), CALL_AS_METHOD);
    463 }
    464 
    465 
    466 void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) {
    467   // ----------- S t a t e -------------
    468   //  -- a2    : name
    469   //  -- ra    : return address
    470   // -----------------------------------
    471   Label miss;
    472 
    473   // Get the receiver of the function from the stack into a1.
    474   __ lw(a1, MemOperand(sp, argc * kPointerSize));
    475 
    476   GenerateStringDictionaryReceiverCheck(masm, a1, a0, a3, t0, &miss);
    477 
    478   // a0: elements
    479   // Search the dictionary - put result in register a1.
    480   GenerateDictionaryLoad(masm, &miss, a0, a2, a1, a3, t0);
    481 
    482   GenerateFunctionTailCall(masm, argc, &miss, t0);
    483 
    484   // Cache miss: Jump to runtime.
    485   __ bind(&miss);
    486 }
    487 
    488 
    489 void CallICBase::GenerateMiss(MacroAssembler* masm,
    490                               int argc,
    491                               IC::UtilityId id,
    492                               Code::ExtraICState extra_state) {
    493   // ----------- S t a t e -------------
    494   //  -- a2    : name
    495   //  -- ra    : return address
    496   // -----------------------------------
    497   Isolate* isolate = masm->isolate();
    498 
    499   if (id == IC::kCallIC_Miss) {
    500     __ IncrementCounter(isolate->counters()->call_miss(), 1, a3, t0);
    501   } else {
    502     __ IncrementCounter(isolate->counters()->keyed_call_miss(), 1, a3, t0);
    503   }
    504 
    505   // Get the receiver of the function from the stack.
    506   __ lw(a3, MemOperand(sp, argc*kPointerSize));
    507 
    508   {
    509     FrameScope scope(masm, StackFrame::INTERNAL);
    510 
    511     // Push the receiver and the name of the function.
    512     __ Push(a3, a2);
    513 
    514     // Call the entry.
    515     __ PrepareCEntryArgs(2);
    516     __ PrepareCEntryFunction(ExternalReference(IC_Utility(id), isolate));
    517 
    518     CEntryStub stub(1);
    519     __ CallStub(&stub);
    520 
    521     // Move result to a1 and leave the internal frame.
    522     __ mov(a1, v0);
    523   }
    524 
    525   // Check if the receiver is a global object of some sort.
    526   // This can happen only for regular CallIC but not KeyedCallIC.
    527   if (id == IC::kCallIC_Miss) {
    528     Label invoke, global;
    529     __ lw(a2, MemOperand(sp, argc * kPointerSize));
    530     __ JumpIfSmi(a2, &invoke);
    531     __ GetObjectType(a2, a3, a3);
    532     __ Branch(&global, eq, a3, Operand(JS_GLOBAL_OBJECT_TYPE));
    533     __ Branch(&invoke, ne, a3, Operand(JS_BUILTINS_OBJECT_TYPE));
    534 
    535     // Patch the receiver on the stack.
    536     __ bind(&global);
    537     __ lw(a2, FieldMemOperand(a2, GlobalObject::kGlobalReceiverOffset));
    538     __ sw(a2, MemOperand(sp, argc * kPointerSize));
    539     __ bind(&invoke);
    540   }
    541   // Invoke the function.
    542   CallKind call_kind = CallICBase::Contextual::decode(extra_state)
    543       ? CALL_AS_FUNCTION
    544       : CALL_AS_METHOD;
    545   ParameterCount actual(argc);
    546   __ InvokeFunction(a1,
    547                     actual,
    548                     JUMP_FUNCTION,
    549                     NullCallWrapper(),
    550                     call_kind);
    551 }
    552 
    553 
    554 void CallIC::GenerateMegamorphic(MacroAssembler* masm,
    555                                  int argc,
    556                                  Code::ExtraICState extra_ic_state) {
    557   // ----------- S t a t e -------------
    558   //  -- a2    : name
    559   //  -- ra    : return address
    560   // -----------------------------------
    561 
    562   // Get the receiver of the function from the stack into a1.
    563   __ lw(a1, MemOperand(sp, argc * kPointerSize));
    564   GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, extra_ic_state);
    565   GenerateMiss(masm, argc, extra_ic_state);
    566 }
    567 
    568 
    569 void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
    570   // ----------- S t a t e -------------
    571   //  -- a2    : name
    572   //  -- ra    : return address
    573   // -----------------------------------
    574 
    575   // Get the receiver of the function from the stack into a1.
    576   __ lw(a1, MemOperand(sp, argc * kPointerSize));
    577 
    578   Label do_call, slow_call, slow_load, slow_reload_receiver;
    579   Label check_number_dictionary, check_string, lookup_monomorphic_cache;
    580   Label index_smi, index_string;
    581 
    582   // Check that the key is a smi.
    583   __ JumpIfNotSmi(a2, &check_string);
    584   __ bind(&index_smi);
    585   // Now the key is known to be a smi. This place is also jumped to from below
    586   // where a numeric string is converted to a smi.
    587 
    588   GenerateKeyedLoadReceiverCheck(
    589       masm, a1, a0, a3, Map::kHasIndexedInterceptor, &slow_call);
    590 
    591   GenerateFastArrayLoad(
    592       masm, a1, a2, t0, a3, a0, a1, &check_number_dictionary, &slow_load);
    593   Counters* counters = masm->isolate()->counters();
    594   __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1, a0, a3);
    595 
    596   __ bind(&do_call);
    597   // receiver in a1 is not used after this point.
    598   // a2: key
    599   // a1: function
    600 
    601   GenerateFunctionTailCall(masm, argc, &slow_call, a0);
    602 
    603   __ bind(&check_number_dictionary);
    604   // a2: key
    605   // a3: elements map
    606   // t0: elements pointer
    607   // Check whether the elements is a number dictionary.
    608   __ LoadRoot(at, Heap::kHashTableMapRootIndex);
    609   __ Branch(&slow_load, ne, a3, Operand(at));
    610   __ sra(a0, a2, kSmiTagSize);
    611   // a0: untagged index
    612   __ LoadFromNumberDictionary(&slow_load, t0, a2, a1, a0, a3, t1);
    613   __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1, a0, a3);
    614   __ jmp(&do_call);
    615 
    616   __ bind(&slow_load);
    617   // This branch is taken when calling KeyedCallIC_Miss is neither required
    618   // nor beneficial.
    619   __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1, a0, a3);
    620   {
    621     FrameScope scope(masm, StackFrame::INTERNAL);
    622     __ push(a2);  // Save the key.
    623     __ Push(a1, a2);  // Pass the receiver and the key.
    624     __ CallRuntime(Runtime::kKeyedGetProperty, 2);
    625     __ pop(a2);  // Restore the key.
    626   }
    627   __ mov(a1, v0);
    628   __ jmp(&do_call);
    629 
    630   __ bind(&check_string);
    631   GenerateKeyStringCheck(masm, a2, a0, a3, &index_string, &slow_call);
    632 
    633   // The key is known to be a symbol.
    634   // If the receiver is a regular JS object with slow properties then do
    635   // a quick inline probe of the receiver's dictionary.
    636   // Otherwise do the monomorphic cache probe.
    637   GenerateKeyedLoadReceiverCheck(
    638       masm, a1, a0, a3, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
    639 
    640   __ lw(a0, FieldMemOperand(a1, JSObject::kPropertiesOffset));
    641   __ lw(a3, FieldMemOperand(a0, HeapObject::kMapOffset));
    642   __ LoadRoot(at, Heap::kHashTableMapRootIndex);
    643   __ Branch(&lookup_monomorphic_cache, ne, a3, Operand(at));
    644 
    645   GenerateDictionaryLoad(masm, &slow_load, a0, a2, a1, a3, t0);
    646   __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1, a0, a3);
    647   __ jmp(&do_call);
    648 
    649   __ bind(&lookup_monomorphic_cache);
    650   __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1, a0, a3);
    651   GenerateMonomorphicCacheProbe(masm,
    652                                 argc,
    653                                 Code::KEYED_CALL_IC,
    654                                 Code::kNoExtraICState);
    655   // Fall through on miss.
    656 
    657   __ bind(&slow_call);
    658   // This branch is taken if:
    659   // - the receiver requires boxing or access check,
    660   // - the key is neither smi nor symbol,
    661   // - the value loaded is not a function,
    662   // - there is hope that the runtime will create a monomorphic call stub,
    663   //   that will get fetched next time.
    664   __ IncrementCounter(counters->keyed_call_generic_slow(), 1, a0, a3);
    665   GenerateMiss(masm, argc);
    666 
    667   __ bind(&index_string);
    668   __ IndexFromHash(a3, a2);
    669   // Now jump to the place where smi keys are handled.
    670   __ jmp(&index_smi);
    671 }
    672 
    673 
    674 void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
    675   // ----------- S t a t e -------------
    676   //  -- a2    : name
    677   //  -- ra    : return address
    678   // -----------------------------------
    679 
    680   // Check if the name is a string.
    681   Label miss;
    682   __ JumpIfSmi(a2, &miss);
    683   __ IsObjectJSStringType(a2, a0, &miss);
    684 
    685   CallICBase::GenerateNormal(masm, argc);
    686   __ bind(&miss);
    687   GenerateMiss(masm, argc);
    688 }
    689 
    690 
    691 // Defined in ic.cc.
    692 Object* LoadIC_Miss(Arguments args);
    693 
    694 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
    695   // ----------- S t a t e -------------
    696   //  -- a2    : name
    697   //  -- ra    : return address
    698   //  -- a0    : receiver
    699   //  -- sp[0] : receiver
    700   // -----------------------------------
    701 
    702   // Probe the stub cache.
    703   Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
    704   Isolate::Current()->stub_cache()->GenerateProbe(
    705       masm, flags, a0, a2, a3, t0, t1, t2);
    706 
    707   // Cache miss: Jump to runtime.
    708   GenerateMiss(masm);
    709 }
    710 
    711 
    712 void LoadIC::GenerateNormal(MacroAssembler* masm) {
    713   // ----------- S t a t e -------------
    714   //  -- a2    : name
    715   //  -- lr    : return address
    716   //  -- a0    : receiver
    717   //  -- sp[0] : receiver
    718   // -----------------------------------
    719   Label miss;
    720 
    721   GenerateStringDictionaryReceiverCheck(masm, a0, a1, a3, t0, &miss);
    722 
    723   // a1: elements
    724   GenerateDictionaryLoad(masm, &miss, a1, a2, v0, a3, t0);
    725   __ Ret();
    726 
    727   // Cache miss: Jump to runtime.
    728   __ bind(&miss);
    729   GenerateMiss(masm);
    730 }
    731 
    732 
    733 void LoadIC::GenerateMiss(MacroAssembler* masm) {
    734   // ----------- S t a t e -------------
    735   //  -- a2    : name
    736   //  -- ra    : return address
    737   //  -- a0    : receiver
    738   //  -- sp[0] : receiver
    739   // -----------------------------------
    740   Isolate* isolate = masm->isolate();
    741 
    742   __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, a3, t0);
    743 
    744   __ mov(a3, a0);
    745   __ Push(a3, a2);
    746 
    747   // Perform tail call to the entry.
    748   ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss), isolate);
    749   __ TailCallExternalReference(ref, 2, 1);
    750 }
    751 
    752 
    753 static MemOperand GenerateMappedArgumentsLookup(MacroAssembler* masm,
    754                                                 Register object,
    755                                                 Register key,
    756                                                 Register scratch1,
    757                                                 Register scratch2,
    758                                                 Register scratch3,
    759                                                 Label* unmapped_case,
    760                                                 Label* slow_case) {
    761   // Check that the receiver is a JSObject. Because of the map check
    762   // later, we do not need to check for interceptors or whether it
    763   // requires access checks.
    764   __ JumpIfSmi(object, slow_case);
    765   // Check that the object is some kind of JSObject.
    766   __ GetObjectType(object, scratch1, scratch2);
    767   __ Branch(slow_case, lt, scratch2, Operand(FIRST_JS_RECEIVER_TYPE));
    768 
    769   // Check that the key is a positive smi.
    770   __ And(scratch1, key, Operand(0x80000001));
    771   __ Branch(slow_case, ne, scratch1, Operand(zero_reg));
    772 
    773   // Load the elements into scratch1 and check its map.
    774   __ lw(scratch1, FieldMemOperand(object, JSObject::kElementsOffset));
    775   __ CheckMap(scratch1,
    776               scratch2,
    777               Heap::kNonStrictArgumentsElementsMapRootIndex,
    778               slow_case,
    779               DONT_DO_SMI_CHECK);
    780   // Check if element is in the range of mapped arguments. If not, jump
    781   // to the unmapped lookup with the parameter map in scratch1.
    782   __ lw(scratch2, FieldMemOperand(scratch1, FixedArray::kLengthOffset));
    783   __ Subu(scratch2, scratch2, Operand(Smi::FromInt(2)));
    784   __ Branch(unmapped_case, Ugreater_equal, key, Operand(scratch2));
    785 
    786   // Load element index and check whether it is the hole.
    787   const int kOffset =
    788       FixedArray::kHeaderSize + 2 * kPointerSize - kHeapObjectTag;
    789 
    790   __ li(scratch3, Operand(kPointerSize >> 1));
    791   __ Mul(scratch3, key, scratch3);
    792   __ Addu(scratch3, scratch3, Operand(kOffset));
    793 
    794   __ Addu(scratch2, scratch1, scratch3);
    795   __ lw(scratch2, MemOperand(scratch2));
    796   __ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex);
    797   __ Branch(unmapped_case, eq, scratch2, Operand(scratch3));
    798 
    799   // Load value from context and return it. We can reuse scratch1 because
    800   // we do not jump to the unmapped lookup (which requires the parameter
    801   // map in scratch1).
    802   __ lw(scratch1, FieldMemOperand(scratch1, FixedArray::kHeaderSize));
    803   __ li(scratch3, Operand(kPointerSize >> 1));
    804   __ Mul(scratch3, scratch2, scratch3);
    805   __ Addu(scratch3, scratch3, Operand(Context::kHeaderSize - kHeapObjectTag));
    806   __ Addu(scratch2, scratch1, scratch3);
    807   return MemOperand(scratch2);
    808 }
    809 
    810 
    811 static MemOperand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
    812                                                   Register key,
    813                                                   Register parameter_map,
    814                                                   Register scratch,
    815                                                   Label* slow_case) {
    816   // Element is in arguments backing store, which is referenced by the
    817   // second element of the parameter_map. The parameter_map register
    818   // must be loaded with the parameter map of the arguments object and is
    819   // overwritten.
    820   const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
    821   Register backing_store = parameter_map;
    822   __ lw(backing_store, FieldMemOperand(parameter_map, kBackingStoreOffset));
    823   __ CheckMap(backing_store,
    824               scratch,
    825               Heap::kFixedArrayMapRootIndex,
    826               slow_case,
    827               DONT_DO_SMI_CHECK);
    828   __ lw(scratch, FieldMemOperand(backing_store, FixedArray::kLengthOffset));
    829   __ Branch(slow_case, Ugreater_equal, key, Operand(scratch));
    830   __ li(scratch, Operand(kPointerSize >> 1));
    831   __ Mul(scratch, key, scratch);
    832   __ Addu(scratch,
    833           scratch,
    834           Operand(FixedArray::kHeaderSize - kHeapObjectTag));
    835   __ Addu(scratch, backing_store, scratch);
    836   return MemOperand(scratch);
    837 }
    838 
    839 
    840 void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) {
    841   // ---------- S t a t e --------------
    842   //  -- lr     : return address
    843   //  -- a0     : key
    844   //  -- a1     : receiver
    845   // -----------------------------------
    846   Label slow, notin;
    847   MemOperand mapped_location =
    848       GenerateMappedArgumentsLookup(masm, a1, a0, a2, a3, t0, &notin, &slow);
    849   __ Ret(USE_DELAY_SLOT);
    850   __ lw(v0, mapped_location);
    851   __ bind(&notin);
    852   // The unmapped lookup expects that the parameter map is in a2.
    853   MemOperand unmapped_location =
    854       GenerateUnmappedArgumentsLookup(masm, a0, a2, a3, &slow);
    855   __ lw(a2, unmapped_location);
    856   __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
    857   __ Branch(&slow, eq, a2, Operand(a3));
    858   __ Ret(USE_DELAY_SLOT);
    859   __ mov(v0, a2);
    860   __ bind(&slow);
    861   GenerateMiss(masm, false);
    862 }
    863 
    864 
    865 void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) {
    866   // ---------- S t a t e --------------
    867   //  -- a0     : value
    868   //  -- a1     : key
    869   //  -- a2     : receiver
    870   //  -- lr     : return address
    871   // -----------------------------------
    872   Label slow, notin;
    873   // Store address is returned in register (of MemOperand) mapped_location.
    874   MemOperand mapped_location =
    875       GenerateMappedArgumentsLookup(masm, a2, a1, a3, t0, t1, &notin, &slow);
    876   __ sw(a0, mapped_location);
    877   __ mov(t5, a0);
    878   ASSERT_EQ(mapped_location.offset(), 0);
    879   __ RecordWrite(a3, mapped_location.rm(), t5,
    880                  kRAHasNotBeenSaved, kDontSaveFPRegs);
    881   __ Ret(USE_DELAY_SLOT);
    882   __ mov(v0, a0);  // (In delay slot) return the value stored in v0.
    883   __ bind(&notin);
    884   // The unmapped lookup expects that the parameter map is in a3.
    885   // Store address is returned in register (of MemOperand) unmapped_location.
    886   MemOperand unmapped_location =
    887       GenerateUnmappedArgumentsLookup(masm, a1, a3, t0, &slow);
    888   __ sw(a0, unmapped_location);
    889   __ mov(t5, a0);
    890   ASSERT_EQ(unmapped_location.offset(), 0);
    891   __ RecordWrite(a3, unmapped_location.rm(), t5,
    892                  kRAHasNotBeenSaved, kDontSaveFPRegs);
    893   __ Ret(USE_DELAY_SLOT);
    894   __ mov(v0, a0);  // (In delay slot) return the value stored in v0.
    895   __ bind(&slow);
    896   GenerateMiss(masm, false);
    897 }
    898 
    899 
    900 void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm,
    901                                              int argc) {
    902   // ----------- S t a t e -------------
    903   //  -- a2    : name
    904   //  -- lr    : return address
    905   // -----------------------------------
    906   Label slow, notin;
    907   // Load receiver.
    908   __ lw(a1, MemOperand(sp, argc * kPointerSize));
    909   MemOperand mapped_location =
    910       GenerateMappedArgumentsLookup(masm, a1, a2, a3, t0, t1, &notin, &slow);
    911   __ lw(a1, mapped_location);
    912   GenerateFunctionTailCall(masm, argc, &slow, a3);
    913   __ bind(&notin);
    914   // The unmapped lookup expects that the parameter map is in a3.
    915   MemOperand unmapped_location =
    916       GenerateUnmappedArgumentsLookup(masm, a2, a3, t0, &slow);
    917   __ lw(a1, unmapped_location);
    918   __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
    919   __ Branch(&slow, eq, a1, Operand(a3));
    920   GenerateFunctionTailCall(masm, argc, &slow, a3);
    921   __ bind(&slow);
    922   GenerateMiss(masm, argc);
    923 }
    924 
    925 
    926 Object* KeyedLoadIC_Miss(Arguments args);
    927 
    928 
    929 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
    930   // ---------- S t a t e --------------
    931   //  -- ra     : return address
    932   //  -- a0     : key
    933   //  -- a1     : receiver
    934   // -----------------------------------
    935   Isolate* isolate = masm->isolate();
    936 
    937   __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, a3, t0);
    938 
    939   __ Push(a1, a0);
    940 
    941   // Perform tail call to the entry.
    942   ExternalReference ref = force_generic
    943       ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric), isolate)
    944       : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
    945 
    946   __ TailCallExternalReference(ref, 2, 1);
    947 }
    948 
    949 
    950 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
    951   // ---------- S t a t e --------------
    952   //  -- ra     : return address
    953   //  -- a0     : key
    954   //  -- a1     : receiver
    955   // -----------------------------------
    956 
    957   __ Push(a1, a0);
    958 
    959   __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
    960 }
    961 
    962 
    963 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
    964   // ---------- S t a t e --------------
    965   //  -- ra     : return address
    966   //  -- a0     : key
    967   //  -- a1     : receiver
    968   // -----------------------------------
    969   Label slow, check_string, index_smi, index_string, property_array_property;
    970   Label probe_dictionary, check_number_dictionary;
    971 
    972   Register key = a0;
    973   Register receiver = a1;
    974 
    975   Isolate* isolate = masm->isolate();
    976 
    977   // Check that the key is a smi.
    978   __ JumpIfNotSmi(key, &check_string);
    979   __ bind(&index_smi);
    980   // Now the key is known to be a smi. This place is also jumped to from below
    981   // where a numeric string is converted to a smi.
    982 
    983   GenerateKeyedLoadReceiverCheck(
    984       masm, receiver, a2, a3, Map::kHasIndexedInterceptor, &slow);
    985 
    986   // Check the receiver's map to see if it has fast elements.
    987   __ CheckFastElements(a2, a3, &check_number_dictionary);
    988 
    989   GenerateFastArrayLoad(
    990       masm, receiver, key, t0, a3, a2, v0, NULL, &slow);
    991 
    992   __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, a2, a3);
    993   __ Ret();
    994 
    995   __ bind(&check_number_dictionary);
    996   __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
    997   __ lw(a3, FieldMemOperand(t0, JSObject::kMapOffset));
    998 
    999   // Check whether the elements is a number dictionary.
   1000   // a0: key
   1001   // a3: elements map
   1002   // t0: elements
   1003   __ LoadRoot(at, Heap::kHashTableMapRootIndex);
   1004   __ Branch(&slow, ne, a3, Operand(at));
   1005   __ sra(a2, a0, kSmiTagSize);
   1006   __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
   1007   __ Ret();
   1008 
   1009   // Slow case, key and receiver still in a0 and a1.
   1010   __ bind(&slow);
   1011   __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(),
   1012                       1,
   1013                       a2,
   1014                       a3);
   1015   GenerateRuntimeGetProperty(masm);
   1016 
   1017   __ bind(&check_string);
   1018   GenerateKeyStringCheck(masm, key, a2, a3, &index_string, &slow);
   1019 
   1020   GenerateKeyedLoadReceiverCheck(
   1021        masm, receiver, a2, a3, Map::kHasIndexedInterceptor, &slow);
   1022 
   1023 
   1024   // If the receiver is a fast-case object, check the keyed lookup
   1025   // cache. Otherwise probe the dictionary.
   1026   __ lw(a3, FieldMemOperand(a1, JSObject::kPropertiesOffset));
   1027   __ lw(t0, FieldMemOperand(a3, HeapObject::kMapOffset));
   1028   __ LoadRoot(at, Heap::kHashTableMapRootIndex);
   1029   __ Branch(&probe_dictionary, eq, t0, Operand(at));
   1030 
   1031   // Load the map of the receiver, compute the keyed lookup cache hash
   1032   // based on 32 bits of the map pointer and the string hash.
   1033   __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
   1034   __ sra(a3, a2, KeyedLookupCache::kMapHashShift);
   1035   __ lw(t0, FieldMemOperand(a0, String::kHashFieldOffset));
   1036   __ sra(at, t0, String::kHashShift);
   1037   __ xor_(a3, a3, at);
   1038   int mask = KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask;
   1039   __ And(a3, a3, Operand(mask));
   1040 
   1041   // Load the key (consisting of map and symbol) from the cache and
   1042   // check for match.
   1043   Label load_in_object_property;
   1044   static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
   1045   Label hit_on_nth_entry[kEntriesPerBucket];
   1046   ExternalReference cache_keys =
   1047       ExternalReference::keyed_lookup_cache_keys(isolate);
   1048   __ li(t0, Operand(cache_keys));
   1049   __ sll(at, a3, kPointerSizeLog2 + 1);
   1050   __ addu(t0, t0, at);
   1051 
   1052   for (int i = 0; i < kEntriesPerBucket - 1; i++) {
   1053     Label try_next_entry;
   1054     __ lw(t1, MemOperand(t0, kPointerSize * i * 2));
   1055     __ Branch(&try_next_entry, ne, a2, Operand(t1));
   1056     __ lw(t1, MemOperand(t0, kPointerSize * (i * 2 + 1)));
   1057     __ Branch(&hit_on_nth_entry[i], eq, a0, Operand(t1));
   1058     __ bind(&try_next_entry);
   1059   }
   1060 
   1061   __ lw(t1, MemOperand(t0, kPointerSize * (kEntriesPerBucket - 1) * 2));
   1062   __ Branch(&slow, ne, a2, Operand(t1));
   1063   __ lw(t1, MemOperand(t0, kPointerSize * ((kEntriesPerBucket - 1) * 2 + 1)));
   1064   __ Branch(&slow, ne, a0, Operand(t1));
   1065 
   1066   // Get field offset.
   1067   // a0     : key
   1068   // a1     : receiver
   1069   // a2     : receiver's map
   1070   // a3     : lookup cache index
   1071   ExternalReference cache_field_offsets =
   1072       ExternalReference::keyed_lookup_cache_field_offsets(isolate);
   1073 
   1074   // Hit on nth entry.
   1075   for (int i = kEntriesPerBucket - 1; i >= 0; i--) {
   1076     __ bind(&hit_on_nth_entry[i]);
   1077     __ li(t0, Operand(cache_field_offsets));
   1078     __ sll(at, a3, kPointerSizeLog2);
   1079     __ addu(at, t0, at);
   1080     __ lw(t1, MemOperand(at, kPointerSize * i));
   1081     __ lbu(t2, FieldMemOperand(a2, Map::kInObjectPropertiesOffset));
   1082     __ Subu(t1, t1, t2);
   1083     __ Branch(&property_array_property, ge, t1, Operand(zero_reg));
   1084     if (i != 0) {
   1085       __ Branch(&load_in_object_property);
   1086     }
   1087   }
   1088 
   1089   // Load in-object property.
   1090   __ bind(&load_in_object_property);
   1091   __ lbu(t2, FieldMemOperand(a2, Map::kInstanceSizeOffset));
   1092   __ addu(t2, t2, t1);  // Index from start of object.
   1093   __ Subu(a1, a1, Operand(kHeapObjectTag));  // Remove the heap tag.
   1094   __ sll(at, t2, kPointerSizeLog2);
   1095   __ addu(at, a1, at);
   1096   __ lw(v0, MemOperand(at));
   1097   __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
   1098                       1,
   1099                       a2,
   1100                       a3);
   1101   __ Ret();
   1102 
   1103   // Load property array property.
   1104   __ bind(&property_array_property);
   1105   __ lw(a1, FieldMemOperand(a1, JSObject::kPropertiesOffset));
   1106   __ Addu(a1, a1, FixedArray::kHeaderSize - kHeapObjectTag);
   1107   __ sll(t0, t1, kPointerSizeLog2);
   1108   __ Addu(t0, t0, a1);
   1109   __ lw(v0, MemOperand(t0));
   1110   __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
   1111                       1,
   1112                       a2,
   1113                       a3);
   1114   __ Ret();
   1115 
   1116 
   1117   // Do a quick inline probe of the receiver's dictionary, if it
   1118   // exists.
   1119   __ bind(&probe_dictionary);
   1120   // a1: receiver
   1121   // a0: key
   1122   // a3: elements
   1123   __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
   1124   __ lbu(a2, FieldMemOperand(a2, Map::kInstanceTypeOffset));
   1125   GenerateGlobalInstanceTypeCheck(masm, a2, &slow);
   1126   // Load the property to v0.
   1127   GenerateDictionaryLoad(masm, &slow, a3, a0, v0, a2, t0);
   1128   __ IncrementCounter(isolate->counters()->keyed_load_generic_symbol(),
   1129                       1,
   1130                       a2,
   1131                       a3);
   1132   __ Ret();
   1133 
   1134   __ bind(&index_string);
   1135   __ IndexFromHash(a3, key);
   1136   // Now jump to the place where smi keys are handled.
   1137   __ Branch(&index_smi);
   1138 }
   1139 
   1140 
   1141 void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
   1142   // ---------- S t a t e --------------
   1143   //  -- ra     : return address
   1144   //  -- a0     : key (index)
   1145   //  -- a1     : receiver
   1146   // -----------------------------------
   1147   Label miss;
   1148 
   1149   Register receiver = a1;
   1150   Register index = a0;
   1151   Register scratch = a3;
   1152   Register result = v0;
   1153 
   1154   StringCharAtGenerator char_at_generator(receiver,
   1155                                           index,
   1156                                           scratch,
   1157                                           result,
   1158                                           &miss,  // When not a string.
   1159                                           &miss,  // When not a number.
   1160                                           &miss,  // When index out of range.
   1161                                           STRING_INDEX_IS_ARRAY_INDEX);
   1162   char_at_generator.GenerateFast(masm);
   1163   __ Ret();
   1164 
   1165   StubRuntimeCallHelper call_helper;
   1166   char_at_generator.GenerateSlow(masm, call_helper);
   1167 
   1168   __ bind(&miss);
   1169   GenerateMiss(masm, false);
   1170 }
   1171 
   1172 
   1173 void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
   1174                                               StrictModeFlag strict_mode) {
   1175   // ---------- S t a t e --------------
   1176   //  -- a0     : value
   1177   //  -- a1     : key
   1178   //  -- a2     : receiver
   1179   //  -- ra     : return address
   1180   // -----------------------------------
   1181 
   1182   // Push receiver, key and value for runtime call.
   1183   __ Push(a2, a1, a0);
   1184   __ li(a1, Operand(Smi::FromInt(NONE)));          // PropertyAttributes.
   1185   __ li(a0, Operand(Smi::FromInt(strict_mode)));   // Strict mode.
   1186   __ Push(a1, a0);
   1187 
   1188   __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
   1189 }
   1190 
   1191 
   1192 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
   1193                                    StrictModeFlag strict_mode) {
   1194   // ---------- S t a t e --------------
   1195   //  -- a0     : value
   1196   //  -- a1     : key
   1197   //  -- a2     : receiver
   1198   //  -- ra     : return address
   1199   // -----------------------------------
   1200   Label slow, array, extra, check_if_double_array;
   1201   Label fast_object_with_map_check, fast_object_without_map_check;
   1202   Label fast_double_with_map_check, fast_double_without_map_check;
   1203   Label transition_smi_elements, finish_object_store, non_double_value;
   1204   Label transition_double_elements;
   1205 
   1206   // Register usage.
   1207   Register value = a0;
   1208   Register key = a1;
   1209   Register receiver = a2;
   1210   Register receiver_map = a3;
   1211   Register elements_map = t2;
   1212   Register elements = t3;  // Elements array of the receiver.
   1213   // t0 and t1 are used as general scratch registers.
   1214 
   1215   // Check that the key is a smi.
   1216   __ JumpIfNotSmi(key, &slow);
   1217   // Check that the object isn't a smi.
   1218   __ JumpIfSmi(receiver, &slow);
   1219   // Get the map of the object.
   1220   __ lw(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
   1221   // Check that the receiver does not require access checks.  We need
   1222   // to do this because this generic stub does not perform map checks.
   1223   __ lbu(t0, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
   1224   __ And(t0, t0, Operand(1 << Map::kIsAccessCheckNeeded));
   1225   __ Branch(&slow, ne, t0, Operand(zero_reg));
   1226   // Check if the object is a JS array or not.
   1227   __ lbu(t0, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset));
   1228   __ Branch(&array, eq, t0, Operand(JS_ARRAY_TYPE));
   1229   // Check that the object is some kind of JSObject.
   1230   __ Branch(&slow, lt, t0, Operand(FIRST_JS_OBJECT_TYPE));
   1231 
   1232   // Object case: Check key against length in the elements array.
   1233   __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
   1234   // Check array bounds. Both the key and the length of FixedArray are smis.
   1235   __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
   1236   __ Branch(&fast_object_with_map_check, lo, key, Operand(t0));
   1237 
   1238   // Slow case, handle jump to runtime.
   1239   __ bind(&slow);
   1240   // Entry registers are intact.
   1241   // a0: value.
   1242   // a1: key.
   1243   // a2: receiver.
   1244   GenerateRuntimeSetProperty(masm, strict_mode);
   1245 
   1246   // Extra capacity case: Check if there is extra capacity to
   1247   // perform the store and update the length. Used for adding one
   1248   // element to the array by writing to array[array.length].
   1249   __ bind(&extra);
   1250   // Condition code from comparing key and array length is still available.
   1251   // Only support writing to array[array.length].
   1252   __ Branch(&slow, ne, key, Operand(t0));
   1253   // Check for room in the elements backing store.
   1254   // Both the key and the length of FixedArray are smis.
   1255   __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
   1256   __ Branch(&slow, hs, key, Operand(t0));
   1257   __ lw(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
   1258   __ Branch(
   1259       &check_if_double_array, ne, elements_map, Heap::kFixedArrayMapRootIndex);
   1260 
   1261   // Calculate key + 1 as smi.
   1262   STATIC_ASSERT(kSmiTag == 0);
   1263   __ Addu(t0, key, Operand(Smi::FromInt(1)));
   1264   __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
   1265   __ Branch(&fast_object_without_map_check);
   1266 
   1267   __ bind(&check_if_double_array);
   1268   __ Branch(&slow, ne, elements_map, Heap::kFixedDoubleArrayMapRootIndex);
   1269   // Add 1 to key, and go to common element store code for doubles.
   1270   STATIC_ASSERT(kSmiTag == 0);
   1271   __ Addu(t0, key, Operand(Smi::FromInt(1)));
   1272   __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
   1273   __ jmp(&fast_double_without_map_check);
   1274 
   1275   // Array case: Get the length and the elements array from the JS
   1276   // array. Check that the array is in fast mode (and writable); if it
   1277   // is the length is always a smi.
   1278   __ bind(&array);
   1279   __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
   1280 
   1281   // Check the key against the length in the array.
   1282   __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
   1283   __ Branch(&extra, hs, key, Operand(t0));
   1284   // Fall through to fast case.
   1285 
   1286   __ bind(&fast_object_with_map_check);
   1287   Register scratch_value = t0;
   1288   Register address = t1;
   1289   __ lw(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
   1290   __ Branch(&fast_double_with_map_check,
   1291             ne,
   1292             elements_map,
   1293             Heap::kFixedArrayMapRootIndex);
   1294   __ bind(&fast_object_without_map_check);
   1295   // Smi stores don't require further checks.
   1296   Label non_smi_value;
   1297   __ JumpIfNotSmi(value, &non_smi_value);
   1298   // It's irrelevant whether array is smi-only or not when writing a smi.
   1299   __ Addu(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
   1300   __ sll(scratch_value, key, kPointerSizeLog2 - kSmiTagSize);
   1301   __ Addu(address, address, scratch_value);
   1302   __ sw(value, MemOperand(address));
   1303   __ Ret(USE_DELAY_SLOT);
   1304   __ mov(v0, value);
   1305 
   1306   __ bind(&non_smi_value);
   1307   // Escape to elements kind transition case.
   1308   __ CheckFastObjectElements(receiver_map, scratch_value,
   1309                              &transition_smi_elements);
   1310   // Fast elements array, store the value to the elements backing store.
   1311   __ bind(&finish_object_store);
   1312   __ Addu(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
   1313   __ sll(scratch_value, key, kPointerSizeLog2 - kSmiTagSize);
   1314   __ Addu(address, address, scratch_value);
   1315   __ sw(value, MemOperand(address));
   1316   // Update write barrier for the elements array address.
   1317   __ mov(v0, value);  // Preserve the value which is returned.
   1318   __ RecordWrite(elements,
   1319                  address,
   1320                  value,
   1321                  kRAHasNotBeenSaved,
   1322                  kDontSaveFPRegs,
   1323                  EMIT_REMEMBERED_SET,
   1324                  OMIT_SMI_CHECK);
   1325   __ Ret();
   1326 
   1327   __ bind(&fast_double_with_map_check);
   1328   // Check for fast double array case. If this fails, call through to the
   1329   // runtime.
   1330   __ Branch(&slow, ne, elements_map, Heap::kFixedDoubleArrayMapRootIndex);
   1331   __ bind(&fast_double_without_map_check);
   1332   __ StoreNumberToDoubleElements(value,
   1333                                  key,
   1334                                  receiver,
   1335                                  elements,
   1336                                  a3,
   1337                                  t0,
   1338                                  t1,
   1339                                  t2,
   1340                                  &transition_double_elements);
   1341   __ Ret(USE_DELAY_SLOT);
   1342   __ mov(v0, value);
   1343 
   1344   __ bind(&transition_smi_elements);
   1345   // Transition the array appropriately depending on the value type.
   1346   __ lw(t0, FieldMemOperand(value, HeapObject::kMapOffset));
   1347   __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
   1348   __ Branch(&non_double_value, ne, t0, Operand(at));
   1349 
   1350   // Value is a double. Transition FAST_SMI_ONLY_ELEMENTS ->
   1351   // FAST_DOUBLE_ELEMENTS and complete the store.
   1352   __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
   1353                                          FAST_DOUBLE_ELEMENTS,
   1354                                          receiver_map,
   1355                                          t0,
   1356                                          &slow);
   1357   ASSERT(receiver_map.is(a3));  // Transition code expects map in a3
   1358   ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &slow);
   1359   __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
   1360   __ jmp(&fast_double_without_map_check);
   1361 
   1362   __ bind(&non_double_value);
   1363   // Value is not a double, FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS
   1364   __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
   1365                                          FAST_ELEMENTS,
   1366                                          receiver_map,
   1367                                          t0,
   1368                                          &slow);
   1369   ASSERT(receiver_map.is(a3));  // Transition code expects map in a3
   1370   ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm);
   1371   __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
   1372   __ jmp(&finish_object_store);
   1373 
   1374   __ bind(&transition_double_elements);
   1375   // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
   1376   // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
   1377   // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
   1378   __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
   1379                                          FAST_ELEMENTS,
   1380                                          receiver_map,
   1381                                          t0,
   1382                                          &slow);
   1383   ASSERT(receiver_map.is(a3));  // Transition code expects map in a3
   1384   ElementsTransitionGenerator::GenerateDoubleToObject(masm, &slow);
   1385   __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
   1386   __ jmp(&finish_object_store);
   1387 }
   1388 
   1389 
   1390 void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
   1391   // ---------- S t a t e --------------
   1392   //  -- ra     : return address
   1393   //  -- a0     : key
   1394   //  -- a1     : receiver
   1395   // -----------------------------------
   1396   Label slow;
   1397 
   1398   // Check that the receiver isn't a smi.
   1399   __ JumpIfSmi(a1, &slow);
   1400 
   1401   // Check that the key is an array index, that is Uint32.
   1402   __ And(t0, a0, Operand(kSmiTagMask | kSmiSignMask));
   1403   __ Branch(&slow, ne, t0, Operand(zero_reg));
   1404 
   1405   // Get the map of the receiver.
   1406   __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
   1407 
   1408   // Check that it has indexed interceptor and access checks
   1409   // are not enabled for this object.
   1410   __ lbu(a3, FieldMemOperand(a2, Map::kBitFieldOffset));
   1411   __ And(a3, a3, Operand(kSlowCaseBitFieldMask));
   1412   __ Branch(&slow, ne, a3, Operand(1 << Map::kHasIndexedInterceptor));
   1413   // Everything is fine, call runtime.
   1414   __ Push(a1, a0);  // Receiver, key.
   1415 
   1416   // Perform tail call to the entry.
   1417   __ TailCallExternalReference(ExternalReference(
   1418        IC_Utility(kKeyedLoadPropertyWithInterceptor), masm->isolate()), 2, 1);
   1419 
   1420   __ bind(&slow);
   1421   GenerateMiss(masm, false);
   1422 }
   1423 
   1424 
   1425 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
   1426   // ---------- S t a t e --------------
   1427   //  -- a0     : value
   1428   //  -- a1     : key
   1429   //  -- a2     : receiver
   1430   //  -- ra     : return address
   1431   // -----------------------------------
   1432 
   1433   // Push receiver, key and value for runtime call.
   1434   __ Push(a2, a1, a0);
   1435 
   1436   ExternalReference ref = force_generic
   1437       ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
   1438                           masm->isolate())
   1439       : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
   1440   __ TailCallExternalReference(ref, 3, 1);
   1441 }
   1442 
   1443 
   1444 void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
   1445   // ---------- S t a t e --------------
   1446   //  -- a0     : value
   1447   //  -- a1     : key
   1448   //  -- a2     : receiver
   1449   //  -- ra     : return address
   1450   // -----------------------------------
   1451 
   1452   // Push receiver, key and value for runtime call.
   1453   // We can't use MultiPush as the order of the registers is important.
   1454   __ Push(a2, a1, a0);
   1455 
   1456   // The slow case calls into the runtime to complete the store without causing
   1457   // an IC miss that would otherwise cause a transition to the generic stub.
   1458   ExternalReference ref =
   1459       ExternalReference(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
   1460 
   1461   __ TailCallExternalReference(ref, 3, 1);
   1462 }
   1463 
   1464 
   1465 void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) {
   1466   // ---------- S t a t e --------------
   1467   //  -- a2     : receiver
   1468   //  -- a3     : target map
   1469   //  -- ra     : return address
   1470   // -----------------------------------
   1471   // Must return the modified receiver in v0.
   1472   if (!FLAG_trace_elements_transitions) {
   1473     Label fail;
   1474     ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &fail);
   1475     __ Ret(USE_DELAY_SLOT);
   1476     __ mov(v0, a2);
   1477     __ bind(&fail);
   1478   }
   1479 
   1480   __ push(a2);
   1481   __ TailCallRuntime(Runtime::kTransitionElementsSmiToDouble, 1, 1);
   1482 }
   1483 
   1484 
   1485 void KeyedStoreIC::GenerateTransitionElementsDoubleToObject(
   1486     MacroAssembler* masm) {
   1487   // ---------- S t a t e --------------
   1488   //  -- a2     : receiver
   1489   //  -- a3     : target map
   1490   //  -- ra     : return address
   1491   // -----------------------------------
   1492   // Must return the modified receiver in v0.
   1493   if (!FLAG_trace_elements_transitions) {
   1494     Label fail;
   1495     ElementsTransitionGenerator::GenerateDoubleToObject(masm, &fail);
   1496     __ Ret(USE_DELAY_SLOT);
   1497     __ mov(v0, a2);
   1498     __ bind(&fail);
   1499   }
   1500 
   1501   __ push(a2);
   1502   __ TailCallRuntime(Runtime::kTransitionElementsDoubleToObject, 1, 1);
   1503 }
   1504 
   1505 
   1506 void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
   1507                                   StrictModeFlag strict_mode) {
   1508   // ----------- S t a t e -------------
   1509   //  -- a0    : value
   1510   //  -- a1    : receiver
   1511   //  -- a2    : name
   1512   //  -- ra    : return address
   1513   // -----------------------------------
   1514 
   1515   // Get the receiver from the stack and probe the stub cache.
   1516   Code::Flags flags =
   1517       Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC, strict_mode);
   1518   Isolate::Current()->stub_cache()->GenerateProbe(
   1519       masm, flags, a1, a2, a3, t0, t1, t2);
   1520 
   1521   // Cache miss: Jump to runtime.
   1522   GenerateMiss(masm);
   1523 }
   1524 
   1525 
   1526 void StoreIC::GenerateMiss(MacroAssembler* masm) {
   1527   // ----------- S t a t e -------------
   1528   //  -- a0    : value
   1529   //  -- a1    : receiver
   1530   //  -- a2    : name
   1531   //  -- ra    : return address
   1532   // -----------------------------------
   1533 
   1534   __ Push(a1, a2, a0);
   1535   // Perform tail call to the entry.
   1536   ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss),
   1537                                             masm->isolate());
   1538   __ TailCallExternalReference(ref, 3, 1);
   1539 }
   1540 
   1541 
   1542 void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
   1543   // ----------- S t a t e -------------
   1544   //  -- a0    : value
   1545   //  -- a1    : receiver
   1546   //  -- a2    : name
   1547   //  -- ra    : return address
   1548   // -----------------------------------
   1549   //
   1550   // This accepts as a receiver anything JSArray::SetElementsLength accepts
   1551   // (currently anything except for external arrays which means anything with
   1552   // elements of FixedArray type).  Value must be a number, but only smis are
   1553   // accepted as the most common case.
   1554 
   1555   Label miss;
   1556 
   1557   Register receiver = a1;
   1558   Register value = a0;
   1559   Register scratch = a3;
   1560 
   1561   // Check that the receiver isn't a smi.
   1562   __ JumpIfSmi(receiver, &miss);
   1563 
   1564   // Check that the object is a JS array.
   1565   __ GetObjectType(receiver, scratch, scratch);
   1566   __ Branch(&miss, ne, scratch, Operand(JS_ARRAY_TYPE));
   1567 
   1568   // Check that elements are FixedArray.
   1569   // We rely on StoreIC_ArrayLength below to deal with all types of
   1570   // fast elements (including COW).
   1571   __ lw(scratch, FieldMemOperand(receiver, JSArray::kElementsOffset));
   1572   __ GetObjectType(scratch, scratch, scratch);
   1573   __ Branch(&miss, ne, scratch, Operand(FIXED_ARRAY_TYPE));
   1574 
   1575   // Check that the array has fast properties, otherwise the length
   1576   // property might have been redefined.
   1577   __ lw(scratch, FieldMemOperand(receiver, JSArray::kPropertiesOffset));
   1578   __ lw(scratch, FieldMemOperand(scratch, FixedArray::kMapOffset));
   1579   __ LoadRoot(at, Heap::kHashTableMapRootIndex);
   1580   __ Branch(&miss, eq, scratch, Operand(at));
   1581 
   1582   // Check that value is a smi.
   1583   __ JumpIfNotSmi(value, &miss);
   1584 
   1585   // Prepare tail call to StoreIC_ArrayLength.
   1586   __ Push(receiver, value);
   1587 
   1588   ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_ArrayLength),
   1589                                             masm->isolate());
   1590   __ TailCallExternalReference(ref, 2, 1);
   1591 
   1592   __ bind(&miss);
   1593 
   1594   GenerateMiss(masm);
   1595 }
   1596 
   1597 
   1598 void StoreIC::GenerateNormal(MacroAssembler* masm) {
   1599   // ----------- S t a t e -------------
   1600   //  -- a0    : value
   1601   //  -- a1    : receiver
   1602   //  -- a2    : name
   1603   //  -- ra    : return address
   1604   // -----------------------------------
   1605   Label miss;
   1606 
   1607   GenerateStringDictionaryReceiverCheck(masm, a1, a3, t0, t1, &miss);
   1608 
   1609   GenerateDictionaryStore(masm, &miss, a3, a2, a0, t0, t1);
   1610   Counters* counters = masm->isolate()->counters();
   1611   __ IncrementCounter(counters->store_normal_hit(), 1, t0, t1);
   1612   __ Ret();
   1613 
   1614   __ bind(&miss);
   1615   __ IncrementCounter(counters->store_normal_miss(), 1, t0, t1);
   1616   GenerateMiss(masm);
   1617 }
   1618 
   1619 
   1620 void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
   1621                                   StrictModeFlag strict_mode) {
   1622   // ----------- S t a t e -------------
   1623   //  -- a0    : value
   1624   //  -- a1    : receiver
   1625   //  -- a2    : name
   1626   //  -- ra    : return address
   1627   // -----------------------------------
   1628 
   1629   __ Push(a1, a2, a0);
   1630 
   1631   __ li(a1, Operand(Smi::FromInt(NONE)));  // PropertyAttributes.
   1632   __ li(a0, Operand(Smi::FromInt(strict_mode)));
   1633   __ Push(a1, a0);
   1634 
   1635   // Do tail-call to runtime routine.
   1636   __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
   1637 }
   1638 
   1639 
   1640 #undef __
   1641 
   1642 
   1643 Condition CompareIC::ComputeCondition(Token::Value op) {
   1644   switch (op) {
   1645     case Token::EQ_STRICT:
   1646     case Token::EQ:
   1647       return eq;
   1648     case Token::LT:
   1649       return lt;
   1650     case Token::GT:
   1651       return gt;
   1652     case Token::LTE:
   1653       return le;
   1654     case Token::GTE:
   1655       return ge;
   1656     default:
   1657       UNREACHABLE();
   1658       return kNoCondition;
   1659   }
   1660 }
   1661 
   1662 
   1663 void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
   1664   HandleScope scope;
   1665   Handle<Code> rewritten;
   1666   State previous_state = GetState();
   1667   State state = TargetState(previous_state, false, x, y);
   1668   if (state == GENERIC) {
   1669     CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, a1, a0);
   1670     rewritten = stub.GetCode();
   1671   } else {
   1672     ICCompareStub stub(op_, state);
   1673     if (state == KNOWN_OBJECTS) {
   1674       stub.set_known_map(Handle<Map>(Handle<JSObject>::cast(x)->map()));
   1675     }
   1676     rewritten = stub.GetCode();
   1677   }
   1678   set_target(*rewritten);
   1679 
   1680 #ifdef DEBUG
   1681   if (FLAG_trace_ic) {
   1682     PrintF("[CompareIC (%s->%s)#%s]\n",
   1683            GetStateName(previous_state),
   1684            GetStateName(state),
   1685            Token::Name(op_));
   1686   }
   1687 #endif
   1688 
   1689   // Activate inlined smi code.
   1690   if (previous_state == UNINITIALIZED) {
   1691     PatchInlinedSmiCode(address());
   1692   }
   1693 }
   1694 
   1695 
   1696 void PatchInlinedSmiCode(Address address) {
   1697   Address andi_instruction_address =
   1698       address + Assembler::kCallTargetAddressOffset;
   1699 
   1700   // If the instruction following the call is not a andi at, rx, #yyy, nothing
   1701   // was inlined.
   1702   Instr instr = Assembler::instr_at(andi_instruction_address);
   1703   if (!(Assembler::IsAndImmediate(instr) &&
   1704         Assembler::GetRt(instr) == (uint32_t)zero_reg.code())) {
   1705     return;
   1706   }
   1707 
   1708   // The delta to the start of the map check instruction and the
   1709   // condition code uses at the patched jump.
   1710   int delta = Assembler::GetImmediate16(instr);
   1711   delta += Assembler::GetRs(instr) * kImm16Mask;
   1712   // If the delta is 0 the instruction is andi at, zero_reg, #0 which also
   1713   // signals that nothing was inlined.
   1714   if (delta == 0) {
   1715     return;
   1716   }
   1717 
   1718 #ifdef DEBUG
   1719   if (FLAG_trace_ic) {
   1720     PrintF("[  patching ic at %p, andi=%p, delta=%d\n",
   1721            address, andi_instruction_address, delta);
   1722   }
   1723 #endif
   1724 
   1725   Address patch_address =
   1726       andi_instruction_address - delta * Instruction::kInstrSize;
   1727   Instr instr_at_patch = Assembler::instr_at(patch_address);
   1728   Instr branch_instr =
   1729       Assembler::instr_at(patch_address + Instruction::kInstrSize);
   1730   ASSERT(Assembler::IsAndImmediate(instr_at_patch));
   1731   ASSERT_EQ(0, Assembler::GetImmediate16(instr_at_patch));
   1732   ASSERT(Assembler::IsBranch(branch_instr));
   1733   if (Assembler::IsBeq(branch_instr)) {
   1734     // This is patching a "jump if not smi" site to be active.
   1735     // Changing:
   1736     //   andi at, rx, 0
   1737     //   Branch <target>, eq, at, Operand(zero_reg)
   1738     // to:
   1739     //   andi at, rx, #kSmiTagMask
   1740     //   Branch <target>, ne, at, Operand(zero_reg)
   1741     CodePatcher patcher(patch_address, 2);
   1742     Register reg = Register::from_code(Assembler::GetRs(instr_at_patch));
   1743     patcher.masm()->andi(at, reg, kSmiTagMask);
   1744     patcher.ChangeBranchCondition(ne);
   1745   } else {
   1746     ASSERT(Assembler::IsBne(branch_instr));
   1747     // This is patching a "jump if smi" site to be active.
   1748     // Changing:
   1749     //   andi at, rx, 0
   1750     //   Branch <target>, ne, at, Operand(zero_reg)
   1751     // to:
   1752     //   andi at, rx, #kSmiTagMask
   1753     //   Branch <target>, eq, at, Operand(zero_reg)
   1754     CodePatcher patcher(patch_address, 2);
   1755     Register reg = Register::from_code(Assembler::GetRs(instr_at_patch));
   1756     patcher.masm()->andi(at, reg, kSmiTagMask);
   1757     patcher.ChangeBranchCondition(eq);
   1758   }
   1759 }
   1760 
   1761 
   1762 } }  // namespace v8::internal
   1763 
   1764 #endif  // V8_TARGET_ARCH_MIPS
   1765