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