Home | History | Annotate | Download | only in arm
      1 // Copyright 2011 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 defined(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 GenerateStringDictionaryReceiverCheck(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   __ tst(receiver, Operand(kSmiTagMask));
     83   __ b(eq, miss);
     84 
     85   // Check that the receiver is a valid JS object.
     86   __ CompareObjectType(receiver, t0, t1, FIRST_JS_OBJECT_TYPE);
     87   __ b(lt, miss);
     88 
     89   // If this assert fails, we have to check upper bound too.
     90   ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
     91 
     92   GenerateGlobalInstanceTypeCheck(masm, t1, miss);
     93 
     94   // Check that the global object does not require access checks.
     95   __ ldrb(t1, FieldMemOperand(t0, Map::kBitFieldOffset));
     96   __ tst(t1, Operand((1 << Map::kIsAccessCheckNeeded) |
     97                      (1 << Map::kHasNamedInterceptor)));
     98   __ b(ne, miss);
     99 
    100   __ ldr(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
    101   __ ldr(t1, FieldMemOperand(elements, HeapObject::kMapOffset));
    102   __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
    103   __ cmp(t1, ip);
    104   __ b(ne, miss);
    105 }
    106 
    107 
    108 // Probe the string dictionary in the |elements| register. Jump to the
    109 // |done| label if a property with the given name is found. Jump to
    110 // the |miss| label otherwise.
    111 static void GenerateStringDictionaryProbes(MacroAssembler* masm,
    112                                            Label* miss,
    113                                            Label* done,
    114                                            Register elements,
    115                                            Register name,
    116                                            Register scratch1,
    117                                            Register scratch2) {
    118   // Assert that name contains a string.
    119   if (FLAG_debug_code) __ AbortIfNotString(name);
    120 
    121   // Compute the capacity mask.
    122   const int kCapacityOffset = StringDictionary::kHeaderSize +
    123       StringDictionary::kCapacityIndex * kPointerSize;
    124   __ ldr(scratch1, FieldMemOperand(elements, kCapacityOffset));
    125   __ mov(scratch1, Operand(scratch1, ASR, kSmiTagSize));  // convert smi to int
    126   __ sub(scratch1, scratch1, Operand(1));
    127 
    128   const int kElementsStartOffset = StringDictionary::kHeaderSize +
    129       StringDictionary::kElementsStartIndex * kPointerSize;
    130 
    131   // Generate an unrolled loop that performs a few probes before
    132   // giving up. Measurements done on Gmail indicate that 2 probes
    133   // cover ~93% of loads from dictionaries.
    134   static const int kProbes = 4;
    135   for (int i = 0; i < kProbes; i++) {
    136     // Compute the masked index: (hash + i + i * i) & mask.
    137     __ ldr(scratch2, FieldMemOperand(name, String::kHashFieldOffset));
    138     if (i > 0) {
    139       // Add the probe offset (i + i * i) left shifted to avoid right shifting
    140       // the hash in a separate instruction. The value hash + i + i * i is right
    141       // shifted in the following and instruction.
    142       ASSERT(StringDictionary::GetProbeOffset(i) <
    143              1 << (32 - String::kHashFieldOffset));
    144       __ add(scratch2, scratch2, Operand(
    145           StringDictionary::GetProbeOffset(i) << String::kHashShift));
    146     }
    147     __ and_(scratch2, scratch1, Operand(scratch2, LSR, String::kHashShift));
    148 
    149     // Scale the index by multiplying by the element size.
    150     ASSERT(StringDictionary::kEntrySize == 3);
    151     // scratch2 = scratch2 * 3.
    152     __ add(scratch2, scratch2, Operand(scratch2, LSL, 1));
    153 
    154     // Check if the key is identical to the name.
    155     __ add(scratch2, elements, Operand(scratch2, LSL, 2));
    156     __ ldr(ip, FieldMemOperand(scratch2, kElementsStartOffset));
    157     __ cmp(name, Operand(ip));
    158     if (i != kProbes - 1) {
    159       __ b(eq, done);
    160     } else {
    161       __ b(ne, miss);
    162     }
    163   }
    164 }
    165 
    166 
    167 // Helper function used from LoadIC/CallIC GenerateNormal.
    168 //
    169 // elements: Property dictionary. It is not clobbered if a jump to the miss
    170 //           label is done.
    171 // name:     Property name. It is not clobbered if a jump to the miss label is
    172 //           done
    173 // result:   Register for the result. It is only updated if a jump to the miss
    174 //           label is not done. Can be the same as elements or name clobbering
    175 //           one of these in the case of not jumping to the miss label.
    176 // The two scratch registers need to be different from elements, name and
    177 // result.
    178 // The generated code assumes that the receiver has slow properties,
    179 // is not a global object and does not have interceptors.
    180 static void GenerateDictionaryLoad(MacroAssembler* masm,
    181                                    Label* miss,
    182                                    Register elements,
    183                                    Register name,
    184                                    Register result,
    185                                    Register scratch1,
    186                                    Register scratch2) {
    187   // Main use of the scratch registers.
    188   // scratch1: Used as temporary and to hold the capacity of the property
    189   //           dictionary.
    190   // scratch2: Used as temporary.
    191   Label done;
    192 
    193   // Probe the dictionary.
    194   GenerateStringDictionaryProbes(masm,
    195                                  miss,
    196                                  &done,
    197                                  elements,
    198                                  name,
    199                                  scratch1,
    200                                  scratch2);
    201 
    202   // If probing finds an entry check that the value is a normal
    203   // property.
    204   __ bind(&done);  // scratch2 == elements + 4 * index
    205   const int kElementsStartOffset = StringDictionary::kHeaderSize +
    206       StringDictionary::kElementsStartIndex * kPointerSize;
    207   const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
    208   __ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
    209   __ tst(scratch1, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize));
    210   __ b(ne, miss);
    211 
    212   // Get the value at the masked, scaled index and return.
    213   __ ldr(result,
    214          FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
    215 }
    216 
    217 
    218 // Helper function used from StoreIC::GenerateNormal.
    219 //
    220 // elements: Property dictionary. It is not clobbered if a jump to the miss
    221 //           label is done.
    222 // name:     Property name. It is not clobbered if a jump to the miss label is
    223 //           done
    224 // value:    The value to store.
    225 // The two scratch registers need to be different from elements, name and
    226 // result.
    227 // The generated code assumes that the receiver has slow properties,
    228 // is not a global object and does not have interceptors.
    229 static void GenerateDictionaryStore(MacroAssembler* masm,
    230                                     Label* miss,
    231                                     Register elements,
    232                                     Register name,
    233                                     Register value,
    234                                     Register scratch1,
    235                                     Register scratch2) {
    236   // Main use of the scratch registers.
    237   // scratch1: Used as temporary and to hold the capacity of the property
    238   //           dictionary.
    239   // scratch2: Used as temporary.
    240   Label done;
    241 
    242   // Probe the dictionary.
    243   GenerateStringDictionaryProbes(masm,
    244                                  miss,
    245                                  &done,
    246                                  elements,
    247                                  name,
    248                                  scratch1,
    249                                  scratch2);
    250 
    251   // If probing finds an entry in the dictionary check that the value
    252   // is a normal property that is not read only.
    253   __ bind(&done);  // scratch2 == elements + 4 * index
    254   const int kElementsStartOffset = StringDictionary::kHeaderSize +
    255       StringDictionary::kElementsStartIndex * kPointerSize;
    256   const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
    257   const int kTypeAndReadOnlyMask
    258       = (PropertyDetails::TypeField::mask() |
    259          PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
    260   __ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
    261   __ tst(scratch1, Operand(kTypeAndReadOnlyMask));
    262   __ b(ne, miss);
    263 
    264   // Store the value at the masked, scaled index and return.
    265   const int kValueOffset = kElementsStartOffset + kPointerSize;
    266   __ add(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag));
    267   __ str(value, MemOperand(scratch2));
    268 
    269   // Update the write barrier. Make sure not to clobber the value.
    270   __ mov(scratch1, value);
    271   __ RecordWrite(elements, scratch2, scratch1);
    272 }
    273 
    274 
    275 static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
    276                                          Label* miss,
    277                                          Register elements,
    278                                          Register key,
    279                                          Register result,
    280                                          Register t0,
    281                                          Register t1,
    282                                          Register t2) {
    283   // Register use:
    284   //
    285   // elements - holds the slow-case elements of the receiver on entry.
    286   //            Unchanged unless 'result' is the same register.
    287   //
    288   // key      - holds the smi key on entry.
    289   //            Unchanged unless 'result' is the same register.
    290   //
    291   // result   - holds the result on exit if the load succeeded.
    292   //            Allowed to be the same as 'key' or 'result'.
    293   //            Unchanged on bailout so 'key' or 'result' can be used
    294   //            in further computation.
    295   //
    296   // Scratch registers:
    297   //
    298   // t0 - holds the untagged key on entry and holds the hash once computed.
    299   //
    300   // t1 - used to hold the capacity mask of the dictionary
    301   //
    302   // t2 - used for the index into the dictionary.
    303   Label done;
    304 
    305   // Compute the hash code from the untagged key.  This must be kept in sync
    306   // with ComputeIntegerHash in utils.h.
    307   //
    308   // hash = ~hash + (hash << 15);
    309   __ mvn(t1, Operand(t0));
    310   __ add(t0, t1, Operand(t0, LSL, 15));
    311   // hash = hash ^ (hash >> 12);
    312   __ eor(t0, t0, Operand(t0, LSR, 12));
    313   // hash = hash + (hash << 2);
    314   __ add(t0, t0, Operand(t0, LSL, 2));
    315   // hash = hash ^ (hash >> 4);
    316   __ eor(t0, t0, Operand(t0, LSR, 4));
    317   // hash = hash * 2057;
    318   __ mov(t1, Operand(2057));
    319   __ mul(t0, t0, t1);
    320   // hash = hash ^ (hash >> 16);
    321   __ eor(t0, t0, Operand(t0, LSR, 16));
    322 
    323   // Compute the capacity mask.
    324   __ ldr(t1, FieldMemOperand(elements, NumberDictionary::kCapacityOffset));
    325   __ mov(t1, Operand(t1, ASR, kSmiTagSize));  // convert smi to int
    326   __ sub(t1, t1, Operand(1));
    327 
    328   // Generate an unrolled loop that performs a few probes before giving up.
    329   static const int kProbes = 4;
    330   for (int i = 0; i < kProbes; i++) {
    331     // Use t2 for index calculations and keep the hash intact in t0.
    332     __ mov(t2, t0);
    333     // Compute the masked index: (hash + i + i * i) & mask.
    334     if (i > 0) {
    335       __ add(t2, t2, Operand(NumberDictionary::GetProbeOffset(i)));
    336     }
    337     __ and_(t2, t2, Operand(t1));
    338 
    339     // Scale the index by multiplying by the element size.
    340     ASSERT(NumberDictionary::kEntrySize == 3);
    341     __ add(t2, t2, Operand(t2, LSL, 1));  // t2 = t2 * 3
    342 
    343     // Check if the key is identical to the name.
    344     __ add(t2, elements, Operand(t2, LSL, kPointerSizeLog2));
    345     __ ldr(ip, FieldMemOperand(t2, NumberDictionary::kElementsStartOffset));
    346     __ cmp(key, Operand(ip));
    347     if (i != kProbes - 1) {
    348       __ b(eq, &done);
    349     } else {
    350       __ b(ne, miss);
    351     }
    352   }
    353 
    354   __ bind(&done);
    355   // Check that the value is a normal property.
    356   // t2: elements + (index * kPointerSize)
    357   const int kDetailsOffset =
    358       NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
    359   __ ldr(t1, FieldMemOperand(t2, kDetailsOffset));
    360   __ tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::mask())));
    361   __ b(ne, miss);
    362 
    363   // Get the value at the masked, scaled index and return.
    364   const int kValueOffset =
    365       NumberDictionary::kElementsStartOffset + kPointerSize;
    366   __ ldr(result, FieldMemOperand(t2, kValueOffset));
    367 }
    368 
    369 
    370 void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
    371   // ----------- S t a t e -------------
    372   //  -- r2    : name
    373   //  -- lr    : return address
    374   //  -- r0    : receiver
    375   //  -- sp[0] : receiver
    376   // -----------------------------------
    377   Label miss;
    378 
    379   StubCompiler::GenerateLoadArrayLength(masm, r0, r3, &miss);
    380   __ bind(&miss);
    381   StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
    382 }
    383 
    384 
    385 void LoadIC::GenerateStringLength(MacroAssembler* masm, bool support_wrappers) {
    386   // ----------- S t a t e -------------
    387   //  -- r2    : name
    388   //  -- lr    : return address
    389   //  -- r0    : receiver
    390   //  -- sp[0] : receiver
    391   // -----------------------------------
    392   Label miss;
    393 
    394   StubCompiler::GenerateLoadStringLength(masm, r0, r1, r3, &miss,
    395                                          support_wrappers);
    396   // Cache miss: Jump to runtime.
    397   __ bind(&miss);
    398   StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
    399 }
    400 
    401 
    402 void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
    403   // ----------- S t a t e -------------
    404   //  -- r2    : name
    405   //  -- lr    : return address
    406   //  -- r0    : receiver
    407   //  -- sp[0] : receiver
    408   // -----------------------------------
    409   Label miss;
    410 
    411   StubCompiler::GenerateLoadFunctionPrototype(masm, r0, r1, r3, &miss);
    412   __ bind(&miss);
    413   StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
    414 }
    415 
    416 
    417 // Checks the receiver for special cases (value type, slow case bits).
    418 // Falls through for regular JS object.
    419 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
    420                                            Register receiver,
    421                                            Register map,
    422                                            Register scratch,
    423                                            int interceptor_bit,
    424                                            Label* slow) {
    425   // Check that the object isn't a smi.
    426   __ JumpIfSmi(receiver, slow);
    427   // Get the map of the receiver.
    428   __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
    429   // Check bit field.
    430   __ ldrb(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
    431   __ tst(scratch,
    432          Operand((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)));
    433   __ b(ne, slow);
    434   // Check that the object is some kind of JS object EXCEPT JS Value type.
    435   // In the case that the object is a value-wrapper object,
    436   // we enter the runtime system to make sure that indexing into string
    437   // objects work as intended.
    438   ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
    439   __ ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
    440   __ cmp(scratch, Operand(JS_OBJECT_TYPE));
    441   __ b(lt, slow);
    442 }
    443 
    444 
    445 // Loads an indexed element from a fast case array.
    446 // If not_fast_array is NULL, doesn't perform the elements map check.
    447 static void GenerateFastArrayLoad(MacroAssembler* masm,
    448                                   Register receiver,
    449                                   Register key,
    450                                   Register elements,
    451                                   Register scratch1,
    452                                   Register scratch2,
    453                                   Register result,
    454                                   Label* not_fast_array,
    455                                   Label* out_of_range) {
    456   // Register use:
    457   //
    458   // receiver - holds the receiver on entry.
    459   //            Unchanged unless 'result' is the same register.
    460   //
    461   // key      - holds the smi key on entry.
    462   //            Unchanged unless 'result' is the same register.
    463   //
    464   // elements - holds the elements of the receiver on exit.
    465   //
    466   // result   - holds the result on exit if the load succeeded.
    467   //            Allowed to be the the same as 'receiver' or 'key'.
    468   //            Unchanged on bailout so 'receiver' and 'key' can be safely
    469   //            used by further computation.
    470   //
    471   // Scratch registers:
    472   //
    473   // scratch1 - used to hold elements map and elements length.
    474   //            Holds the elements map if not_fast_array branch is taken.
    475   //
    476   // scratch2 - used to hold the loaded value.
    477 
    478   __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
    479   if (not_fast_array != NULL) {
    480     // Check that the object is in fast mode and writable.
    481     __ ldr(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
    482     __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
    483     __ cmp(scratch1, ip);
    484     __ b(ne, not_fast_array);
    485   } else {
    486     __ AssertFastElements(elements);
    487   }
    488   // Check that the key (index) is within bounds.
    489   __ ldr(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset));
    490   __ cmp(key, Operand(scratch1));
    491   __ b(hs, out_of_range);
    492   // Fast case: Do the load.
    493   __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
    494   // The key is a smi.
    495   ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
    496   __ ldr(scratch2,
    497          MemOperand(scratch1, key, LSL, kPointerSizeLog2 - kSmiTagSize));
    498   __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
    499   __ cmp(scratch2, ip);
    500   // In case the loaded value is the_hole we have to consult GetProperty
    501   // to ensure the prototype chain is searched.
    502   __ b(eq, out_of_range);
    503   __ mov(result, scratch2);
    504 }
    505 
    506 
    507 // Checks whether a key is an array index string or a symbol string.
    508 // Falls through if a key is a symbol.
    509 static void GenerateKeyStringCheck(MacroAssembler* masm,
    510                                    Register key,
    511                                    Register map,
    512                                    Register hash,
    513                                    Label* index_string,
    514                                    Label* not_symbol) {
    515   // The key is not a smi.
    516   // Is it a string?
    517   __ CompareObjectType(key, map, hash, FIRST_NONSTRING_TYPE);
    518   __ b(ge, not_symbol);
    519 
    520   // Is the string an array index, with cached numeric value?
    521   __ ldr(hash, FieldMemOperand(key, String::kHashFieldOffset));
    522   __ tst(hash, Operand(String::kContainsCachedArrayIndexMask));
    523   __ b(eq, index_string);
    524 
    525   // Is the string a symbol?
    526   // map: key map
    527   __ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
    528   ASSERT(kSymbolTag != 0);
    529   __ tst(hash, Operand(kIsSymbolMask));
    530   __ b(eq, not_symbol);
    531 }
    532 
    533 
    534 // Defined in ic.cc.
    535 Object* CallIC_Miss(Arguments args);
    536 
    537 // The generated code does not accept smi keys.
    538 // The generated code falls through if both probes miss.
    539 static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
    540                                           int argc,
    541                                           Code::Kind kind) {
    542   // ----------- S t a t e -------------
    543   //  -- r1    : receiver
    544   //  -- r2    : name
    545   // -----------------------------------
    546   Label number, non_number, non_string, boolean, probe, miss;
    547 
    548   // Probe the stub cache.
    549   Code::Flags flags = Code::ComputeFlags(kind,
    550                                          NOT_IN_LOOP,
    551                                          MONOMORPHIC,
    552                                          Code::kNoExtraICState,
    553                                          NORMAL,
    554                                          argc);
    555   Isolate::Current()->stub_cache()->GenerateProbe(
    556       masm, flags, r1, r2, r3, r4, r5);
    557 
    558   // If the stub cache probing failed, the receiver might be a value.
    559   // For value objects, we use the map of the prototype objects for
    560   // the corresponding JSValue for the cache and that is what we need
    561   // to probe.
    562   //
    563   // Check for number.
    564   __ tst(r1, Operand(kSmiTagMask));
    565   __ b(eq, &number);
    566   __ CompareObjectType(r1, r3, r3, HEAP_NUMBER_TYPE);
    567   __ b(ne, &non_number);
    568   __ bind(&number);
    569   StubCompiler::GenerateLoadGlobalFunctionPrototype(
    570       masm, Context::NUMBER_FUNCTION_INDEX, r1);
    571   __ b(&probe);
    572 
    573   // Check for string.
    574   __ bind(&non_number);
    575   __ cmp(r3, Operand(FIRST_NONSTRING_TYPE));
    576   __ b(hs, &non_string);
    577   StubCompiler::GenerateLoadGlobalFunctionPrototype(
    578       masm, Context::STRING_FUNCTION_INDEX, r1);
    579   __ b(&probe);
    580 
    581   // Check for boolean.
    582   __ bind(&non_string);
    583   __ LoadRoot(ip, Heap::kTrueValueRootIndex);
    584   __ cmp(r1, ip);
    585   __ b(eq, &boolean);
    586   __ LoadRoot(ip, Heap::kFalseValueRootIndex);
    587   __ cmp(r1, ip);
    588   __ b(ne, &miss);
    589   __ bind(&boolean);
    590   StubCompiler::GenerateLoadGlobalFunctionPrototype(
    591       masm, Context::BOOLEAN_FUNCTION_INDEX, r1);
    592 
    593   // Probe the stub cache for the value object.
    594   __ bind(&probe);
    595   Isolate::Current()->stub_cache()->GenerateProbe(
    596       masm, flags, r1, r2, r3, r4, r5);
    597 
    598   __ bind(&miss);
    599 }
    600 
    601 
    602 static void GenerateFunctionTailCall(MacroAssembler* masm,
    603                                      int argc,
    604                                      Label* miss,
    605                                      Register scratch) {
    606   // r1: function
    607 
    608   // Check that the value isn't a smi.
    609   __ tst(r1, Operand(kSmiTagMask));
    610   __ b(eq, miss);
    611 
    612   // Check that the value is a JSFunction.
    613   __ CompareObjectType(r1, scratch, scratch, JS_FUNCTION_TYPE);
    614   __ b(ne, miss);
    615 
    616   // Invoke the function.
    617   ParameterCount actual(argc);
    618   __ InvokeFunction(r1, actual, JUMP_FUNCTION);
    619 }
    620 
    621 
    622 static void GenerateCallNormal(MacroAssembler* masm, int argc) {
    623   // ----------- S t a t e -------------
    624   //  -- r2    : name
    625   //  -- lr    : return address
    626   // -----------------------------------
    627   Label miss;
    628 
    629   // Get the receiver of the function from the stack into r1.
    630   __ ldr(r1, MemOperand(sp, argc * kPointerSize));
    631 
    632   GenerateStringDictionaryReceiverCheck(masm, r1, r0, r3, r4, &miss);
    633 
    634   // r0: elements
    635   // Search the dictionary - put result in register r1.
    636   GenerateDictionaryLoad(masm, &miss, r0, r2, r1, r3, r4);
    637 
    638   GenerateFunctionTailCall(masm, argc, &miss, r4);
    639 
    640   __ bind(&miss);
    641 }
    642 
    643 
    644 static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
    645   // ----------- S t a t e -------------
    646   //  -- r2    : name
    647   //  -- lr    : return address
    648   // -----------------------------------
    649   Isolate* isolate = masm->isolate();
    650 
    651   if (id == IC::kCallIC_Miss) {
    652     __ IncrementCounter(isolate->counters()->call_miss(), 1, r3, r4);
    653   } else {
    654     __ IncrementCounter(isolate->counters()->keyed_call_miss(), 1, r3, r4);
    655   }
    656 
    657   // Get the receiver of the function from the stack.
    658   __ ldr(r3, MemOperand(sp, argc * kPointerSize));
    659 
    660   __ EnterInternalFrame();
    661 
    662   // Push the receiver and the name of the function.
    663   __ Push(r3, r2);
    664 
    665   // Call the entry.
    666   __ mov(r0, Operand(2));
    667   __ mov(r1, Operand(ExternalReference(IC_Utility(id), isolate)));
    668 
    669   CEntryStub stub(1);
    670   __ CallStub(&stub);
    671 
    672   // Move result to r1 and leave the internal frame.
    673   __ mov(r1, Operand(r0));
    674   __ LeaveInternalFrame();
    675 
    676   // Check if the receiver is a global object of some sort.
    677   // This can happen only for regular CallIC but not KeyedCallIC.
    678   if (id == IC::kCallIC_Miss) {
    679     Label invoke, global;
    680     __ ldr(r2, MemOperand(sp, argc * kPointerSize));  // receiver
    681     __ tst(r2, Operand(kSmiTagMask));
    682     __ b(eq, &invoke);
    683     __ CompareObjectType(r2, r3, r3, JS_GLOBAL_OBJECT_TYPE);
    684     __ b(eq, &global);
    685     __ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE));
    686     __ b(ne, &invoke);
    687 
    688     // Patch the receiver on the stack.
    689     __ bind(&global);
    690     __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
    691     __ str(r2, MemOperand(sp, argc * kPointerSize));
    692     __ bind(&invoke);
    693   }
    694 
    695   // Invoke the function.
    696   ParameterCount actual(argc);
    697   __ InvokeFunction(r1, actual, JUMP_FUNCTION);
    698 }
    699 
    700 
    701 void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
    702   // ----------- S t a t e -------------
    703   //  -- r2    : name
    704   //  -- lr    : return address
    705   // -----------------------------------
    706 
    707   GenerateCallMiss(masm, argc, IC::kCallIC_Miss);
    708 }
    709 
    710 
    711 void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
    712   // ----------- S t a t e -------------
    713   //  -- r2    : name
    714   //  -- lr    : return address
    715   // -----------------------------------
    716 
    717   // Get the receiver of the function from the stack into r1.
    718   __ ldr(r1, MemOperand(sp, argc * kPointerSize));
    719   GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC);
    720   GenerateMiss(masm, argc);
    721 }
    722 
    723 
    724 void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
    725   // ----------- S t a t e -------------
    726   //  -- r2    : name
    727   //  -- lr    : return address
    728   // -----------------------------------
    729 
    730   GenerateCallNormal(masm, argc);
    731   GenerateMiss(masm, argc);
    732 }
    733 
    734 
    735 void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
    736   // ----------- S t a t e -------------
    737   //  -- r2    : name
    738   //  -- lr    : return address
    739   // -----------------------------------
    740 
    741   GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss);
    742 }
    743 
    744 
    745 void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
    746   // ----------- S t a t e -------------
    747   //  -- r2    : name
    748   //  -- lr    : return address
    749   // -----------------------------------
    750 
    751   // Get the receiver of the function from the stack into r1.
    752   __ ldr(r1, MemOperand(sp, argc * kPointerSize));
    753 
    754   Label do_call, slow_call, slow_load, slow_reload_receiver;
    755   Label check_number_dictionary, check_string, lookup_monomorphic_cache;
    756   Label index_smi, index_string;
    757 
    758   // Check that the key is a smi.
    759   __ JumpIfNotSmi(r2, &check_string);
    760   __ bind(&index_smi);
    761   // Now the key is known to be a smi. This place is also jumped to from below
    762   // where a numeric string is converted to a smi.
    763 
    764   GenerateKeyedLoadReceiverCheck(
    765       masm, r1, r0, r3, Map::kHasIndexedInterceptor, &slow_call);
    766 
    767   GenerateFastArrayLoad(
    768       masm, r1, r2, r4, r3, r0, r1, &check_number_dictionary, &slow_load);
    769   Counters* counters = masm->isolate()->counters();
    770   __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1, r0, r3);
    771 
    772   __ bind(&do_call);
    773   // receiver in r1 is not used after this point.
    774   // r2: key
    775   // r1: function
    776   GenerateFunctionTailCall(masm, argc, &slow_call, r0);
    777 
    778   __ bind(&check_number_dictionary);
    779   // r2: key
    780   // r3: elements map
    781   // r4: elements
    782   // Check whether the elements is a number dictionary.
    783   __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
    784   __ cmp(r3, ip);
    785   __ b(ne, &slow_load);
    786   __ mov(r0, Operand(r2, ASR, kSmiTagSize));
    787   // r0: untagged index
    788   GenerateNumberDictionaryLoad(masm, &slow_load, r4, r2, r1, r0, r3, r5);
    789   __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1, r0, r3);
    790   __ jmp(&do_call);
    791 
    792   __ bind(&slow_load);
    793   // This branch is taken when calling KeyedCallIC_Miss is neither required
    794   // nor beneficial.
    795   __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1, r0, r3);
    796   __ EnterInternalFrame();
    797   __ push(r2);  // save the key
    798   __ Push(r1, r2);  // pass the receiver and the key
    799   __ CallRuntime(Runtime::kKeyedGetProperty, 2);
    800   __ pop(r2);  // restore the key
    801   __ LeaveInternalFrame();
    802   __ mov(r1, r0);
    803   __ jmp(&do_call);
    804 
    805   __ bind(&check_string);
    806   GenerateKeyStringCheck(masm, r2, r0, r3, &index_string, &slow_call);
    807 
    808   // The key is known to be a symbol.
    809   // If the receiver is a regular JS object with slow properties then do
    810   // a quick inline probe of the receiver's dictionary.
    811   // Otherwise do the monomorphic cache probe.
    812   GenerateKeyedLoadReceiverCheck(
    813       masm, r1, r0, r3, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
    814 
    815   __ ldr(r0, FieldMemOperand(r1, JSObject::kPropertiesOffset));
    816   __ ldr(r3, FieldMemOperand(r0, HeapObject::kMapOffset));
    817   __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
    818   __ cmp(r3, ip);
    819   __ b(ne, &lookup_monomorphic_cache);
    820 
    821   GenerateDictionaryLoad(masm, &slow_load, r0, r2, r1, r3, r4);
    822   __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1, r0, r3);
    823   __ jmp(&do_call);
    824 
    825   __ bind(&lookup_monomorphic_cache);
    826   __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1, r0, r3);
    827   GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC);
    828   // Fall through on miss.
    829 
    830   __ bind(&slow_call);
    831   // This branch is taken if:
    832   // - the receiver requires boxing or access check,
    833   // - the key is neither smi nor symbol,
    834   // - the value loaded is not a function,
    835   // - there is hope that the runtime will create a monomorphic call stub
    836   //   that will get fetched next time.
    837   __ IncrementCounter(counters->keyed_call_generic_slow(), 1, r0, r3);
    838   GenerateMiss(masm, argc);
    839 
    840   __ bind(&index_string);
    841   __ IndexFromHash(r3, r2);
    842   // Now jump to the place where smi keys are handled.
    843   __ jmp(&index_smi);
    844 }
    845 
    846 
    847 void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
    848   // ----------- S t a t e -------------
    849   //  -- r2    : name
    850   //  -- lr    : return address
    851   // -----------------------------------
    852 
    853   // Check if the name is a string.
    854   Label miss;
    855   __ tst(r2, Operand(kSmiTagMask));
    856   __ b(eq, &miss);
    857   __ IsObjectJSStringType(r2, r0, &miss);
    858 
    859   GenerateCallNormal(masm, argc);
    860   __ bind(&miss);
    861   GenerateMiss(masm, argc);
    862 }
    863 
    864 
    865 // Defined in ic.cc.
    866 Object* LoadIC_Miss(Arguments args);
    867 
    868 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
    869   // ----------- S t a t e -------------
    870   //  -- r2    : name
    871   //  -- lr    : return address
    872   //  -- r0    : receiver
    873   //  -- sp[0] : receiver
    874   // -----------------------------------
    875 
    876   // Probe the stub cache.
    877   Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
    878                                          NOT_IN_LOOP,
    879                                          MONOMORPHIC);
    880   Isolate::Current()->stub_cache()->GenerateProbe(
    881       masm, flags, r0, r2, r3, r4, r5);
    882 
    883   // Cache miss: Jump to runtime.
    884   GenerateMiss(masm);
    885 }
    886 
    887 
    888 void LoadIC::GenerateNormal(MacroAssembler* masm) {
    889   // ----------- S t a t e -------------
    890   //  -- r2    : name
    891   //  -- lr    : return address
    892   //  -- r0    : receiver
    893   //  -- sp[0] : receiver
    894   // -----------------------------------
    895   Label miss;
    896 
    897   GenerateStringDictionaryReceiverCheck(masm, r0, r1, r3, r4, &miss);
    898 
    899   // r1: elements
    900   GenerateDictionaryLoad(masm, &miss, r1, r2, r0, r3, r4);
    901   __ Ret();
    902 
    903   // Cache miss: Jump to runtime.
    904   __ bind(&miss);
    905   GenerateMiss(masm);
    906 }
    907 
    908 
    909 void LoadIC::GenerateMiss(MacroAssembler* masm) {
    910   // ----------- S t a t e -------------
    911   //  -- r2    : name
    912   //  -- lr    : return address
    913   //  -- r0    : receiver
    914   //  -- sp[0] : receiver
    915   // -----------------------------------
    916   Isolate* isolate = masm->isolate();
    917 
    918   __ IncrementCounter(isolate->counters()->load_miss(), 1, r3, r4);
    919 
    920   __ mov(r3, r0);
    921   __ Push(r3, r2);
    922 
    923   // Perform tail call to the entry.
    924   ExternalReference ref =
    925       ExternalReference(IC_Utility(kLoadIC_Miss), isolate);
    926   __ TailCallExternalReference(ref, 2, 1);
    927 }
    928 
    929 // Returns the code marker, or the 0 if the code is not marked.
    930 static inline int InlinedICSiteMarker(Address address,
    931                                       Address* inline_end_address) {
    932   if (V8::UseCrankshaft()) return false;
    933 
    934   // If the instruction after the call site is not the pseudo instruction nop1
    935   // then this is not related to an inlined in-object property load. The nop1
    936   // instruction is located just after the call to the IC in the deferred code
    937   // handling the miss in the inlined code. After the nop1 instruction there is
    938   // a branch instruction for jumping back from the deferred code.
    939   Address address_after_call = address + Assembler::kCallTargetAddressOffset;
    940   Instr instr_after_call = Assembler::instr_at(address_after_call);
    941   int code_marker = MacroAssembler::GetCodeMarker(instr_after_call);
    942 
    943   // A negative result means the code is not marked.
    944   if (code_marker <= 0) return 0;
    945 
    946   Address address_after_nop = address_after_call + Assembler::kInstrSize;
    947   Instr instr_after_nop = Assembler::instr_at(address_after_nop);
    948   // There may be some reg-reg move and frame merging code to skip over before
    949   // the branch back from the DeferredReferenceGetKeyedValue code to the inlined
    950   // code.
    951   while (!Assembler::IsBranch(instr_after_nop)) {
    952     address_after_nop += Assembler::kInstrSize;
    953     instr_after_nop = Assembler::instr_at(address_after_nop);
    954   }
    955 
    956   // Find the end of the inlined code for handling the load.
    957   int b_offset =
    958       Assembler::GetBranchOffset(instr_after_nop) + Assembler::kPcLoadDelta;
    959   ASSERT(b_offset < 0);  // Jumping back from deferred code.
    960   *inline_end_address = address_after_nop + b_offset;
    961 
    962   return code_marker;
    963 }
    964 
    965 
    966 bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
    967   if (V8::UseCrankshaft()) return false;
    968 
    969   // Find the end of the inlined code for handling the load if this is an
    970   // inlined IC call site.
    971   Address inline_end_address = 0;
    972   if (InlinedICSiteMarker(address, &inline_end_address)
    973       != Assembler::PROPERTY_ACCESS_INLINED) {
    974     return false;
    975   }
    976 
    977   // Patch the offset of the property load instruction (ldr r0, [r1, #+XXX]).
    978   // The immediate must be representable in 12 bits.
    979   ASSERT((JSObject::kMaxInstanceSize - JSObject::kHeaderSize) < (1 << 12));
    980   Address ldr_property_instr_address =
    981       inline_end_address - Assembler::kInstrSize;
    982   ASSERT(Assembler::IsLdrRegisterImmediate(
    983       Assembler::instr_at(ldr_property_instr_address)));
    984   Instr ldr_property_instr = Assembler::instr_at(ldr_property_instr_address);
    985   ldr_property_instr = Assembler::SetLdrRegisterImmediateOffset(
    986       ldr_property_instr, offset - kHeapObjectTag);
    987   Assembler::instr_at_put(ldr_property_instr_address, ldr_property_instr);
    988 
    989   // Indicate that code has changed.
    990   CPU::FlushICache(ldr_property_instr_address, 1 * Assembler::kInstrSize);
    991 
    992   // Patch the map check.
    993   // For PROPERTY_ACCESS_INLINED, the load map instruction is generated
    994   // 4 instructions before the end of the inlined code.
    995   // See codgen-arm.cc CodeGenerator::EmitNamedLoad.
    996   int ldr_map_offset = -4;
    997   Address ldr_map_instr_address =
    998       inline_end_address + ldr_map_offset * Assembler::kInstrSize;
    999   Assembler::set_target_address_at(ldr_map_instr_address,
   1000                                    reinterpret_cast<Address>(map));
   1001   return true;
   1002 }
   1003 
   1004 
   1005 bool LoadIC::PatchInlinedContextualLoad(Address address,
   1006                                         Object* map,
   1007                                         Object* cell,
   1008                                         bool is_dont_delete) {
   1009   // Find the end of the inlined code for handling the contextual load if
   1010   // this is inlined IC call site.
   1011   Address inline_end_address = 0;
   1012   int marker = InlinedICSiteMarker(address, &inline_end_address);
   1013   if (!((marker == Assembler::PROPERTY_ACCESS_INLINED_CONTEXT) ||
   1014         (marker == Assembler::PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE))) {
   1015     return false;
   1016   }
   1017   // On ARM we don't rely on the is_dont_delete argument as the hint is already
   1018   // embedded in the code marker.
   1019   bool marker_is_dont_delete =
   1020       marker == Assembler::PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE;
   1021 
   1022   // These are the offsets from the end of the inlined code.
   1023   // See codgen-arm.cc CodeGenerator::EmitNamedLoad.
   1024   int ldr_map_offset = marker_is_dont_delete ? -5: -8;
   1025   int ldr_cell_offset = marker_is_dont_delete ? -2: -5;
   1026   if (FLAG_debug_code && marker_is_dont_delete) {
   1027     // Three extra instructions were generated to check for the_hole_value.
   1028     ldr_map_offset -= 3;
   1029     ldr_cell_offset -= 3;
   1030   }
   1031   Address ldr_map_instr_address =
   1032       inline_end_address + ldr_map_offset * Assembler::kInstrSize;
   1033   Address ldr_cell_instr_address =
   1034       inline_end_address + ldr_cell_offset * Assembler::kInstrSize;
   1035 
   1036   // Patch the map check.
   1037   Assembler::set_target_address_at(ldr_map_instr_address,
   1038                                    reinterpret_cast<Address>(map));
   1039   // Patch the cell address.
   1040   Assembler::set_target_address_at(ldr_cell_instr_address,
   1041                                    reinterpret_cast<Address>(cell));
   1042 
   1043   return true;
   1044 }
   1045 
   1046 
   1047 bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) {
   1048   if (V8::UseCrankshaft()) return false;
   1049 
   1050   // Find the end of the inlined code for the store if there is an
   1051   // inlined version of the store.
   1052   Address inline_end_address = 0;
   1053   if (InlinedICSiteMarker(address, &inline_end_address)
   1054       != Assembler::PROPERTY_ACCESS_INLINED) {
   1055     return false;
   1056   }
   1057 
   1058   // Compute the address of the map load instruction.
   1059   Address ldr_map_instr_address =
   1060       inline_end_address -
   1061       (CodeGenerator::GetInlinedNamedStoreInstructionsAfterPatch() *
   1062        Assembler::kInstrSize);
   1063 
   1064   // Update the offsets if initializing the inlined store. No reason
   1065   // to update the offsets when clearing the inlined version because
   1066   // it will bail out in the map check.
   1067   if (map != HEAP->null_value()) {
   1068     // Patch the offset in the actual store instruction.
   1069     Address str_property_instr_address =
   1070         ldr_map_instr_address + 3 * Assembler::kInstrSize;
   1071     Instr str_property_instr = Assembler::instr_at(str_property_instr_address);
   1072     ASSERT(Assembler::IsStrRegisterImmediate(str_property_instr));
   1073     str_property_instr = Assembler::SetStrRegisterImmediateOffset(
   1074         str_property_instr, offset - kHeapObjectTag);
   1075     Assembler::instr_at_put(str_property_instr_address, str_property_instr);
   1076 
   1077     // Patch the offset in the add instruction that is part of the
   1078     // write barrier.
   1079     Address add_offset_instr_address =
   1080         str_property_instr_address + Assembler::kInstrSize;
   1081     Instr add_offset_instr = Assembler::instr_at(add_offset_instr_address);
   1082     ASSERT(Assembler::IsAddRegisterImmediate(add_offset_instr));
   1083     add_offset_instr = Assembler::SetAddRegisterImmediateOffset(
   1084         add_offset_instr, offset - kHeapObjectTag);
   1085     Assembler::instr_at_put(add_offset_instr_address, add_offset_instr);
   1086 
   1087     // Indicate that code has changed.
   1088     CPU::FlushICache(str_property_instr_address, 2 * Assembler::kInstrSize);
   1089   }
   1090 
   1091   // Patch the map check.
   1092   Assembler::set_target_address_at(ldr_map_instr_address,
   1093                                    reinterpret_cast<Address>(map));
   1094 
   1095   return true;
   1096 }
   1097 
   1098 
   1099 bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
   1100   if (V8::UseCrankshaft()) return false;
   1101 
   1102   Address inline_end_address = 0;
   1103   if (InlinedICSiteMarker(address, &inline_end_address)
   1104       != Assembler::PROPERTY_ACCESS_INLINED) {
   1105     return false;
   1106   }
   1107 
   1108   // Patch the map check.
   1109   Address ldr_map_instr_address =
   1110       inline_end_address -
   1111       (CodeGenerator::GetInlinedKeyedLoadInstructionsAfterPatch() *
   1112       Assembler::kInstrSize);
   1113   Assembler::set_target_address_at(ldr_map_instr_address,
   1114                                    reinterpret_cast<Address>(map));
   1115   return true;
   1116 }
   1117 
   1118 
   1119 bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
   1120   if (V8::UseCrankshaft()) return false;
   1121 
   1122   // Find the end of the inlined code for handling the store if this is an
   1123   // inlined IC call site.
   1124   Address inline_end_address = 0;
   1125   if (InlinedICSiteMarker(address, &inline_end_address)
   1126       != Assembler::PROPERTY_ACCESS_INLINED) {
   1127     return false;
   1128   }
   1129 
   1130   // Patch the map check.
   1131   Address ldr_map_instr_address =
   1132       inline_end_address -
   1133       (CodeGenerator::kInlinedKeyedStoreInstructionsAfterPatch *
   1134       Assembler::kInstrSize);
   1135   Assembler::set_target_address_at(ldr_map_instr_address,
   1136                                    reinterpret_cast<Address>(map));
   1137   return true;
   1138 }
   1139 
   1140 
   1141 Object* KeyedLoadIC_Miss(Arguments args);
   1142 
   1143 
   1144 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
   1145   // ---------- S t a t e --------------
   1146   //  -- lr     : return address
   1147   //  -- r0     : key
   1148   //  -- r1     : receiver
   1149   // -----------------------------------
   1150   Isolate* isolate = masm->isolate();
   1151 
   1152   __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, r3, r4);
   1153 
   1154   __ Push(r1, r0);
   1155 
   1156   ExternalReference ref =
   1157       ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
   1158   __ TailCallExternalReference(ref, 2, 1);
   1159 }
   1160 
   1161 
   1162 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
   1163   // ---------- S t a t e --------------
   1164   //  -- lr     : return address
   1165   //  -- r0     : key
   1166   //  -- r1     : receiver
   1167   // -----------------------------------
   1168 
   1169   __ Push(r1, r0);
   1170 
   1171   __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
   1172 }
   1173 
   1174 
   1175 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
   1176   // ---------- S t a t e --------------
   1177   //  -- lr     : return address
   1178   //  -- r0     : key
   1179   //  -- r1     : receiver
   1180   // -----------------------------------
   1181   Label slow, check_string, index_smi, index_string, property_array_property;
   1182   Label probe_dictionary, check_number_dictionary;
   1183 
   1184   Register key = r0;
   1185   Register receiver = r1;
   1186 
   1187   Isolate* isolate = masm->isolate();
   1188 
   1189   // Check that the key is a smi.
   1190   __ JumpIfNotSmi(key, &check_string);
   1191   __ bind(&index_smi);
   1192   // Now the key is known to be a smi. This place is also jumped to from below
   1193   // where a numeric string is converted to a smi.
   1194 
   1195   GenerateKeyedLoadReceiverCheck(
   1196       masm, receiver, r2, r3, Map::kHasIndexedInterceptor, &slow);
   1197 
   1198   // Check the "has fast elements" bit in the receiver's map which is
   1199   // now in r2.
   1200   __ ldrb(r3, FieldMemOperand(r2, Map::kBitField2Offset));
   1201   __ tst(r3, Operand(1 << Map::kHasFastElements));
   1202   __ b(eq, &check_number_dictionary);
   1203 
   1204   GenerateFastArrayLoad(
   1205       masm, receiver, key, r4, r3, r2, r0, NULL, &slow);
   1206   __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, r2, r3);
   1207   __ Ret();
   1208 
   1209   __ bind(&check_number_dictionary);
   1210   __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset));
   1211   __ ldr(r3, FieldMemOperand(r4, JSObject::kMapOffset));
   1212 
   1213   // Check whether the elements is a number dictionary.
   1214   // r0: key
   1215   // r3: elements map
   1216   // r4: elements
   1217   __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
   1218   __ cmp(r3, ip);
   1219   __ b(ne, &slow);
   1220   __ mov(r2, Operand(r0, ASR, kSmiTagSize));
   1221   GenerateNumberDictionaryLoad(masm, &slow, r4, r0, r0, r2, r3, r5);
   1222   __ Ret();
   1223 
   1224   // Slow case, key and receiver still in r0 and r1.
   1225   __ bind(&slow);
   1226   __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(),
   1227                       1, r2, r3);
   1228   GenerateRuntimeGetProperty(masm);
   1229 
   1230   __ bind(&check_string);
   1231   GenerateKeyStringCheck(masm, key, r2, r3, &index_string, &slow);
   1232 
   1233   GenerateKeyedLoadReceiverCheck(
   1234       masm, receiver, r2, r3, Map::kHasNamedInterceptor, &slow);
   1235 
   1236   // If the receiver is a fast-case object, check the keyed lookup
   1237   // cache. Otherwise probe the dictionary.
   1238   __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset));
   1239   __ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset));
   1240   __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
   1241   __ cmp(r4, ip);
   1242   __ b(eq, &probe_dictionary);
   1243 
   1244   // Load the map of the receiver, compute the keyed lookup cache hash
   1245   // based on 32 bits of the map pointer and the string hash.
   1246   __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
   1247   __ mov(r3, Operand(r2, ASR, KeyedLookupCache::kMapHashShift));
   1248   __ ldr(r4, FieldMemOperand(r0, String::kHashFieldOffset));
   1249   __ eor(r3, r3, Operand(r4, ASR, String::kHashShift));
   1250   __ And(r3, r3, Operand(KeyedLookupCache::kCapacityMask));
   1251 
   1252   // Load the key (consisting of map and symbol) from the cache and
   1253   // check for match.
   1254   ExternalReference cache_keys =
   1255       ExternalReference::keyed_lookup_cache_keys(isolate);
   1256   __ mov(r4, Operand(cache_keys));
   1257   __ add(r4, r4, Operand(r3, LSL, kPointerSizeLog2 + 1));
   1258   __ ldr(r5, MemOperand(r4, kPointerSize, PostIndex));  // Move r4 to symbol.
   1259   __ cmp(r2, r5);
   1260   __ b(ne, &slow);
   1261   __ ldr(r5, MemOperand(r4));
   1262   __ cmp(r0, r5);
   1263   __ b(ne, &slow);
   1264 
   1265   // Get field offset.
   1266   // r0     : key
   1267   // r1     : receiver
   1268   // r2     : receiver's map
   1269   // r3     : lookup cache index
   1270   ExternalReference cache_field_offsets =
   1271       ExternalReference::keyed_lookup_cache_field_offsets(isolate);
   1272   __ mov(r4, Operand(cache_field_offsets));
   1273   __ ldr(r5, MemOperand(r4, r3, LSL, kPointerSizeLog2));
   1274   __ ldrb(r6, FieldMemOperand(r2, Map::kInObjectPropertiesOffset));
   1275   __ sub(r5, r5, r6, SetCC);
   1276   __ b(ge, &property_array_property);
   1277 
   1278   // Load in-object property.
   1279   __ ldrb(r6, FieldMemOperand(r2, Map::kInstanceSizeOffset));
   1280   __ add(r6, r6, r5);  // Index from start of object.
   1281   __ sub(r1, r1, Operand(kHeapObjectTag));  // Remove the heap tag.
   1282   __ ldr(r0, MemOperand(r1, r6, LSL, kPointerSizeLog2));
   1283   __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
   1284                       1, r2, r3);
   1285   __ Ret();
   1286 
   1287   // Load property array property.
   1288   __ bind(&property_array_property);
   1289   __ ldr(r1, FieldMemOperand(r1, JSObject::kPropertiesOffset));
   1290   __ add(r1, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
   1291   __ ldr(r0, MemOperand(r1, r5, LSL, kPointerSizeLog2));
   1292   __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
   1293                       1, r2, r3);
   1294   __ Ret();
   1295 
   1296   // Do a quick inline probe of the receiver's dictionary, if it
   1297   // exists.
   1298   __ bind(&probe_dictionary);
   1299   // r1: receiver
   1300   // r0: key
   1301   // r3: elements
   1302   __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
   1303   __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
   1304   GenerateGlobalInstanceTypeCheck(masm, r2, &slow);
   1305   // Load the property to r0.
   1306   GenerateDictionaryLoad(masm, &slow, r3, r0, r0, r2, r4);
   1307   __ IncrementCounter(isolate->counters()->keyed_load_generic_symbol(),
   1308                       1, r2, r3);
   1309   __ Ret();
   1310 
   1311   __ bind(&index_string);
   1312   __ IndexFromHash(r3, key);
   1313   // Now jump to the place where smi keys are handled.
   1314   __ jmp(&index_smi);
   1315 }
   1316 
   1317 
   1318 void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
   1319   // ---------- S t a t e --------------
   1320   //  -- lr     : return address
   1321   //  -- r0     : key (index)
   1322   //  -- r1     : receiver
   1323   // -----------------------------------
   1324   Label miss;
   1325 
   1326   Register receiver = r1;
   1327   Register index = r0;
   1328   Register scratch1 = r2;
   1329   Register scratch2 = r3;
   1330   Register result = r0;
   1331 
   1332   StringCharAtGenerator char_at_generator(receiver,
   1333                                           index,
   1334                                           scratch1,
   1335                                           scratch2,
   1336                                           result,
   1337                                           &miss,  // When not a string.
   1338                                           &miss,  // When not a number.
   1339                                           &miss,  // When index out of range.
   1340                                           STRING_INDEX_IS_ARRAY_INDEX);
   1341   char_at_generator.GenerateFast(masm);
   1342   __ Ret();
   1343 
   1344   StubRuntimeCallHelper call_helper;
   1345   char_at_generator.GenerateSlow(masm, call_helper);
   1346 
   1347   __ bind(&miss);
   1348   GenerateMiss(masm);
   1349 }
   1350 
   1351 
   1352 void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
   1353   // ---------- S t a t e --------------
   1354   //  -- lr     : return address
   1355   //  -- r0     : key
   1356   //  -- r1     : receiver
   1357   // -----------------------------------
   1358   Label slow;
   1359 
   1360   // Check that the receiver isn't a smi.
   1361   __ JumpIfSmi(r1, &slow);
   1362 
   1363   // Check that the key is an array index, that is Uint32.
   1364   __ tst(r0, Operand(kSmiTagMask | kSmiSignMask));
   1365   __ b(ne, &slow);
   1366 
   1367   // Get the map of the receiver.
   1368   __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
   1369 
   1370   // Check that it has indexed interceptor and access checks
   1371   // are not enabled for this object.
   1372   __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset));
   1373   __ and_(r3, r3, Operand(kSlowCaseBitFieldMask));
   1374   __ cmp(r3, Operand(1 << Map::kHasIndexedInterceptor));
   1375   __ b(ne, &slow);
   1376 
   1377   // Everything is fine, call runtime.
   1378   __ Push(r1, r0);  // Receiver, key.
   1379 
   1380   // Perform tail call to the entry.
   1381   __ TailCallExternalReference(
   1382       ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor),
   1383                         masm->isolate()),
   1384       2,
   1385       1);
   1386 
   1387   __ bind(&slow);
   1388   GenerateMiss(masm);
   1389 }
   1390 
   1391 
   1392 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
   1393   // ---------- S t a t e --------------
   1394   //  -- r0     : value
   1395   //  -- r1     : key
   1396   //  -- r2     : receiver
   1397   //  -- lr     : return address
   1398   // -----------------------------------
   1399 
   1400   // Push receiver, key and value for runtime call.
   1401   __ Push(r2, r1, r0);
   1402 
   1403   ExternalReference ref =
   1404       ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
   1405   __ TailCallExternalReference(ref, 3, 1);
   1406 }
   1407 
   1408 
   1409 void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
   1410                                               StrictModeFlag strict_mode) {
   1411   // ---------- S t a t e --------------
   1412   //  -- r0     : value
   1413   //  -- r1     : key
   1414   //  -- r2     : receiver
   1415   //  -- lr     : return address
   1416   // -----------------------------------
   1417 
   1418   // Push receiver, key and value for runtime call.
   1419   __ Push(r2, r1, r0);
   1420 
   1421   __ mov(r1, Operand(Smi::FromInt(NONE)));          // PropertyAttributes
   1422   __ mov(r0, Operand(Smi::FromInt(strict_mode)));   // Strict mode.
   1423   __ Push(r1, r0);
   1424 
   1425   __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
   1426 }
   1427 
   1428 
   1429 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
   1430                                    StrictModeFlag strict_mode) {
   1431   // ---------- S t a t e --------------
   1432   //  -- r0     : value
   1433   //  -- r1     : key
   1434   //  -- r2     : receiver
   1435   //  -- lr     : return address
   1436   // -----------------------------------
   1437   Label slow, fast, array, extra;
   1438 
   1439   // Register usage.
   1440   Register value = r0;
   1441   Register key = r1;
   1442   Register receiver = r2;
   1443   Register elements = r3;  // Elements array of the receiver.
   1444   // r4 and r5 are used as general scratch registers.
   1445 
   1446   // Check that the key is a smi.
   1447   __ tst(key, Operand(kSmiTagMask));
   1448   __ b(ne, &slow);
   1449   // Check that the object isn't a smi.
   1450   __ tst(receiver, Operand(kSmiTagMask));
   1451   __ b(eq, &slow);
   1452   // Get the map of the object.
   1453   __ ldr(r4, FieldMemOperand(receiver, HeapObject::kMapOffset));
   1454   // Check that the receiver does not require access checks.  We need
   1455   // to do this because this generic stub does not perform map checks.
   1456   __ ldrb(ip, FieldMemOperand(r4, Map::kBitFieldOffset));
   1457   __ tst(ip, Operand(1 << Map::kIsAccessCheckNeeded));
   1458   __ b(ne, &slow);
   1459   // Check if the object is a JS array or not.
   1460   __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
   1461   __ cmp(r4, Operand(JS_ARRAY_TYPE));
   1462   __ b(eq, &array);
   1463   // Check that the object is some kind of JS object.
   1464   __ cmp(r4, Operand(FIRST_JS_OBJECT_TYPE));
   1465   __ b(lt, &slow);
   1466 
   1467   // Object case: Check key against length in the elements array.
   1468   __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
   1469   // Check that the object is in fast mode and writable.
   1470   __ ldr(r4, FieldMemOperand(elements, HeapObject::kMapOffset));
   1471   __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
   1472   __ cmp(r4, ip);
   1473   __ b(ne, &slow);
   1474   // Check array bounds. Both the key and the length of FixedArray are smis.
   1475   __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
   1476   __ cmp(key, Operand(ip));
   1477   __ b(lo, &fast);
   1478 
   1479   // Slow case, handle jump to runtime.
   1480   __ bind(&slow);
   1481   // Entry registers are intact.
   1482   // r0: value.
   1483   // r1: key.
   1484   // r2: receiver.
   1485   GenerateRuntimeSetProperty(masm, strict_mode);
   1486 
   1487   // Extra capacity case: Check if there is extra capacity to
   1488   // perform the store and update the length. Used for adding one
   1489   // element to the array by writing to array[array.length].
   1490   __ bind(&extra);
   1491   // Condition code from comparing key and array length is still available.
   1492   __ b(ne, &slow);  // Only support writing to writing to array[array.length].
   1493   // Check for room in the elements backing store.
   1494   // Both the key and the length of FixedArray are smis.
   1495   __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
   1496   __ cmp(key, Operand(ip));
   1497   __ b(hs, &slow);
   1498   // Calculate key + 1 as smi.
   1499   ASSERT_EQ(0, kSmiTag);
   1500   __ add(r4, key, Operand(Smi::FromInt(1)));
   1501   __ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset));
   1502   __ b(&fast);
   1503 
   1504   // Array case: Get the length and the elements array from the JS
   1505   // array. Check that the array is in fast mode (and writable); if it
   1506   // is the length is always a smi.
   1507   __ bind(&array);
   1508   __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
   1509   __ ldr(r4, FieldMemOperand(elements, HeapObject::kMapOffset));
   1510   __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
   1511   __ cmp(r4, ip);
   1512   __ b(ne, &slow);
   1513 
   1514   // Check the key against the length in the array.
   1515   __ ldr(ip, FieldMemOperand(receiver, JSArray::kLengthOffset));
   1516   __ cmp(key, Operand(ip));
   1517   __ b(hs, &extra);
   1518   // Fall through to fast case.
   1519 
   1520   __ bind(&fast);
   1521   // Fast case, store the value to the elements backing store.
   1522   __ add(r5, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
   1523   __ add(r5, r5, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
   1524   __ str(value, MemOperand(r5));
   1525   // Skip write barrier if the written value is a smi.
   1526   __ tst(value, Operand(kSmiTagMask));
   1527   __ Ret(eq);
   1528   // Update write barrier for the elements array address.
   1529   __ sub(r4, r5, Operand(elements));
   1530   __ RecordWrite(elements, Operand(r4), r5, r6);
   1531 
   1532   __ Ret();
   1533 }
   1534 
   1535 
   1536 void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
   1537                                   StrictModeFlag strict_mode) {
   1538   // ----------- S t a t e -------------
   1539   //  -- r0    : value
   1540   //  -- r1    : receiver
   1541   //  -- r2    : name
   1542   //  -- lr    : return address
   1543   // -----------------------------------
   1544 
   1545   // Get the receiver from the stack and probe the stub cache.
   1546   Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
   1547                                          NOT_IN_LOOP,
   1548                                          MONOMORPHIC,
   1549                                          strict_mode);
   1550 
   1551   Isolate::Current()->stub_cache()->GenerateProbe(
   1552       masm, flags, r1, r2, r3, r4, r5);
   1553 
   1554   // Cache miss: Jump to runtime.
   1555   GenerateMiss(masm);
   1556 }
   1557 
   1558 
   1559 void StoreIC::GenerateMiss(MacroAssembler* masm) {
   1560   // ----------- S t a t e -------------
   1561   //  -- r0    : value
   1562   //  -- r1    : receiver
   1563   //  -- r2    : name
   1564   //  -- lr    : return address
   1565   // -----------------------------------
   1566 
   1567   __ Push(r1, r2, r0);
   1568 
   1569   // Perform tail call to the entry.
   1570   ExternalReference ref =
   1571       ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
   1572   __ TailCallExternalReference(ref, 3, 1);
   1573 }
   1574 
   1575 
   1576 void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
   1577   // ----------- S t a t e -------------
   1578   //  -- r0    : value
   1579   //  -- r1    : receiver
   1580   //  -- r2    : name
   1581   //  -- lr    : return address
   1582   // -----------------------------------
   1583   //
   1584   // This accepts as a receiver anything JSObject::SetElementsLength accepts
   1585   // (currently anything except for external and pixel arrays which means
   1586   // anything with elements of FixedArray type.), but currently is restricted
   1587   // to JSArray.
   1588   // Value must be a number, but only smis are accepted as the most common case.
   1589 
   1590   Label miss;
   1591 
   1592   Register receiver = r1;
   1593   Register value = r0;
   1594   Register scratch = r3;
   1595 
   1596   // Check that the receiver isn't a smi.
   1597   __ JumpIfSmi(receiver, &miss);
   1598 
   1599   // Check that the object is a JS array.
   1600   __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
   1601   __ b(ne, &miss);
   1602 
   1603   // Check that elements are FixedArray.
   1604   // We rely on StoreIC_ArrayLength below to deal with all types of
   1605   // fast elements (including COW).
   1606   __ ldr(scratch, FieldMemOperand(receiver, JSArray::kElementsOffset));
   1607   __ CompareObjectType(scratch, scratch, scratch, FIXED_ARRAY_TYPE);
   1608   __ b(ne, &miss);
   1609 
   1610   // Check that value is a smi.
   1611   __ JumpIfNotSmi(value, &miss);
   1612 
   1613   // Prepare tail call to StoreIC_ArrayLength.
   1614   __ Push(receiver, value);
   1615 
   1616   ExternalReference ref =
   1617       ExternalReference(IC_Utility(kStoreIC_ArrayLength), masm->isolate());
   1618   __ TailCallExternalReference(ref, 2, 1);
   1619 
   1620   __ bind(&miss);
   1621 
   1622   GenerateMiss(masm);
   1623 }
   1624 
   1625 
   1626 void StoreIC::GenerateNormal(MacroAssembler* masm) {
   1627   // ----------- S t a t e -------------
   1628   //  -- r0    : value
   1629   //  -- r1    : receiver
   1630   //  -- r2    : name
   1631   //  -- lr    : return address
   1632   // -----------------------------------
   1633   Label miss;
   1634 
   1635   GenerateStringDictionaryReceiverCheck(masm, r1, r3, r4, r5, &miss);
   1636 
   1637   GenerateDictionaryStore(masm, &miss, r3, r2, r0, r4, r5);
   1638   Counters* counters = masm->isolate()->counters();
   1639   __ IncrementCounter(counters->store_normal_hit(),
   1640                       1, r4, r5);
   1641   __ Ret();
   1642 
   1643   __ bind(&miss);
   1644   __ IncrementCounter(counters->store_normal_miss(), 1, r4, r5);
   1645   GenerateMiss(masm);
   1646 }
   1647 
   1648 
   1649 void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
   1650                                   StrictModeFlag strict_mode) {
   1651   // ----------- S t a t e -------------
   1652   //  -- r0    : value
   1653   //  -- r1    : receiver
   1654   //  -- r2    : name
   1655   //  -- lr    : return address
   1656   // -----------------------------------
   1657 
   1658   __ Push(r1, r2, r0);
   1659 
   1660   __ mov(r1, Operand(Smi::FromInt(NONE)));  // PropertyAttributes
   1661   __ mov(r0, Operand(Smi::FromInt(strict_mode)));
   1662   __ Push(r1, r0);
   1663 
   1664   // Do tail-call to runtime routine.
   1665   __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
   1666 }
   1667 
   1668 
   1669 #undef __
   1670 
   1671 
   1672 Condition CompareIC::ComputeCondition(Token::Value op) {
   1673   switch (op) {
   1674     case Token::EQ_STRICT:
   1675     case Token::EQ:
   1676       return eq;
   1677     case Token::LT:
   1678       return lt;
   1679     case Token::GT:
   1680       // Reverse left and right operands to obtain ECMA-262 conversion order.
   1681       return lt;
   1682     case Token::LTE:
   1683       // Reverse left and right operands to obtain ECMA-262 conversion order.
   1684       return ge;
   1685     case Token::GTE:
   1686       return ge;
   1687     default:
   1688       UNREACHABLE();
   1689       return kNoCondition;
   1690   }
   1691 }
   1692 
   1693 
   1694 void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
   1695   HandleScope scope;
   1696   Handle<Code> rewritten;
   1697   State previous_state = GetState();
   1698   State state = TargetState(previous_state, false, x, y);
   1699   if (state == GENERIC) {
   1700     CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, r1, r0);
   1701     rewritten = stub.GetCode();
   1702   } else {
   1703     ICCompareStub stub(op_, state);
   1704     rewritten = stub.GetCode();
   1705   }
   1706   set_target(*rewritten);
   1707 
   1708 #ifdef DEBUG
   1709   if (FLAG_trace_ic) {
   1710     PrintF("[CompareIC (%s->%s)#%s]\n",
   1711            GetStateName(previous_state),
   1712            GetStateName(state),
   1713            Token::Name(op_));
   1714   }
   1715 #endif
   1716 
   1717   // Activate inlined smi code.
   1718   if (previous_state == UNINITIALIZED) {
   1719     PatchInlinedSmiCode(address());
   1720   }
   1721 }
   1722 
   1723 
   1724 void PatchInlinedSmiCode(Address address) {
   1725   Address cmp_instruction_address =
   1726       address + Assembler::kCallTargetAddressOffset;
   1727 
   1728   // If the instruction following the call is not a cmp rx, #yyy, nothing
   1729   // was inlined.
   1730   Instr instr = Assembler::instr_at(cmp_instruction_address);
   1731   if (!Assembler::IsCmpImmediate(instr)) {
   1732     return;
   1733   }
   1734 
   1735   // The delta to the start of the map check instruction and the
   1736   // condition code uses at the patched jump.
   1737   int delta = Assembler::GetCmpImmediateRawImmediate(instr);
   1738   delta +=
   1739       Assembler::GetCmpImmediateRegister(instr).code() * kOff12Mask;
   1740   // If the delta is 0 the instruction is cmp r0, #0 which also signals that
   1741   // nothing was inlined.
   1742   if (delta == 0) {
   1743     return;
   1744   }
   1745 
   1746 #ifdef DEBUG
   1747   if (FLAG_trace_ic) {
   1748     PrintF("[  patching ic at %p, cmp=%p, delta=%d\n",
   1749            address, cmp_instruction_address, delta);
   1750   }
   1751 #endif
   1752 
   1753   Address patch_address =
   1754       cmp_instruction_address - delta * Instruction::kInstrSize;
   1755   Instr instr_at_patch = Assembler::instr_at(patch_address);
   1756   Instr branch_instr =
   1757       Assembler::instr_at(patch_address + Instruction::kInstrSize);
   1758   ASSERT(Assembler::IsCmpRegister(instr_at_patch));
   1759   ASSERT_EQ(Assembler::GetRn(instr_at_patch).code(),
   1760             Assembler::GetRm(instr_at_patch).code());
   1761   ASSERT(Assembler::IsBranch(branch_instr));
   1762   if (Assembler::GetCondition(branch_instr) == eq) {
   1763     // This is patching a "jump if not smi" site to be active.
   1764     // Changing
   1765     //   cmp rx, rx
   1766     //   b eq, <target>
   1767     // to
   1768     //   tst rx, #kSmiTagMask
   1769     //   b ne, <target>
   1770     CodePatcher patcher(patch_address, 2);
   1771     Register reg = Assembler::GetRn(instr_at_patch);
   1772     patcher.masm()->tst(reg, Operand(kSmiTagMask));
   1773     patcher.EmitCondition(ne);
   1774   } else {
   1775     ASSERT(Assembler::GetCondition(branch_instr) == ne);
   1776     // This is patching a "jump if smi" site to be active.
   1777     // Changing
   1778     //   cmp rx, rx
   1779     //   b ne, <target>
   1780     // to
   1781     //   tst rx, #kSmiTagMask
   1782     //   b eq, <target>
   1783     CodePatcher patcher(patch_address, 2);
   1784     Register reg = Assembler::GetRn(instr_at_patch);
   1785     patcher.masm()->tst(reg, Operand(kSmiTagMask));
   1786     patcher.EmitCondition(eq);
   1787   }
   1788 }
   1789 
   1790 
   1791 } }  // namespace v8::internal
   1792 
   1793 #endif  // V8_TARGET_ARCH_ARM
   1794