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 defined(V8_TARGET_ARCH_ARM)
     31 
     32 #include "ic-inl.h"
     33 #include "codegen.h"
     34 #include "stub-cache.h"
     35 
     36 namespace v8 {
     37 namespace internal {
     38 
     39 #define __ ACCESS_MASM(masm)
     40 
     41 
     42 static void ProbeTable(Isolate* isolate,
     43                        MacroAssembler* masm,
     44                        Code::Flags flags,
     45                        StubCache::Table table,
     46                        Register receiver,
     47                        Register name,
     48                        // Number of the cache entry, not scaled.
     49                        Register offset,
     50                        Register scratch,
     51                        Register scratch2,
     52                        Register offset_scratch) {
     53   ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
     54   ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
     55   ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
     56 
     57   uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address());
     58   uint32_t value_off_addr = reinterpret_cast<uint32_t>(value_offset.address());
     59   uint32_t map_off_addr = reinterpret_cast<uint32_t>(map_offset.address());
     60 
     61   // Check the relative positions of the address fields.
     62   ASSERT(value_off_addr > key_off_addr);
     63   ASSERT((value_off_addr - key_off_addr) % 4 == 0);
     64   ASSERT((value_off_addr - key_off_addr) < (256 * 4));
     65   ASSERT(map_off_addr > key_off_addr);
     66   ASSERT((map_off_addr - key_off_addr) % 4 == 0);
     67   ASSERT((map_off_addr - key_off_addr) < (256 * 4));
     68 
     69   Label miss;
     70   Register base_addr = scratch;
     71   scratch = no_reg;
     72 
     73   // Multiply by 3 because there are 3 fields per entry (name, code, map).
     74   __ add(offset_scratch, offset, Operand(offset, LSL, 1));
     75 
     76   // Calculate the base address of the entry.
     77   __ mov(base_addr, Operand(key_offset));
     78   __ add(base_addr, base_addr, Operand(offset_scratch, LSL, kPointerSizeLog2));
     79 
     80   // Check that the key in the entry matches the name.
     81   __ ldr(ip, MemOperand(base_addr, 0));
     82   __ cmp(name, ip);
     83   __ b(ne, &miss);
     84 
     85   // Check the map matches.
     86   __ ldr(ip, MemOperand(base_addr, map_off_addr - key_off_addr));
     87   __ ldr(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset));
     88   __ cmp(ip, scratch2);
     89   __ b(ne, &miss);
     90 
     91   // Get the code entry from the cache.
     92   Register code = scratch2;
     93   scratch2 = no_reg;
     94   __ ldr(code, MemOperand(base_addr, value_off_addr - key_off_addr));
     95 
     96   // Check that the flags match what we're looking for.
     97   Register flags_reg = base_addr;
     98   base_addr = no_reg;
     99   __ ldr(flags_reg, FieldMemOperand(code, Code::kFlagsOffset));
    100   // It's a nice optimization if this constant is encodable in the bic insn.
    101 
    102   uint32_t mask = Code::kFlagsNotUsedInLookup;
    103   ASSERT(__ ImmediateFitsAddrMode1Instruction(mask));
    104   __ bic(flags_reg, flags_reg, Operand(mask));
    105   // Using cmn and the negative instead of cmp means we can use movw.
    106   if (flags < 0) {
    107     __ cmn(flags_reg, Operand(-flags));
    108   } else {
    109     __ cmp(flags_reg, Operand(flags));
    110   }
    111   __ b(ne, &miss);
    112 
    113 #ifdef DEBUG
    114     if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
    115       __ jmp(&miss);
    116     } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
    117       __ jmp(&miss);
    118     }
    119 #endif
    120 
    121   // Jump to the first instruction in the code stub.
    122   __ add(pc, code, Operand(Code::kHeaderSize - kHeapObjectTag));
    123 
    124   // Miss: fall through.
    125   __ bind(&miss);
    126 }
    127 
    128 
    129 // Helper function used to check that the dictionary doesn't contain
    130 // the property. This function may return false negatives, so miss_label
    131 // must always call a backup property check that is complete.
    132 // This function is safe to call if the receiver has fast properties.
    133 // Name must be a symbol and receiver must be a heap object.
    134 static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
    135                                              Label* miss_label,
    136                                              Register receiver,
    137                                              Handle<String> name,
    138                                              Register scratch0,
    139                                              Register scratch1) {
    140   ASSERT(name->IsSymbol());
    141   Counters* counters = masm->isolate()->counters();
    142   __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
    143   __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
    144 
    145   Label done;
    146 
    147   const int kInterceptorOrAccessCheckNeededMask =
    148       (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
    149 
    150   // Bail out if the receiver has a named interceptor or requires access checks.
    151   Register map = scratch1;
    152   __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
    153   __ ldrb(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
    154   __ tst(scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
    155   __ b(ne, miss_label);
    156 
    157   // Check that receiver is a JSObject.
    158   __ ldrb(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
    159   __ cmp(scratch0, Operand(FIRST_SPEC_OBJECT_TYPE));
    160   __ b(lt, miss_label);
    161 
    162   // Load properties array.
    163   Register properties = scratch0;
    164   __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
    165   // Check that the properties array is a dictionary.
    166   __ ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset));
    167   Register tmp = properties;
    168   __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
    169   __ cmp(map, tmp);
    170   __ b(ne, miss_label);
    171 
    172   // Restore the temporarily used register.
    173   __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
    174 
    175 
    176   StringDictionaryLookupStub::GenerateNegativeLookup(masm,
    177                                                      miss_label,
    178                                                      &done,
    179                                                      receiver,
    180                                                      properties,
    181                                                      name,
    182                                                      scratch1);
    183   __ bind(&done);
    184   __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
    185 }
    186 
    187 
    188 void StubCache::GenerateProbe(MacroAssembler* masm,
    189                               Code::Flags flags,
    190                               Register receiver,
    191                               Register name,
    192                               Register scratch,
    193                               Register extra,
    194                               Register extra2,
    195                               Register extra3) {
    196   Isolate* isolate = masm->isolate();
    197   Label miss;
    198 
    199   // Make sure that code is valid. The multiplying code relies on the
    200   // entry size being 12.
    201   ASSERT(sizeof(Entry) == 12);
    202 
    203   // Make sure the flags does not name a specific type.
    204   ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
    205 
    206   // Make sure that there are no register conflicts.
    207   ASSERT(!scratch.is(receiver));
    208   ASSERT(!scratch.is(name));
    209   ASSERT(!extra.is(receiver));
    210   ASSERT(!extra.is(name));
    211   ASSERT(!extra.is(scratch));
    212   ASSERT(!extra2.is(receiver));
    213   ASSERT(!extra2.is(name));
    214   ASSERT(!extra2.is(scratch));
    215   ASSERT(!extra2.is(extra));
    216 
    217   // Check scratch, extra and extra2 registers are valid.
    218   ASSERT(!scratch.is(no_reg));
    219   ASSERT(!extra.is(no_reg));
    220   ASSERT(!extra2.is(no_reg));
    221   ASSERT(!extra3.is(no_reg));
    222 
    223   Counters* counters = masm->isolate()->counters();
    224   __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1,
    225                       extra2, extra3);
    226 
    227   // Check that the receiver isn't a smi.
    228   __ JumpIfSmi(receiver, &miss);
    229 
    230   // Get the map of the receiver and compute the hash.
    231   __ ldr(scratch, FieldMemOperand(name, String::kHashFieldOffset));
    232   __ ldr(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
    233   __ add(scratch, scratch, Operand(ip));
    234   uint32_t mask = kPrimaryTableSize - 1;
    235   // We shift out the last two bits because they are not part of the hash and
    236   // they are always 01 for maps.
    237   __ mov(scratch, Operand(scratch, LSR, kHeapObjectTagSize));
    238   // Mask down the eor argument to the minimum to keep the immediate
    239   // ARM-encodable.
    240   __ eor(scratch, scratch, Operand((flags >> kHeapObjectTagSize) & mask));
    241   // Prefer and_ to ubfx here because ubfx takes 2 cycles.
    242   __ and_(scratch, scratch, Operand(mask));
    243 
    244   // Probe the primary table.
    245   ProbeTable(isolate,
    246              masm,
    247              flags,
    248              kPrimary,
    249              receiver,
    250              name,
    251              scratch,
    252              extra,
    253              extra2,
    254              extra3);
    255 
    256   // Primary miss: Compute hash for secondary probe.
    257   __ sub(scratch, scratch, Operand(name, LSR, kHeapObjectTagSize));
    258   uint32_t mask2 = kSecondaryTableSize - 1;
    259   __ add(scratch, scratch, Operand((flags >> kHeapObjectTagSize) & mask2));
    260   __ and_(scratch, scratch, Operand(mask2));
    261 
    262   // Probe the secondary table.
    263   ProbeTable(isolate,
    264              masm,
    265              flags,
    266              kSecondary,
    267              receiver,
    268              name,
    269              scratch,
    270              extra,
    271              extra2,
    272              extra3);
    273 
    274   // Cache miss: Fall-through and let caller handle the miss by
    275   // entering the runtime system.
    276   __ bind(&miss);
    277   __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1,
    278                       extra2, extra3);
    279 }
    280 
    281 
    282 void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
    283                                                        int index,
    284                                                        Register prototype) {
    285   // Load the global or builtins object from the current context.
    286   __ ldr(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
    287   // Load the global context from the global or builtins object.
    288   __ ldr(prototype,
    289          FieldMemOperand(prototype, GlobalObject::kGlobalContextOffset));
    290   // Load the function from the global context.
    291   __ ldr(prototype, MemOperand(prototype, Context::SlotOffset(index)));
    292   // Load the initial map.  The global functions all have initial maps.
    293   __ ldr(prototype,
    294          FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
    295   // Load the prototype from the initial map.
    296   __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
    297 }
    298 
    299 
    300 void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
    301     MacroAssembler* masm,
    302     int index,
    303     Register prototype,
    304     Label* miss) {
    305   Isolate* isolate = masm->isolate();
    306   // Check we're still in the same context.
    307   __ ldr(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
    308   __ Move(ip, isolate->global());
    309   __ cmp(prototype, ip);
    310   __ b(ne, miss);
    311   // Get the global function with the given index.
    312   Handle<JSFunction> function(
    313       JSFunction::cast(isolate->global_context()->get(index)));
    314   // Load its initial map. The global functions all have initial maps.
    315   __ Move(prototype, Handle<Map>(function->initial_map()));
    316   // Load the prototype from the initial map.
    317   __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
    318 }
    319 
    320 
    321 // Load a fast property out of a holder object (src). In-object properties
    322 // are loaded directly otherwise the property is loaded from the properties
    323 // fixed array.
    324 void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
    325                                             Register dst,
    326                                             Register src,
    327                                             Handle<JSObject> holder,
    328                                             int index) {
    329   // Adjust for the number of properties stored in the holder.
    330   index -= holder->map()->inobject_properties();
    331   if (index < 0) {
    332     // Get the property straight out of the holder.
    333     int offset = holder->map()->instance_size() + (index * kPointerSize);
    334     __ ldr(dst, FieldMemOperand(src, offset));
    335   } else {
    336     // Calculate the offset into the properties array.
    337     int offset = index * kPointerSize + FixedArray::kHeaderSize;
    338     __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
    339     __ ldr(dst, FieldMemOperand(dst, offset));
    340   }
    341 }
    342 
    343 
    344 void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
    345                                            Register receiver,
    346                                            Register scratch,
    347                                            Label* miss_label) {
    348   // Check that the receiver isn't a smi.
    349   __ JumpIfSmi(receiver, miss_label);
    350 
    351   // Check that the object is a JS array.
    352   __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
    353   __ b(ne, miss_label);
    354 
    355   // Load length directly from the JS array.
    356   __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
    357   __ Ret();
    358 }
    359 
    360 
    361 // Generate code to check if an object is a string.  If the object is a
    362 // heap object, its map's instance type is left in the scratch1 register.
    363 // If this is not needed, scratch1 and scratch2 may be the same register.
    364 static void GenerateStringCheck(MacroAssembler* masm,
    365                                 Register receiver,
    366                                 Register scratch1,
    367                                 Register scratch2,
    368                                 Label* smi,
    369                                 Label* non_string_object) {
    370   // Check that the receiver isn't a smi.
    371   __ JumpIfSmi(receiver, smi);
    372 
    373   // Check that the object is a string.
    374   __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
    375   __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
    376   __ and_(scratch2, scratch1, Operand(kIsNotStringMask));
    377   // The cast is to resolve the overload for the argument of 0x0.
    378   __ cmp(scratch2, Operand(static_cast<int32_t>(kStringTag)));
    379   __ b(ne, non_string_object);
    380 }
    381 
    382 
    383 // Generate code to load the length from a string object and return the length.
    384 // If the receiver object is not a string or a wrapped string object the
    385 // execution continues at the miss label. The register containing the
    386 // receiver is potentially clobbered.
    387 void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
    388                                             Register receiver,
    389                                             Register scratch1,
    390                                             Register scratch2,
    391                                             Label* miss,
    392                                             bool support_wrappers) {
    393   Label check_wrapper;
    394 
    395   // Check if the object is a string leaving the instance type in the
    396   // scratch1 register.
    397   GenerateStringCheck(masm, receiver, scratch1, scratch2, miss,
    398                       support_wrappers ? &check_wrapper : miss);
    399 
    400   // Load length directly from the string.
    401   __ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset));
    402   __ Ret();
    403 
    404   if (support_wrappers) {
    405     // Check if the object is a JSValue wrapper.
    406     __ bind(&check_wrapper);
    407     __ cmp(scratch1, Operand(JS_VALUE_TYPE));
    408     __ b(ne, miss);
    409 
    410     // Unwrap the value and check if the wrapped value is a string.
    411     __ ldr(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
    412     GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
    413     __ ldr(r0, FieldMemOperand(scratch1, String::kLengthOffset));
    414     __ Ret();
    415   }
    416 }
    417 
    418 
    419 void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
    420                                                  Register receiver,
    421                                                  Register scratch1,
    422                                                  Register scratch2,
    423                                                  Label* miss_label) {
    424   __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
    425   __ mov(r0, scratch1);
    426   __ Ret();
    427 }
    428 
    429 
    430 // Generate StoreField code, value is passed in r0 register.
    431 // When leaving generated code after success, the receiver_reg and name_reg
    432 // may be clobbered.  Upon branch to miss_label, the receiver and name
    433 // registers have their original values.
    434 void StubCompiler::GenerateStoreField(MacroAssembler* masm,
    435                                       Handle<JSObject> object,
    436                                       int index,
    437                                       Handle<Map> transition,
    438                                       Register receiver_reg,
    439                                       Register name_reg,
    440                                       Register scratch,
    441                                       Label* miss_label) {
    442   // r0 : value
    443   Label exit;
    444 
    445   // Check that the map of the object hasn't changed.
    446   CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
    447                                              : REQUIRE_EXACT_MAP;
    448   __ CheckMap(receiver_reg, scratch, Handle<Map>(object->map()), miss_label,
    449               DO_SMI_CHECK, mode);
    450 
    451   // Perform global security token check if needed.
    452   if (object->IsJSGlobalProxy()) {
    453     __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
    454   }
    455 
    456   // Stub never generated for non-global objects that require access
    457   // checks.
    458   ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
    459 
    460   // Perform map transition for the receiver if necessary.
    461   if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
    462     // The properties must be extended before we can store the value.
    463     // We jump to a runtime call that extends the properties array.
    464     __ push(receiver_reg);
    465     __ mov(r2, Operand(transition));
    466     __ Push(r2, r0);
    467     __ TailCallExternalReference(
    468         ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
    469                           masm->isolate()),
    470         3,
    471         1);
    472     return;
    473   }
    474 
    475   if (!transition.is_null()) {
    476     // Update the map of the object; no write barrier updating is
    477     // needed because the map is never in new space.
    478     __ mov(ip, Operand(transition));
    479     __ str(ip, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
    480   }
    481 
    482   // Adjust for the number of properties stored in the object. Even in the
    483   // face of a transition we can use the old map here because the size of the
    484   // object and the number of in-object properties is not going to change.
    485   index -= object->map()->inobject_properties();
    486 
    487   if (index < 0) {
    488     // Set the property straight into the object.
    489     int offset = object->map()->instance_size() + (index * kPointerSize);
    490     __ str(r0, FieldMemOperand(receiver_reg, offset));
    491 
    492     // Skip updating write barrier if storing a smi.
    493     __ JumpIfSmi(r0, &exit);
    494 
    495     // Update the write barrier for the array address.
    496     // Pass the now unused name_reg as a scratch register.
    497     __ mov(name_reg, r0);
    498     __ RecordWriteField(receiver_reg,
    499                         offset,
    500                         name_reg,
    501                         scratch,
    502                         kLRHasNotBeenSaved,
    503                         kDontSaveFPRegs);
    504   } else {
    505     // Write to the properties array.
    506     int offset = index * kPointerSize + FixedArray::kHeaderSize;
    507     // Get the properties array
    508     __ ldr(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
    509     __ str(r0, FieldMemOperand(scratch, offset));
    510 
    511     // Skip updating write barrier if storing a smi.
    512     __ JumpIfSmi(r0, &exit);
    513 
    514     // Update the write barrier for the array address.
    515     // Ok to clobber receiver_reg and name_reg, since we return.
    516     __ mov(name_reg, r0);
    517     __ RecordWriteField(scratch,
    518                         offset,
    519                         name_reg,
    520                         receiver_reg,
    521                         kLRHasNotBeenSaved,
    522                         kDontSaveFPRegs);
    523   }
    524 
    525   // Return the value (register r0).
    526   __ bind(&exit);
    527   __ Ret();
    528 }
    529 
    530 
    531 void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
    532   ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
    533   Handle<Code> code = (kind == Code::LOAD_IC)
    534       ? masm->isolate()->builtins()->LoadIC_Miss()
    535       : masm->isolate()->builtins()->KeyedLoadIC_Miss();
    536   __ Jump(code, RelocInfo::CODE_TARGET);
    537 }
    538 
    539 
    540 static void GenerateCallFunction(MacroAssembler* masm,
    541                                  Handle<Object> object,
    542                                  const ParameterCount& arguments,
    543                                  Label* miss,
    544                                  Code::ExtraICState extra_ic_state) {
    545   // ----------- S t a t e -------------
    546   //  -- r0: receiver
    547   //  -- r1: function to call
    548   // -----------------------------------
    549 
    550   // Check that the function really is a function.
    551   __ JumpIfSmi(r1, miss);
    552   __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
    553   __ b(ne, miss);
    554 
    555   // Patch the receiver on the stack with the global proxy if
    556   // necessary.
    557   if (object->IsGlobalObject()) {
    558     __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
    559     __ str(r3, MemOperand(sp, arguments.immediate() * kPointerSize));
    560   }
    561 
    562   // Invoke the function.
    563   CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
    564       ? CALL_AS_FUNCTION
    565       : CALL_AS_METHOD;
    566   __ InvokeFunction(r1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
    567 }
    568 
    569 
    570 static void PushInterceptorArguments(MacroAssembler* masm,
    571                                      Register receiver,
    572                                      Register holder,
    573                                      Register name,
    574                                      Handle<JSObject> holder_obj) {
    575   __ push(name);
    576   Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
    577   ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
    578   Register scratch = name;
    579   __ mov(scratch, Operand(interceptor));
    580   __ push(scratch);
    581   __ push(receiver);
    582   __ push(holder);
    583   __ ldr(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
    584   __ push(scratch);
    585 }
    586 
    587 
    588 static void CompileCallLoadPropertyWithInterceptor(
    589     MacroAssembler* masm,
    590     Register receiver,
    591     Register holder,
    592     Register name,
    593     Handle<JSObject> holder_obj) {
    594   PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
    595 
    596   ExternalReference ref =
    597       ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
    598                         masm->isolate());
    599   __ mov(r0, Operand(5));
    600   __ mov(r1, Operand(ref));
    601 
    602   CEntryStub stub(1);
    603   __ CallStub(&stub);
    604 }
    605 
    606 
    607 static const int kFastApiCallArguments = 3;
    608 
    609 // Reserves space for the extra arguments to FastHandleApiCall in the
    610 // caller's frame.
    611 //
    612 // These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
    613 static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
    614                                        Register scratch) {
    615   __ mov(scratch, Operand(Smi::FromInt(0)));
    616   for (int i = 0; i < kFastApiCallArguments; i++) {
    617     __ push(scratch);
    618   }
    619 }
    620 
    621 
    622 // Undoes the effects of ReserveSpaceForFastApiCall.
    623 static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
    624   __ Drop(kFastApiCallArguments);
    625 }
    626 
    627 
    628 static void GenerateFastApiDirectCall(MacroAssembler* masm,
    629                                       const CallOptimization& optimization,
    630                                       int argc) {
    631   // ----------- S t a t e -------------
    632   //  -- sp[0]              : holder (set by CheckPrototypes)
    633   //  -- sp[4]              : callee JS function
    634   //  -- sp[8]              : call data
    635   //  -- sp[12]             : last JS argument
    636   //  -- ...
    637   //  -- sp[(argc + 3) * 4] : first JS argument
    638   //  -- sp[(argc + 4) * 4] : receiver
    639   // -----------------------------------
    640   // Get the function and setup the context.
    641   Handle<JSFunction> function = optimization.constant_function();
    642   __ LoadHeapObject(r5, function);
    643   __ ldr(cp, FieldMemOperand(r5, JSFunction::kContextOffset));
    644 
    645   // Pass the additional arguments FastHandleApiCall expects.
    646   Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
    647   Handle<Object> call_data(api_call_info->data());
    648   if (masm->isolate()->heap()->InNewSpace(*call_data)) {
    649     __ Move(r0, api_call_info);
    650     __ ldr(r6, FieldMemOperand(r0, CallHandlerInfo::kDataOffset));
    651   } else {
    652     __ Move(r6, call_data);
    653   }
    654   // Store JS function and call data.
    655   __ stm(ib, sp, r5.bit() | r6.bit());
    656 
    657   // r2 points to call data as expected by Arguments
    658   // (refer to layout above).
    659   __ add(r2, sp, Operand(2 * kPointerSize));
    660 
    661   const int kApiStackSpace = 4;
    662 
    663   FrameScope frame_scope(masm, StackFrame::MANUAL);
    664   __ EnterExitFrame(false, kApiStackSpace);
    665 
    666   // r0 = v8::Arguments&
    667   // Arguments is after the return address.
    668   __ add(r0, sp, Operand(1 * kPointerSize));
    669   // v8::Arguments::implicit_args = data
    670   __ str(r2, MemOperand(r0, 0 * kPointerSize));
    671   // v8::Arguments::values = last argument
    672   __ add(ip, r2, Operand(argc * kPointerSize));
    673   __ str(ip, MemOperand(r0, 1 * kPointerSize));
    674   // v8::Arguments::length_ = argc
    675   __ mov(ip, Operand(argc));
    676   __ str(ip, MemOperand(r0, 2 * kPointerSize));
    677   // v8::Arguments::is_construct_call = 0
    678   __ mov(ip, Operand(0));
    679   __ str(ip, MemOperand(r0, 3 * kPointerSize));
    680 
    681   const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
    682   Address function_address = v8::ToCData<Address>(api_call_info->callback());
    683   ApiFunction fun(function_address);
    684   ExternalReference ref = ExternalReference(&fun,
    685                                             ExternalReference::DIRECT_API_CALL,
    686                                             masm->isolate());
    687   AllowExternalCallThatCantCauseGC scope(masm);
    688 
    689   __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
    690 }
    691 
    692 
    693 class CallInterceptorCompiler BASE_EMBEDDED {
    694  public:
    695   CallInterceptorCompiler(StubCompiler* stub_compiler,
    696                           const ParameterCount& arguments,
    697                           Register name,
    698                           Code::ExtraICState extra_ic_state)
    699       : stub_compiler_(stub_compiler),
    700         arguments_(arguments),
    701         name_(name),
    702         extra_ic_state_(extra_ic_state) {}
    703 
    704   void Compile(MacroAssembler* masm,
    705                Handle<JSObject> object,
    706                Handle<JSObject> holder,
    707                Handle<String> name,
    708                LookupResult* lookup,
    709                Register receiver,
    710                Register scratch1,
    711                Register scratch2,
    712                Register scratch3,
    713                Label* miss) {
    714     ASSERT(holder->HasNamedInterceptor());
    715     ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
    716 
    717     // Check that the receiver isn't a smi.
    718     __ JumpIfSmi(receiver, miss);
    719     CallOptimization optimization(lookup);
    720     if (optimization.is_constant_call()) {
    721       CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
    722                        holder, lookup, name, optimization, miss);
    723     } else {
    724       CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
    725                      name, holder, miss);
    726     }
    727   }
    728 
    729  private:
    730   void CompileCacheable(MacroAssembler* masm,
    731                         Handle<JSObject> object,
    732                         Register receiver,
    733                         Register scratch1,
    734                         Register scratch2,
    735                         Register scratch3,
    736                         Handle<JSObject> interceptor_holder,
    737                         LookupResult* lookup,
    738                         Handle<String> name,
    739                         const CallOptimization& optimization,
    740                         Label* miss_label) {
    741     ASSERT(optimization.is_constant_call());
    742     ASSERT(!lookup->holder()->IsGlobalObject());
    743     Counters* counters = masm->isolate()->counters();
    744     int depth1 = kInvalidProtoDepth;
    745     int depth2 = kInvalidProtoDepth;
    746     bool can_do_fast_api_call = false;
    747     if (optimization.is_simple_api_call() &&
    748         !lookup->holder()->IsGlobalObject()) {
    749       depth1 = optimization.GetPrototypeDepthOfExpectedType(
    750           object, interceptor_holder);
    751       if (depth1 == kInvalidProtoDepth) {
    752         depth2 = optimization.GetPrototypeDepthOfExpectedType(
    753             interceptor_holder, Handle<JSObject>(lookup->holder()));
    754       }
    755       can_do_fast_api_call =
    756           depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
    757     }
    758 
    759     __ IncrementCounter(counters->call_const_interceptor(), 1,
    760                         scratch1, scratch2);
    761 
    762     if (can_do_fast_api_call) {
    763       __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
    764                           scratch1, scratch2);
    765       ReserveSpaceForFastApiCall(masm, scratch1);
    766     }
    767 
    768     // Check that the maps from receiver to interceptor's holder
    769     // haven't changed and thus we can invoke interceptor.
    770     Label miss_cleanup;
    771     Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
    772     Register holder =
    773         stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
    774                                         scratch1, scratch2, scratch3,
    775                                         name, depth1, miss);
    776 
    777     // Invoke an interceptor and if it provides a value,
    778     // branch to |regular_invoke|.
    779     Label regular_invoke;
    780     LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
    781                         &regular_invoke);
    782 
    783     // Interceptor returned nothing for this property.  Try to use cached
    784     // constant function.
    785 
    786     // Check that the maps from interceptor's holder to constant function's
    787     // holder haven't changed and thus we can use cached constant function.
    788     if (*interceptor_holder != lookup->holder()) {
    789       stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
    790                                       Handle<JSObject>(lookup->holder()),
    791                                       scratch1, scratch2, scratch3,
    792                                       name, depth2, miss);
    793     } else {
    794       // CheckPrototypes has a side effect of fetching a 'holder'
    795       // for API (object which is instanceof for the signature).  It's
    796       // safe to omit it here, as if present, it should be fetched
    797       // by the previous CheckPrototypes.
    798       ASSERT(depth2 == kInvalidProtoDepth);
    799     }
    800 
    801     // Invoke function.
    802     if (can_do_fast_api_call) {
    803       GenerateFastApiDirectCall(masm, optimization, arguments_.immediate());
    804     } else {
    805       CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
    806           ? CALL_AS_FUNCTION
    807           : CALL_AS_METHOD;
    808       __ InvokeFunction(optimization.constant_function(), arguments_,
    809                         JUMP_FUNCTION, NullCallWrapper(), call_kind);
    810     }
    811 
    812     // Deferred code for fast API call case---clean preallocated space.
    813     if (can_do_fast_api_call) {
    814       __ bind(&miss_cleanup);
    815       FreeSpaceForFastApiCall(masm);
    816       __ b(miss_label);
    817     }
    818 
    819     // Invoke a regular function.
    820     __ bind(&regular_invoke);
    821     if (can_do_fast_api_call) {
    822       FreeSpaceForFastApiCall(masm);
    823     }
    824   }
    825 
    826   void CompileRegular(MacroAssembler* masm,
    827                       Handle<JSObject> object,
    828                       Register receiver,
    829                       Register scratch1,
    830                       Register scratch2,
    831                       Register scratch3,
    832                       Handle<String> name,
    833                       Handle<JSObject> interceptor_holder,
    834                       Label* miss_label) {
    835     Register holder =
    836         stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
    837                                         scratch1, scratch2, scratch3,
    838                                         name, miss_label);
    839 
    840     // Call a runtime function to load the interceptor property.
    841     FrameScope scope(masm, StackFrame::INTERNAL);
    842     // Save the name_ register across the call.
    843     __ push(name_);
    844     PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
    845     __ CallExternalReference(
    846         ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
    847                           masm->isolate()),
    848         5);
    849     // Restore the name_ register.
    850     __ pop(name_);
    851     // Leave the internal frame.
    852   }
    853 
    854   void LoadWithInterceptor(MacroAssembler* masm,
    855                            Register receiver,
    856                            Register holder,
    857                            Handle<JSObject> holder_obj,
    858                            Register scratch,
    859                            Label* interceptor_succeeded) {
    860     {
    861       FrameScope scope(masm, StackFrame::INTERNAL);
    862       __ Push(holder, name_);
    863       CompileCallLoadPropertyWithInterceptor(masm,
    864                                              receiver,
    865                                              holder,
    866                                              name_,
    867                                              holder_obj);
    868       __ pop(name_);  // Restore the name.
    869       __ pop(receiver);  // Restore the holder.
    870     }
    871     // If interceptor returns no-result sentinel, call the constant function.
    872     __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
    873     __ cmp(r0, scratch);
    874     __ b(ne, interceptor_succeeded);
    875   }
    876 
    877   StubCompiler* stub_compiler_;
    878   const ParameterCount& arguments_;
    879   Register name_;
    880   Code::ExtraICState extra_ic_state_;
    881 };
    882 
    883 
    884 // Generate code to check that a global property cell is empty. Create
    885 // the property cell at compilation time if no cell exists for the
    886 // property.
    887 static void GenerateCheckPropertyCell(MacroAssembler* masm,
    888                                       Handle<GlobalObject> global,
    889                                       Handle<String> name,
    890                                       Register scratch,
    891                                       Label* miss) {
    892   Handle<JSGlobalPropertyCell> cell =
    893       GlobalObject::EnsurePropertyCell(global, name);
    894   ASSERT(cell->value()->IsTheHole());
    895   __ mov(scratch, Operand(cell));
    896   __ ldr(scratch,
    897          FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
    898   __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
    899   __ cmp(scratch, ip);
    900   __ b(ne, miss);
    901 }
    902 
    903 
    904 // Calls GenerateCheckPropertyCell for each global object in the prototype chain
    905 // from object to (but not including) holder.
    906 static void GenerateCheckPropertyCells(MacroAssembler* masm,
    907                                        Handle<JSObject> object,
    908                                        Handle<JSObject> holder,
    909                                        Handle<String> name,
    910                                        Register scratch,
    911                                        Label* miss) {
    912   Handle<JSObject> current = object;
    913   while (!current.is_identical_to(holder)) {
    914     if (current->IsGlobalObject()) {
    915       GenerateCheckPropertyCell(masm,
    916                                 Handle<GlobalObject>::cast(current),
    917                                 name,
    918                                 scratch,
    919                                 miss);
    920     }
    921     current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
    922   }
    923 }
    924 
    925 
    926 // Convert and store int passed in register ival to IEEE 754 single precision
    927 // floating point value at memory location (dst + 4 * wordoffset)
    928 // If VFP3 is available use it for conversion.
    929 static void StoreIntAsFloat(MacroAssembler* masm,
    930                             Register dst,
    931                             Register wordoffset,
    932                             Register ival,
    933                             Register fval,
    934                             Register scratch1,
    935                             Register scratch2) {
    936   if (CpuFeatures::IsSupported(VFP3)) {
    937     CpuFeatures::Scope scope(VFP3);
    938     __ vmov(s0, ival);
    939     __ add(scratch1, dst, Operand(wordoffset, LSL, 2));
    940     __ vcvt_f32_s32(s0, s0);
    941     __ vstr(s0, scratch1, 0);
    942   } else {
    943     Label not_special, done;
    944     // Move sign bit from source to destination.  This works because the sign
    945     // bit in the exponent word of the double has the same position and polarity
    946     // as the 2's complement sign bit in a Smi.
    947     ASSERT(kBinary32SignMask == 0x80000000u);
    948 
    949     __ and_(fval, ival, Operand(kBinary32SignMask), SetCC);
    950     // Negate value if it is negative.
    951     __ rsb(ival, ival, Operand(0, RelocInfo::NONE), LeaveCC, ne);
    952 
    953     // We have -1, 0 or 1, which we treat specially. Register ival contains
    954     // absolute value: it is either equal to 1 (special case of -1 and 1),
    955     // greater than 1 (not a special case) or less than 1 (special case of 0).
    956     __ cmp(ival, Operand(1));
    957     __ b(gt, &not_special);
    958 
    959     // For 1 or -1 we need to or in the 0 exponent (biased).
    960     static const uint32_t exponent_word_for_1 =
    961         kBinary32ExponentBias << kBinary32ExponentShift;
    962 
    963     __ orr(fval, fval, Operand(exponent_word_for_1), LeaveCC, eq);
    964     __ b(&done);
    965 
    966     __ bind(&not_special);
    967     // Count leading zeros.
    968     // Gets the wrong answer for 0, but we already checked for that case above.
    969     Register zeros = scratch2;
    970     __ CountLeadingZeros(zeros, ival, scratch1);
    971 
    972     // Compute exponent and or it into the exponent register.
    973     __ rsb(scratch1,
    974            zeros,
    975            Operand((kBitsPerInt - 1) + kBinary32ExponentBias));
    976 
    977     __ orr(fval,
    978            fval,
    979            Operand(scratch1, LSL, kBinary32ExponentShift));
    980 
    981     // Shift up the source chopping the top bit off.
    982     __ add(zeros, zeros, Operand(1));
    983     // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
    984     __ mov(ival, Operand(ival, LSL, zeros));
    985     // And the top (top 20 bits).
    986     __ orr(fval,
    987            fval,
    988            Operand(ival, LSR, kBitsPerInt - kBinary32MantissaBits));
    989 
    990     __ bind(&done);
    991     __ str(fval, MemOperand(dst, wordoffset, LSL, 2));
    992   }
    993 }
    994 
    995 
    996 // Convert unsigned integer with specified number of leading zeroes in binary
    997 // representation to IEEE 754 double.
    998 // Integer to convert is passed in register hiword.
    999 // Resulting double is returned in registers hiword:loword.
   1000 // This functions does not work correctly for 0.
   1001 static void GenerateUInt2Double(MacroAssembler* masm,
   1002                                 Register hiword,
   1003                                 Register loword,
   1004                                 Register scratch,
   1005                                 int leading_zeroes) {
   1006   const int meaningful_bits = kBitsPerInt - leading_zeroes - 1;
   1007   const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits;
   1008 
   1009   const int mantissa_shift_for_hi_word =
   1010       meaningful_bits - HeapNumber::kMantissaBitsInTopWord;
   1011 
   1012   const int mantissa_shift_for_lo_word =
   1013       kBitsPerInt - mantissa_shift_for_hi_word;
   1014 
   1015   __ mov(scratch, Operand(biased_exponent << HeapNumber::kExponentShift));
   1016   if (mantissa_shift_for_hi_word > 0) {
   1017     __ mov(loword, Operand(hiword, LSL, mantissa_shift_for_lo_word));
   1018     __ orr(hiword, scratch, Operand(hiword, LSR, mantissa_shift_for_hi_word));
   1019   } else {
   1020     __ mov(loword, Operand(0, RelocInfo::NONE));
   1021     __ orr(hiword, scratch, Operand(hiword, LSL, mantissa_shift_for_hi_word));
   1022   }
   1023 
   1024   // If least significant bit of biased exponent was not 1 it was corrupted
   1025   // by most significant bit of mantissa so we should fix that.
   1026   if (!(biased_exponent & 1)) {
   1027     __ bic(hiword, hiword, Operand(1 << HeapNumber::kExponentShift));
   1028   }
   1029 }
   1030 
   1031 
   1032 #undef __
   1033 #define __ ACCESS_MASM(masm())
   1034 
   1035 
   1036 Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
   1037                                        Register object_reg,
   1038                                        Handle<JSObject> holder,
   1039                                        Register holder_reg,
   1040                                        Register scratch1,
   1041                                        Register scratch2,
   1042                                        Handle<String> name,
   1043                                        int save_at_depth,
   1044                                        Label* miss) {
   1045   // Make sure there's no overlap between holder and object registers.
   1046   ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
   1047   ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
   1048          && !scratch2.is(scratch1));
   1049 
   1050   // Keep track of the current object in register reg.
   1051   Register reg = object_reg;
   1052   int depth = 0;
   1053 
   1054   if (save_at_depth == depth) {
   1055     __ str(reg, MemOperand(sp));
   1056   }
   1057 
   1058   // Check the maps in the prototype chain.
   1059   // Traverse the prototype chain from the object and do map checks.
   1060   Handle<JSObject> current = object;
   1061   while (!current.is_identical_to(holder)) {
   1062     ++depth;
   1063 
   1064     // Only global objects and objects that do not require access
   1065     // checks are allowed in stubs.
   1066     ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
   1067 
   1068     Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
   1069     if (!current->HasFastProperties() &&
   1070         !current->IsJSGlobalObject() &&
   1071         !current->IsJSGlobalProxy()) {
   1072       if (!name->IsSymbol()) {
   1073         name = factory()->LookupSymbol(name);
   1074       }
   1075       ASSERT(current->property_dictionary()->FindEntry(*name) ==
   1076              StringDictionary::kNotFound);
   1077 
   1078       GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
   1079                                        scratch1, scratch2);
   1080 
   1081       __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
   1082       reg = holder_reg;  // From now on the object will be in holder_reg.
   1083       __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
   1084     } else {
   1085       Handle<Map> current_map(current->map());
   1086       __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK,
   1087                   ALLOW_ELEMENT_TRANSITION_MAPS);
   1088 
   1089       // Check access rights to the global object.  This has to happen after
   1090       // the map check so that we know that the object is actually a global
   1091       // object.
   1092       if (current->IsJSGlobalProxy()) {
   1093         __ CheckAccessGlobalProxy(reg, scratch2, miss);
   1094       }
   1095       reg = holder_reg;  // From now on the object will be in holder_reg.
   1096 
   1097       if (heap()->InNewSpace(*prototype)) {
   1098         // The prototype is in new space; we cannot store a reference to it
   1099         // in the code.  Load it from the map.
   1100         __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
   1101       } else {
   1102         // The prototype is in old space; load it directly.
   1103         __ mov(reg, Operand(prototype));
   1104       }
   1105     }
   1106 
   1107     if (save_at_depth == depth) {
   1108       __ str(reg, MemOperand(sp));
   1109     }
   1110 
   1111     // Go to the next object in the prototype chain.
   1112     current = prototype;
   1113   }
   1114 
   1115   // Log the check depth.
   1116   LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
   1117 
   1118   // Check the holder map.
   1119   __ CheckMap(reg, scratch1, Handle<Map>(current->map()), miss,
   1120               DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
   1121 
   1122   // Perform security check for access to the global object.
   1123   ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
   1124   if (holder->IsJSGlobalProxy()) {
   1125     __ CheckAccessGlobalProxy(reg, scratch1, miss);
   1126   }
   1127 
   1128   // If we've skipped any global objects, it's not enough to verify that
   1129   // their maps haven't changed.  We also need to check that the property
   1130   // cell for the property is still empty.
   1131   GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
   1132 
   1133   // Return the register containing the holder.
   1134   return reg;
   1135 }
   1136 
   1137 
   1138 void StubCompiler::GenerateLoadField(Handle<JSObject> object,
   1139                                      Handle<JSObject> holder,
   1140                                      Register receiver,
   1141                                      Register scratch1,
   1142                                      Register scratch2,
   1143                                      Register scratch3,
   1144                                      int index,
   1145                                      Handle<String> name,
   1146                                      Label* miss) {
   1147   // Check that the receiver isn't a smi.
   1148   __ JumpIfSmi(receiver, miss);
   1149 
   1150   // Check that the maps haven't changed.
   1151   Register reg = CheckPrototypes(
   1152       object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
   1153   GenerateFastPropertyLoad(masm(), r0, reg, holder, index);
   1154   __ Ret();
   1155 }
   1156 
   1157 
   1158 void StubCompiler::GenerateLoadConstant(Handle<JSObject> object,
   1159                                         Handle<JSObject> holder,
   1160                                         Register receiver,
   1161                                         Register scratch1,
   1162                                         Register scratch2,
   1163                                         Register scratch3,
   1164                                         Handle<JSFunction> value,
   1165                                         Handle<String> name,
   1166                                         Label* miss) {
   1167   // Check that the receiver isn't a smi.
   1168   __ JumpIfSmi(receiver, miss);
   1169 
   1170   // Check that the maps haven't changed.
   1171   CheckPrototypes(
   1172       object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
   1173 
   1174   // Return the constant value.
   1175   __ LoadHeapObject(r0, value);
   1176   __ Ret();
   1177 }
   1178 
   1179 
   1180 void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
   1181                                         Handle<JSObject> holder,
   1182                                         Register receiver,
   1183                                         Register name_reg,
   1184                                         Register scratch1,
   1185                                         Register scratch2,
   1186                                         Register scratch3,
   1187                                         Handle<AccessorInfo> callback,
   1188                                         Handle<String> name,
   1189                                         Label* miss) {
   1190   // Check that the receiver isn't a smi.
   1191   __ JumpIfSmi(receiver, miss);
   1192 
   1193   // Check that the maps haven't changed.
   1194   Register reg = CheckPrototypes(object, receiver, holder, scratch1,
   1195                                  scratch2, scratch3, name, miss);
   1196 
   1197   // Build AccessorInfo::args_ list on the stack and push property name below
   1198   // the exit frame to make GC aware of them and store pointers to them.
   1199   __ push(receiver);
   1200   __ mov(scratch2, sp);  // scratch2 = AccessorInfo::args_
   1201   if (heap()->InNewSpace(callback->data())) {
   1202     __ Move(scratch3, callback);
   1203     __ ldr(scratch3, FieldMemOperand(scratch3, AccessorInfo::kDataOffset));
   1204   } else {
   1205     __ Move(scratch3, Handle<Object>(callback->data()));
   1206   }
   1207   __ Push(reg, scratch3, name_reg);
   1208   __ mov(r0, sp);  // r0 = Handle<String>
   1209 
   1210   const int kApiStackSpace = 1;
   1211   FrameScope frame_scope(masm(), StackFrame::MANUAL);
   1212   __ EnterExitFrame(false, kApiStackSpace);
   1213 
   1214   // Create AccessorInfo instance on the stack above the exit frame with
   1215   // scratch2 (internal::Object** args_) as the data.
   1216   __ str(scratch2, MemOperand(sp, 1 * kPointerSize));
   1217   __ add(r1, sp, Operand(1 * kPointerSize));  // r1 = AccessorInfo&
   1218 
   1219   const int kStackUnwindSpace = 4;
   1220   Address getter_address = v8::ToCData<Address>(callback->getter());
   1221   ApiFunction fun(getter_address);
   1222   ExternalReference ref =
   1223       ExternalReference(&fun,
   1224                         ExternalReference::DIRECT_GETTER_CALL,
   1225                         masm()->isolate());
   1226   __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
   1227 }
   1228 
   1229 
   1230 void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
   1231                                            Handle<JSObject> interceptor_holder,
   1232                                            LookupResult* lookup,
   1233                                            Register receiver,
   1234                                            Register name_reg,
   1235                                            Register scratch1,
   1236                                            Register scratch2,
   1237                                            Register scratch3,
   1238                                            Handle<String> name,
   1239                                            Label* miss) {
   1240   ASSERT(interceptor_holder->HasNamedInterceptor());
   1241   ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
   1242 
   1243   // Check that the receiver isn't a smi.
   1244   __ JumpIfSmi(receiver, miss);
   1245 
   1246   // So far the most popular follow ups for interceptor loads are FIELD
   1247   // and CALLBACKS, so inline only them, other cases may be added
   1248   // later.
   1249   bool compile_followup_inline = false;
   1250   if (lookup->IsFound() && lookup->IsCacheable()) {
   1251     if (lookup->type() == FIELD) {
   1252       compile_followup_inline = true;
   1253     } else if (lookup->type() == CALLBACKS &&
   1254                lookup->GetCallbackObject()->IsAccessorInfo()) {
   1255       compile_followup_inline =
   1256           AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL;
   1257     }
   1258   }
   1259 
   1260   if (compile_followup_inline) {
   1261     // Compile the interceptor call, followed by inline code to load the
   1262     // property from further up the prototype chain if the call fails.
   1263     // Check that the maps haven't changed.
   1264     Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
   1265                                           scratch1, scratch2, scratch3,
   1266                                           name, miss);
   1267     ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
   1268 
   1269     // Preserve the receiver register explicitly whenever it is different from
   1270     // the holder and it is needed should the interceptor return without any
   1271     // result. The CALLBACKS case needs the receiver to be passed into C++ code,
   1272     // the FIELD case might cause a miss during the prototype check.
   1273     bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
   1274     bool must_preserve_receiver_reg = !receiver.is(holder_reg) &&
   1275         (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
   1276 
   1277     // Save necessary data before invoking an interceptor.
   1278     // Requires a frame to make GC aware of pushed pointers.
   1279     {
   1280       FrameScope frame_scope(masm(), StackFrame::INTERNAL);
   1281       if (must_preserve_receiver_reg) {
   1282         __ Push(receiver, holder_reg, name_reg);
   1283       } else {
   1284         __ Push(holder_reg, name_reg);
   1285       }
   1286       // Invoke an interceptor.  Note: map checks from receiver to
   1287       // interceptor's holder has been compiled before (see a caller
   1288       // of this method.)
   1289       CompileCallLoadPropertyWithInterceptor(masm(),
   1290                                              receiver,
   1291                                              holder_reg,
   1292                                              name_reg,
   1293                                              interceptor_holder);
   1294       // Check if interceptor provided a value for property.  If it's
   1295       // the case, return immediately.
   1296       Label interceptor_failed;
   1297       __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
   1298       __ cmp(r0, scratch1);
   1299       __ b(eq, &interceptor_failed);
   1300       frame_scope.GenerateLeaveFrame();
   1301       __ Ret();
   1302 
   1303       __ bind(&interceptor_failed);
   1304       __ pop(name_reg);
   1305       __ pop(holder_reg);
   1306       if (must_preserve_receiver_reg) {
   1307         __ pop(receiver);
   1308       }
   1309       // Leave the internal frame.
   1310     }
   1311     // Check that the maps from interceptor's holder to lookup's holder
   1312     // haven't changed.  And load lookup's holder into |holder| register.
   1313     if (must_perfrom_prototype_check) {
   1314       holder_reg = CheckPrototypes(interceptor_holder,
   1315                                    holder_reg,
   1316                                    Handle<JSObject>(lookup->holder()),
   1317                                    scratch1,
   1318                                    scratch2,
   1319                                    scratch3,
   1320                                    name,
   1321                                    miss);
   1322     }
   1323 
   1324     if (lookup->type() == FIELD) {
   1325       // We found FIELD property in prototype chain of interceptor's holder.
   1326       // Retrieve a field from field's holder.
   1327       GenerateFastPropertyLoad(masm(), r0, holder_reg,
   1328                                Handle<JSObject>(lookup->holder()),
   1329                                lookup->GetFieldIndex());
   1330       __ Ret();
   1331     } else {
   1332       // We found CALLBACKS property in prototype chain of interceptor's
   1333       // holder.
   1334       ASSERT(lookup->type() == CALLBACKS);
   1335       Handle<AccessorInfo> callback(
   1336           AccessorInfo::cast(lookup->GetCallbackObject()));
   1337       ASSERT(callback->getter() != NULL);
   1338 
   1339       // Tail call to runtime.
   1340       // Important invariant in CALLBACKS case: the code above must be
   1341       // structured to never clobber |receiver| register.
   1342       __ Move(scratch2, callback);
   1343       // holder_reg is either receiver or scratch1.
   1344       if (!receiver.is(holder_reg)) {
   1345         ASSERT(scratch1.is(holder_reg));
   1346         __ Push(receiver, holder_reg);
   1347         __ ldr(scratch3,
   1348                FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
   1349         __ Push(scratch3, scratch2, name_reg);
   1350       } else {
   1351         __ push(receiver);
   1352         __ ldr(scratch3,
   1353                FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
   1354         __ Push(holder_reg, scratch3, scratch2, name_reg);
   1355       }
   1356 
   1357       ExternalReference ref =
   1358           ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
   1359                             masm()->isolate());
   1360       __ TailCallExternalReference(ref, 5, 1);
   1361     }
   1362   } else {  // !compile_followup_inline
   1363     // Call the runtime system to load the interceptor.
   1364     // Check that the maps haven't changed.
   1365     Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
   1366                                           scratch1, scratch2, scratch3,
   1367                                           name, miss);
   1368     PushInterceptorArguments(masm(), receiver, holder_reg,
   1369                              name_reg, interceptor_holder);
   1370 
   1371     ExternalReference ref =
   1372         ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad),
   1373                           masm()->isolate());
   1374     __ TailCallExternalReference(ref, 5, 1);
   1375   }
   1376 }
   1377 
   1378 
   1379 void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
   1380   if (kind_ == Code::KEYED_CALL_IC) {
   1381     __ cmp(r2, Operand(name));
   1382     __ b(ne, miss);
   1383   }
   1384 }
   1385 
   1386 
   1387 void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
   1388                                                    Handle<JSObject> holder,
   1389                                                    Handle<String> name,
   1390                                                    Label* miss) {
   1391   ASSERT(holder->IsGlobalObject());
   1392 
   1393   // Get the number of arguments.
   1394   const int argc = arguments().immediate();
   1395 
   1396   // Get the receiver from the stack.
   1397   __ ldr(r0, MemOperand(sp, argc * kPointerSize));
   1398 
   1399   // Check that the maps haven't changed.
   1400   __ JumpIfSmi(r0, miss);
   1401   CheckPrototypes(object, r0, holder, r3, r1, r4, name, miss);
   1402 }
   1403 
   1404 
   1405 void CallStubCompiler::GenerateLoadFunctionFromCell(
   1406     Handle<JSGlobalPropertyCell> cell,
   1407     Handle<JSFunction> function,
   1408     Label* miss) {
   1409   // Get the value from the cell.
   1410   __ mov(r3, Operand(cell));
   1411   __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
   1412 
   1413   // Check that the cell contains the same function.
   1414   if (heap()->InNewSpace(*function)) {
   1415     // We can't embed a pointer to a function in new space so we have
   1416     // to verify that the shared function info is unchanged. This has
   1417     // the nice side effect that multiple closures based on the same
   1418     // function can all use this call IC. Before we load through the
   1419     // function, we have to verify that it still is a function.
   1420     __ JumpIfSmi(r1, miss);
   1421     __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
   1422     __ b(ne, miss);
   1423 
   1424     // Check the shared function info. Make sure it hasn't changed.
   1425     __ Move(r3, Handle<SharedFunctionInfo>(function->shared()));
   1426     __ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
   1427     __ cmp(r4, r3);
   1428   } else {
   1429     __ cmp(r1, Operand(function));
   1430   }
   1431   __ b(ne, miss);
   1432 }
   1433 
   1434 
   1435 void CallStubCompiler::GenerateMissBranch() {
   1436   Handle<Code> code =
   1437       isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
   1438                                                kind_,
   1439                                                extra_state_);
   1440   __ Jump(code, RelocInfo::CODE_TARGET);
   1441 }
   1442 
   1443 
   1444 Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
   1445                                                 Handle<JSObject> holder,
   1446                                                 int index,
   1447                                                 Handle<String> name) {
   1448   // ----------- S t a t e -------------
   1449   //  -- r2    : name
   1450   //  -- lr    : return address
   1451   // -----------------------------------
   1452   Label miss;
   1453 
   1454   GenerateNameCheck(name, &miss);
   1455 
   1456   const int argc = arguments().immediate();
   1457 
   1458   // Get the receiver of the function from the stack into r0.
   1459   __ ldr(r0, MemOperand(sp, argc * kPointerSize));
   1460   // Check that the receiver isn't a smi.
   1461   __ JumpIfSmi(r0, &miss);
   1462 
   1463   // Do the right check and compute the holder register.
   1464   Register reg = CheckPrototypes(object, r0, holder, r1, r3, r4, name, &miss);
   1465   GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
   1466 
   1467   GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
   1468 
   1469   // Handle call cache miss.
   1470   __ bind(&miss);
   1471   GenerateMissBranch();
   1472 
   1473   // Return the generated code.
   1474   return GetCode(FIELD, name);
   1475 }
   1476 
   1477 
   1478 Handle<Code> CallStubCompiler::CompileArrayPushCall(
   1479     Handle<Object> object,
   1480     Handle<JSObject> holder,
   1481     Handle<JSGlobalPropertyCell> cell,
   1482     Handle<JSFunction> function,
   1483     Handle<String> name) {
   1484   // ----------- S t a t e -------------
   1485   //  -- r2    : name
   1486   //  -- lr    : return address
   1487   //  -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
   1488   //  -- ...
   1489   //  -- sp[argc * 4]           : receiver
   1490   // -----------------------------------
   1491 
   1492   // If object is not an array, bail out to regular call.
   1493   if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
   1494 
   1495   Label miss;
   1496   GenerateNameCheck(name, &miss);
   1497 
   1498   Register receiver = r1;
   1499   // Get the receiver from the stack
   1500   const int argc = arguments().immediate();
   1501   __ ldr(receiver, MemOperand(sp, argc * kPointerSize));
   1502 
   1503   // Check that the receiver isn't a smi.
   1504   __ JumpIfSmi(receiver, &miss);
   1505 
   1506   // Check that the maps haven't changed.
   1507   CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, r3, r0, r4,
   1508                   name, &miss);
   1509 
   1510   if (argc == 0) {
   1511     // Nothing to do, just return the length.
   1512     __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
   1513     __ Drop(argc + 1);
   1514     __ Ret();
   1515   } else {
   1516     Label call_builtin;
   1517 
   1518     if (argc == 1) {  // Otherwise fall through to call the builtin.
   1519       Label attempt_to_grow_elements;
   1520 
   1521       Register elements = r6;
   1522       Register end_elements = r5;
   1523       // Get the elements array of the object.
   1524       __ ldr(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
   1525 
   1526       // Check that the elements are in fast mode and writable.
   1527       __ CheckMap(elements,
   1528                   r0,
   1529                   Heap::kFixedArrayMapRootIndex,
   1530                   &call_builtin,
   1531                   DONT_DO_SMI_CHECK);
   1532 
   1533 
   1534       // Get the array's length into r0 and calculate new length.
   1535       __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
   1536       STATIC_ASSERT(kSmiTagSize == 1);
   1537       STATIC_ASSERT(kSmiTag == 0);
   1538       __ add(r0, r0, Operand(Smi::FromInt(argc)));
   1539 
   1540       // Get the elements' length.
   1541       __ ldr(r4, FieldMemOperand(elements, FixedArray::kLengthOffset));
   1542 
   1543       // Check if we could survive without allocation.
   1544       __ cmp(r0, r4);
   1545       __ b(gt, &attempt_to_grow_elements);
   1546 
   1547       // Check if value is a smi.
   1548       Label with_write_barrier;
   1549       __ ldr(r4, MemOperand(sp, (argc - 1) * kPointerSize));
   1550       __ JumpIfNotSmi(r4, &with_write_barrier);
   1551 
   1552       // Save new length.
   1553       __ str(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
   1554 
   1555       // Store the value.
   1556       // We may need a register containing the address end_elements below,
   1557       // so write back the value in end_elements.
   1558       __ add(end_elements, elements,
   1559              Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
   1560       const int kEndElementsOffset =
   1561           FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
   1562       __ str(r4, MemOperand(end_elements, kEndElementsOffset, PreIndex));
   1563 
   1564       // Check for a smi.
   1565       __ Drop(argc + 1);
   1566       __ Ret();
   1567 
   1568       __ bind(&with_write_barrier);
   1569 
   1570       __ ldr(r3, FieldMemOperand(receiver, HeapObject::kMapOffset));
   1571 
   1572       if (FLAG_smi_only_arrays  && !FLAG_trace_elements_transitions) {
   1573         Label fast_object, not_fast_object;
   1574         __ CheckFastObjectElements(r3, r7, &not_fast_object);
   1575         __ jmp(&fast_object);
   1576         // In case of fast smi-only, convert to fast object, otherwise bail out.
   1577         __ bind(&not_fast_object);
   1578         __ CheckFastSmiOnlyElements(r3, r7, &call_builtin);
   1579         // edx: receiver
   1580         // r3: map
   1581         __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
   1582                                                FAST_ELEMENTS,
   1583                                                r3,
   1584                                                r7,
   1585                                                &call_builtin);
   1586         __ mov(r2, receiver);
   1587         ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm());
   1588         __ bind(&fast_object);
   1589       } else {
   1590         __ CheckFastObjectElements(r3, r3, &call_builtin);
   1591       }
   1592 
   1593       // Save new length.
   1594       __ str(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
   1595 
   1596       // Store the value.
   1597       // We may need a register containing the address end_elements below,
   1598       // so write back the value in end_elements.
   1599       __ add(end_elements, elements,
   1600              Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
   1601       __ str(r4, MemOperand(end_elements, kEndElementsOffset, PreIndex));
   1602 
   1603       __ RecordWrite(elements,
   1604                      end_elements,
   1605                      r4,
   1606                      kLRHasNotBeenSaved,
   1607                      kDontSaveFPRegs,
   1608                      EMIT_REMEMBERED_SET,
   1609                      OMIT_SMI_CHECK);
   1610       __ Drop(argc + 1);
   1611       __ Ret();
   1612 
   1613       __ bind(&attempt_to_grow_elements);
   1614       // r0: array's length + 1.
   1615       // r4: elements' length.
   1616 
   1617       if (!FLAG_inline_new) {
   1618         __ b(&call_builtin);
   1619       }
   1620 
   1621       __ ldr(r2, MemOperand(sp, (argc - 1) * kPointerSize));
   1622       // Growing elements that are SMI-only requires special handling in case
   1623       // the new element is non-Smi. For now, delegate to the builtin.
   1624       Label no_fast_elements_check;
   1625       __ JumpIfSmi(r2, &no_fast_elements_check);
   1626       __ ldr(r7, FieldMemOperand(receiver, HeapObject::kMapOffset));
   1627       __ CheckFastObjectElements(r7, r7, &call_builtin);
   1628       __ bind(&no_fast_elements_check);
   1629 
   1630       Isolate* isolate = masm()->isolate();
   1631       ExternalReference new_space_allocation_top =
   1632           ExternalReference::new_space_allocation_top_address(isolate);
   1633       ExternalReference new_space_allocation_limit =
   1634           ExternalReference::new_space_allocation_limit_address(isolate);
   1635 
   1636       const int kAllocationDelta = 4;
   1637       // Load top and check if it is the end of elements.
   1638       __ add(end_elements, elements,
   1639              Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
   1640       __ add(end_elements, end_elements, Operand(kEndElementsOffset));
   1641       __ mov(r7, Operand(new_space_allocation_top));
   1642       __ ldr(r3, MemOperand(r7));
   1643       __ cmp(end_elements, r3);
   1644       __ b(ne, &call_builtin);
   1645 
   1646       __ mov(r9, Operand(new_space_allocation_limit));
   1647       __ ldr(r9, MemOperand(r9));
   1648       __ add(r3, r3, Operand(kAllocationDelta * kPointerSize));
   1649       __ cmp(r3, r9);
   1650       __ b(hi, &call_builtin);
   1651 
   1652       // We fit and could grow elements.
   1653       // Update new_space_allocation_top.
   1654       __ str(r3, MemOperand(r7));
   1655       // Push the argument.
   1656       __ str(r2, MemOperand(end_elements));
   1657       // Fill the rest with holes.
   1658       __ LoadRoot(r3, Heap::kTheHoleValueRootIndex);
   1659       for (int i = 1; i < kAllocationDelta; i++) {
   1660         __ str(r3, MemOperand(end_elements, i * kPointerSize));
   1661       }
   1662 
   1663       // Update elements' and array's sizes.
   1664       __ str(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
   1665       __ add(r4, r4, Operand(Smi::FromInt(kAllocationDelta)));
   1666       __ str(r4, FieldMemOperand(elements, FixedArray::kLengthOffset));
   1667 
   1668       // Elements are in new space, so write barrier is not required.
   1669       __ Drop(argc + 1);
   1670       __ Ret();
   1671     }
   1672     __ bind(&call_builtin);
   1673     __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
   1674                                                    masm()->isolate()),
   1675                                  argc + 1,
   1676                                  1);
   1677   }
   1678 
   1679   // Handle call cache miss.
   1680   __ bind(&miss);
   1681   GenerateMissBranch();
   1682 
   1683   // Return the generated code.
   1684   return GetCode(function);
   1685 }
   1686 
   1687 
   1688 Handle<Code> CallStubCompiler::CompileArrayPopCall(
   1689     Handle<Object> object,
   1690     Handle<JSObject> holder,
   1691     Handle<JSGlobalPropertyCell> cell,
   1692     Handle<JSFunction> function,
   1693     Handle<String> name) {
   1694   // ----------- S t a t e -------------
   1695   //  -- r2    : name
   1696   //  -- lr    : return address
   1697   //  -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
   1698   //  -- ...
   1699   //  -- sp[argc * 4]           : receiver
   1700   // -----------------------------------
   1701 
   1702   // If object is not an array, bail out to regular call.
   1703   if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
   1704 
   1705   Label miss, return_undefined, call_builtin;
   1706   Register receiver = r1;
   1707   Register elements = r3;
   1708   GenerateNameCheck(name, &miss);
   1709 
   1710   // Get the receiver from the stack
   1711   const int argc = arguments().immediate();
   1712   __ ldr(receiver, MemOperand(sp, argc * kPointerSize));
   1713   // Check that the receiver isn't a smi.
   1714   __ JumpIfSmi(receiver, &miss);
   1715 
   1716   // Check that the maps haven't changed.
   1717   CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
   1718                   r4, r0, name, &miss);
   1719 
   1720   // Get the elements array of the object.
   1721   __ ldr(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
   1722 
   1723   // Check that the elements are in fast mode and writable.
   1724   __ CheckMap(elements,
   1725               r0,
   1726               Heap::kFixedArrayMapRootIndex,
   1727               &call_builtin,
   1728               DONT_DO_SMI_CHECK);
   1729 
   1730   // Get the array's length into r4 and calculate new length.
   1731   __ ldr(r4, FieldMemOperand(receiver, JSArray::kLengthOffset));
   1732   __ sub(r4, r4, Operand(Smi::FromInt(1)), SetCC);
   1733   __ b(lt, &return_undefined);
   1734 
   1735   // Get the last element.
   1736   __ LoadRoot(r6, Heap::kTheHoleValueRootIndex);
   1737   STATIC_ASSERT(kSmiTagSize == 1);
   1738   STATIC_ASSERT(kSmiTag == 0);
   1739   // We can't address the last element in one operation. Compute the more
   1740   // expensive shift first, and use an offset later on.
   1741   __ add(elements, elements, Operand(r4, LSL, kPointerSizeLog2 - kSmiTagSize));
   1742   __ ldr(r0, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag));
   1743   __ cmp(r0, r6);
   1744   __ b(eq, &call_builtin);
   1745 
   1746   // Set the array's length.
   1747   __ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset));
   1748 
   1749   // Fill with the hole.
   1750   __ str(r6, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag));
   1751   __ Drop(argc + 1);
   1752   __ Ret();
   1753 
   1754   __ bind(&return_undefined);
   1755   __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
   1756   __ Drop(argc + 1);
   1757   __ Ret();
   1758 
   1759   __ bind(&call_builtin);
   1760   __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop,
   1761                                                  masm()->isolate()),
   1762                                argc + 1,
   1763                                1);
   1764 
   1765   // Handle call cache miss.
   1766   __ bind(&miss);
   1767   GenerateMissBranch();
   1768 
   1769   // Return the generated code.
   1770   return GetCode(function);
   1771 }
   1772 
   1773 
   1774 Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
   1775     Handle<Object> object,
   1776     Handle<JSObject> holder,
   1777     Handle<JSGlobalPropertyCell> cell,
   1778     Handle<JSFunction> function,
   1779     Handle<String> name) {
   1780   // ----------- S t a t e -------------
   1781   //  -- r2                     : function name
   1782   //  -- lr                     : return address
   1783   //  -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
   1784   //  -- ...
   1785   //  -- sp[argc * 4]           : receiver
   1786   // -----------------------------------
   1787 
   1788   // If object is not a string, bail out to regular call.
   1789   if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
   1790 
   1791   const int argc = arguments().immediate();
   1792   Label miss;
   1793   Label name_miss;
   1794   Label index_out_of_range;
   1795   Label* index_out_of_range_label = &index_out_of_range;
   1796 
   1797   if (kind_ == Code::CALL_IC &&
   1798       (CallICBase::StringStubState::decode(extra_state_) ==
   1799        DEFAULT_STRING_STUB)) {
   1800     index_out_of_range_label = &miss;
   1801   }
   1802   GenerateNameCheck(name, &name_miss);
   1803 
   1804   // Check that the maps starting from the prototype haven't changed.
   1805   GenerateDirectLoadGlobalFunctionPrototype(masm(),
   1806                                             Context::STRING_FUNCTION_INDEX,
   1807                                             r0,
   1808                                             &miss);
   1809   ASSERT(!object.is_identical_to(holder));
   1810   CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
   1811                   r0, holder, r1, r3, r4, name, &miss);
   1812 
   1813   Register receiver = r1;
   1814   Register index = r4;
   1815   Register result = r0;
   1816   __ ldr(receiver, MemOperand(sp, argc * kPointerSize));
   1817   if (argc > 0) {
   1818     __ ldr(index, MemOperand(sp, (argc - 1) * kPointerSize));
   1819   } else {
   1820     __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
   1821   }
   1822 
   1823   StringCharCodeAtGenerator generator(receiver,
   1824                                       index,
   1825                                       result,
   1826                                       &miss,  // When not a string.
   1827                                       &miss,  // When not a number.
   1828                                       index_out_of_range_label,
   1829                                       STRING_INDEX_IS_NUMBER);
   1830   generator.GenerateFast(masm());
   1831   __ Drop(argc + 1);
   1832   __ Ret();
   1833 
   1834   StubRuntimeCallHelper call_helper;
   1835   generator.GenerateSlow(masm(), call_helper);
   1836 
   1837   if (index_out_of_range.is_linked()) {
   1838     __ bind(&index_out_of_range);
   1839     __ LoadRoot(r0, Heap::kNanValueRootIndex);
   1840     __ Drop(argc + 1);
   1841     __ Ret();
   1842   }
   1843 
   1844   __ bind(&miss);
   1845   // Restore function name in r2.
   1846   __ Move(r2, name);
   1847   __ bind(&name_miss);
   1848   GenerateMissBranch();
   1849 
   1850   // Return the generated code.
   1851   return GetCode(function);
   1852 }
   1853 
   1854 
   1855 Handle<Code> CallStubCompiler::CompileStringCharAtCall(
   1856     Handle<Object> object,
   1857     Handle<JSObject> holder,
   1858     Handle<JSGlobalPropertyCell> cell,
   1859     Handle<JSFunction> function,
   1860     Handle<String> name) {
   1861   // ----------- S t a t e -------------
   1862   //  -- r2                     : function name
   1863   //  -- lr                     : return address
   1864   //  -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
   1865   //  -- ...
   1866   //  -- sp[argc * 4]           : receiver
   1867   // -----------------------------------
   1868 
   1869   // If object is not a string, bail out to regular call.
   1870   if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
   1871 
   1872   const int argc = arguments().immediate();
   1873   Label miss;
   1874   Label name_miss;
   1875   Label index_out_of_range;
   1876   Label* index_out_of_range_label = &index_out_of_range;
   1877   if (kind_ == Code::CALL_IC &&
   1878       (CallICBase::StringStubState::decode(extra_state_) ==
   1879        DEFAULT_STRING_STUB)) {
   1880     index_out_of_range_label = &miss;
   1881   }
   1882   GenerateNameCheck(name, &name_miss);
   1883 
   1884   // Check that the maps starting from the prototype haven't changed.
   1885   GenerateDirectLoadGlobalFunctionPrototype(masm(),
   1886                                             Context::STRING_FUNCTION_INDEX,
   1887                                             r0,
   1888                                             &miss);
   1889   ASSERT(!object.is_identical_to(holder));
   1890   CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
   1891                   r0, holder, r1, r3, r4, name, &miss);
   1892 
   1893   Register receiver = r0;
   1894   Register index = r4;
   1895   Register scratch = r3;
   1896   Register result = r0;
   1897   __ ldr(receiver, MemOperand(sp, argc * kPointerSize));
   1898   if (argc > 0) {
   1899     __ ldr(index, MemOperand(sp, (argc - 1) * kPointerSize));
   1900   } else {
   1901     __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
   1902   }
   1903 
   1904   StringCharAtGenerator generator(receiver,
   1905                                   index,
   1906                                   scratch,
   1907                                   result,
   1908                                   &miss,  // When not a string.
   1909                                   &miss,  // When not a number.
   1910                                   index_out_of_range_label,
   1911                                   STRING_INDEX_IS_NUMBER);
   1912   generator.GenerateFast(masm());
   1913   __ Drop(argc + 1);
   1914   __ Ret();
   1915 
   1916   StubRuntimeCallHelper call_helper;
   1917   generator.GenerateSlow(masm(), call_helper);
   1918 
   1919   if (index_out_of_range.is_linked()) {
   1920     __ bind(&index_out_of_range);
   1921     __ LoadRoot(r0, Heap::kEmptyStringRootIndex);
   1922     __ Drop(argc + 1);
   1923     __ Ret();
   1924   }
   1925 
   1926   __ bind(&miss);
   1927   // Restore function name in r2.
   1928   __ Move(r2, name);
   1929   __ bind(&name_miss);
   1930   GenerateMissBranch();
   1931 
   1932   // Return the generated code.
   1933   return GetCode(function);
   1934 }
   1935 
   1936 
   1937 Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
   1938     Handle<Object> object,
   1939     Handle<JSObject> holder,
   1940     Handle<JSGlobalPropertyCell> cell,
   1941     Handle<JSFunction> function,
   1942     Handle<String> name) {
   1943   // ----------- S t a t e -------------
   1944   //  -- r2                     : function name
   1945   //  -- lr                     : return address
   1946   //  -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
   1947   //  -- ...
   1948   //  -- sp[argc * 4]           : receiver
   1949   // -----------------------------------
   1950 
   1951   const int argc = arguments().immediate();
   1952 
   1953   // If the object is not a JSObject or we got an unexpected number of
   1954   // arguments, bail out to the regular call.
   1955   if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
   1956 
   1957   Label miss;
   1958   GenerateNameCheck(name, &miss);
   1959 
   1960   if (cell.is_null()) {
   1961     __ ldr(r1, MemOperand(sp, 1 * kPointerSize));
   1962 
   1963     STATIC_ASSERT(kSmiTag == 0);
   1964     __ JumpIfSmi(r1, &miss);
   1965 
   1966     CheckPrototypes(Handle<JSObject>::cast(object), r1, holder, r0, r3, r4,
   1967                     name, &miss);
   1968   } else {
   1969     ASSERT(cell->value() == *function);
   1970     GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
   1971                                 &miss);
   1972     GenerateLoadFunctionFromCell(cell, function, &miss);
   1973   }
   1974 
   1975   // Load the char code argument.
   1976   Register code = r1;
   1977   __ ldr(code, MemOperand(sp, 0 * kPointerSize));
   1978 
   1979   // Check the code is a smi.
   1980   Label slow;
   1981   STATIC_ASSERT(kSmiTag == 0);
   1982   __ JumpIfNotSmi(code, &slow);
   1983 
   1984   // Convert the smi code to uint16.
   1985   __ and_(code, code, Operand(Smi::FromInt(0xffff)));
   1986 
   1987   StringCharFromCodeGenerator generator(code, r0);
   1988   generator.GenerateFast(masm());
   1989   __ Drop(argc + 1);
   1990   __ Ret();
   1991 
   1992   StubRuntimeCallHelper call_helper;
   1993   generator.GenerateSlow(masm(), call_helper);
   1994 
   1995   // Tail call the full function. We do not have to patch the receiver
   1996   // because the function makes no use of it.
   1997   __ bind(&slow);
   1998   __ InvokeFunction(
   1999       function,  arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
   2000 
   2001   __ bind(&miss);
   2002   // r2: function name.
   2003   GenerateMissBranch();
   2004 
   2005   // Return the generated code.
   2006   return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
   2007 }
   2008 
   2009 
   2010 Handle<Code> CallStubCompiler::CompileMathFloorCall(
   2011     Handle<Object> object,
   2012     Handle<JSObject> holder,
   2013     Handle<JSGlobalPropertyCell> cell,
   2014     Handle<JSFunction> function,
   2015     Handle<String> name) {
   2016   // ----------- S t a t e -------------
   2017   //  -- r2                     : function name
   2018   //  -- lr                     : return address
   2019   //  -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
   2020   //  -- ...
   2021   //  -- sp[argc * 4]           : receiver
   2022   // -----------------------------------
   2023 
   2024   if (!CpuFeatures::IsSupported(VFP3)) {
   2025     return Handle<Code>::null();
   2026   }
   2027 
   2028   CpuFeatures::Scope scope_vfp3(VFP3);
   2029   const int argc = arguments().immediate();
   2030   // If the object is not a JSObject or we got an unexpected number of
   2031   // arguments, bail out to the regular call.
   2032   if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
   2033 
   2034   Label miss, slow;
   2035   GenerateNameCheck(name, &miss);
   2036 
   2037   if (cell.is_null()) {
   2038     __ ldr(r1, MemOperand(sp, 1 * kPointerSize));
   2039     STATIC_ASSERT(kSmiTag == 0);
   2040     __ JumpIfSmi(r1, &miss);
   2041     CheckPrototypes(Handle<JSObject>::cast(object), r1, holder, r0, r3, r4,
   2042                     name, &miss);
   2043   } else {
   2044     ASSERT(cell->value() == *function);
   2045     GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
   2046                                 &miss);
   2047     GenerateLoadFunctionFromCell(cell, function, &miss);
   2048   }
   2049 
   2050   // Load the (only) argument into r0.
   2051   __ ldr(r0, MemOperand(sp, 0 * kPointerSize));
   2052 
   2053   // If the argument is a smi, just return.
   2054   STATIC_ASSERT(kSmiTag == 0);
   2055   __ tst(r0, Operand(kSmiTagMask));
   2056   __ Drop(argc + 1, eq);
   2057   __ Ret(eq);
   2058 
   2059   __ CheckMap(r0, r1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
   2060 
   2061   Label wont_fit_smi, no_vfp_exception, restore_fpscr_and_return;
   2062 
   2063   // If vfp3 is enabled, we use the fpu rounding with the RM (round towards
   2064   // minus infinity) mode.
   2065 
   2066   // Load the HeapNumber value.
   2067   // We will need access to the value in the core registers, so we load it
   2068   // with ldrd and move it to the fpu. It also spares a sub instruction for
   2069   // updating the HeapNumber value address, as vldr expects a multiple
   2070   // of 4 offset.
   2071   __ Ldrd(r4, r5, FieldMemOperand(r0, HeapNumber::kValueOffset));
   2072   __ vmov(d1, r4, r5);
   2073 
   2074   // Backup FPSCR.
   2075   __ vmrs(r3);
   2076   // Set custom FPCSR:
   2077   //  - Set rounding mode to "Round towards Minus Infinity"
   2078   //    (i.e. bits [23:22] = 0b10).
   2079   //  - Clear vfp cumulative exception flags (bits [3:0]).
   2080   //  - Make sure Flush-to-zero mode control bit is unset (bit 22).
   2081   __ bic(r9, r3,
   2082       Operand(kVFPExceptionMask | kVFPRoundingModeMask | kVFPFlushToZeroMask));
   2083   __ orr(r9, r9, Operand(kRoundToMinusInf));
   2084   __ vmsr(r9);
   2085 
   2086   // Convert the argument to an integer.
   2087   __ vcvt_s32_f64(s0, d1, kFPSCRRounding);
   2088 
   2089   // Use vcvt latency to start checking for special cases.
   2090   // Get the argument exponent and clear the sign bit.
   2091   __ bic(r6, r5, Operand(HeapNumber::kSignMask));
   2092   __ mov(r6, Operand(r6, LSR, HeapNumber::kMantissaBitsInTopWord));
   2093 
   2094   // Retrieve FPSCR and check for vfp exceptions.
   2095   __ vmrs(r9);
   2096   __ tst(r9, Operand(kVFPExceptionMask));
   2097   __ b(&no_vfp_exception, eq);
   2098 
   2099   // Check for NaN, Infinity, and -Infinity.
   2100   // They are invariant through a Math.Floor call, so just
   2101   // return the original argument.
   2102   __ sub(r7, r6, Operand(HeapNumber::kExponentMask
   2103         >> HeapNumber::kMantissaBitsInTopWord), SetCC);
   2104   __ b(&restore_fpscr_and_return, eq);
   2105   // We had an overflow or underflow in the conversion. Check if we
   2106   // have a big exponent.
   2107   __ cmp(r7, Operand(HeapNumber::kMantissaBits));
   2108   // If greater or equal, the argument is already round and in r0.
   2109   __ b(&restore_fpscr_and_return, ge);
   2110   __ b(&wont_fit_smi);
   2111 
   2112   __ bind(&no_vfp_exception);
   2113   // Move the result back to general purpose register r0.
   2114   __ vmov(r0, s0);
   2115   // Check if the result fits into a smi.
   2116   __ add(r1, r0, Operand(0x40000000), SetCC);
   2117   __ b(&wont_fit_smi, mi);
   2118   // Tag the result.
   2119   STATIC_ASSERT(kSmiTag == 0);
   2120   __ mov(r0, Operand(r0, LSL, kSmiTagSize));
   2121 
   2122   // Check for -0.
   2123   __ cmp(r0, Operand(0, RelocInfo::NONE));
   2124   __ b(&restore_fpscr_and_return, ne);
   2125   // r5 already holds the HeapNumber exponent.
   2126   __ tst(r5, Operand(HeapNumber::kSignMask));
   2127   // If our HeapNumber is negative it was -0, so load its address and return.
   2128   // Else r0 is loaded with 0, so we can also just return.
   2129   __ ldr(r0, MemOperand(sp, 0 * kPointerSize), ne);
   2130 
   2131   __ bind(&restore_fpscr_and_return);
   2132   // Restore FPSCR and return.
   2133   __ vmsr(r3);
   2134   __ Drop(argc + 1);
   2135   __ Ret();
   2136 
   2137   __ bind(&wont_fit_smi);
   2138   // Restore FPCSR and fall to slow case.
   2139   __ vmsr(r3);
   2140 
   2141   __ bind(&slow);
   2142   // Tail call the full function. We do not have to patch the receiver
   2143   // because the function makes no use of it.
   2144   __ InvokeFunction(
   2145       function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
   2146 
   2147   __ bind(&miss);
   2148   // r2: function name.
   2149   GenerateMissBranch();
   2150 
   2151   // Return the generated code.
   2152   return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
   2153 }
   2154 
   2155 
   2156 Handle<Code> CallStubCompiler::CompileMathAbsCall(
   2157     Handle<Object> object,
   2158     Handle<JSObject> holder,
   2159     Handle<JSGlobalPropertyCell> cell,
   2160     Handle<JSFunction> function,
   2161     Handle<String> name) {
   2162   // ----------- S t a t e -------------
   2163   //  -- r2                     : function name
   2164   //  -- lr                     : return address
   2165   //  -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
   2166   //  -- ...
   2167   //  -- sp[argc * 4]           : receiver
   2168   // -----------------------------------
   2169 
   2170   const int argc = arguments().immediate();
   2171   // If the object is not a JSObject or we got an unexpected number of
   2172   // arguments, bail out to the regular call.
   2173   if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
   2174 
   2175   Label miss;
   2176   GenerateNameCheck(name, &miss);
   2177   if (cell.is_null()) {
   2178     __ ldr(r1, MemOperand(sp, 1 * kPointerSize));
   2179     STATIC_ASSERT(kSmiTag == 0);
   2180     __ JumpIfSmi(r1, &miss);
   2181     CheckPrototypes(Handle<JSObject>::cast(object), r1, holder, r0, r3, r4,
   2182                     name, &miss);
   2183   } else {
   2184     ASSERT(cell->value() == *function);
   2185     GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
   2186                                 &miss);
   2187     GenerateLoadFunctionFromCell(cell, function, &miss);
   2188   }
   2189 
   2190   // Load the (only) argument into r0.
   2191   __ ldr(r0, MemOperand(sp, 0 * kPointerSize));
   2192 
   2193   // Check if the argument is a smi.
   2194   Label not_smi;
   2195   STATIC_ASSERT(kSmiTag == 0);
   2196   __ JumpIfNotSmi(r0, &not_smi);
   2197 
   2198   // Do bitwise not or do nothing depending on the sign of the
   2199   // argument.
   2200   __ eor(r1, r0, Operand(r0, ASR, kBitsPerInt - 1));
   2201 
   2202   // Add 1 or do nothing depending on the sign of the argument.
   2203   __ sub(r0, r1, Operand(r0, ASR, kBitsPerInt - 1), SetCC);
   2204 
   2205   // If the result is still negative, go to the slow case.
   2206   // This only happens for the most negative smi.
   2207   Label slow;
   2208   __ b(mi, &slow);
   2209 
   2210   // Smi case done.
   2211   __ Drop(argc + 1);
   2212   __ Ret();
   2213 
   2214   // Check if the argument is a heap number and load its exponent and
   2215   // sign.
   2216   __ bind(&not_smi);
   2217   __ CheckMap(r0, r1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
   2218   __ ldr(r1, FieldMemOperand(r0, HeapNumber::kExponentOffset));
   2219 
   2220   // Check the sign of the argument. If the argument is positive,
   2221   // just return it.
   2222   Label negative_sign;
   2223   __ tst(r1, Operand(HeapNumber::kSignMask));
   2224   __ b(ne, &negative_sign);
   2225   __ Drop(argc + 1);
   2226   __ Ret();
   2227 
   2228   // If the argument is negative, clear the sign, and return a new
   2229   // number.
   2230   __ bind(&negative_sign);
   2231   __ eor(r1, r1, Operand(HeapNumber::kSignMask));
   2232   __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
   2233   __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
   2234   __ AllocateHeapNumber(r0, r4, r5, r6, &slow);
   2235   __ str(r1, FieldMemOperand(r0, HeapNumber::kExponentOffset));
   2236   __ str(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
   2237   __ Drop(argc + 1);
   2238   __ Ret();
   2239 
   2240   // Tail call the full function. We do not have to patch the receiver
   2241   // because the function makes no use of it.
   2242   __ bind(&slow);
   2243   __ InvokeFunction(
   2244       function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
   2245 
   2246   __ bind(&miss);
   2247   // r2: function name.
   2248   GenerateMissBranch();
   2249 
   2250   // Return the generated code.
   2251   return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
   2252 }
   2253 
   2254 
   2255 Handle<Code> CallStubCompiler::CompileFastApiCall(
   2256     const CallOptimization& optimization,
   2257     Handle<Object> object,
   2258     Handle<JSObject> holder,
   2259     Handle<JSGlobalPropertyCell> cell,
   2260     Handle<JSFunction> function,
   2261     Handle<String> name) {
   2262   Counters* counters = isolate()->counters();
   2263 
   2264   ASSERT(optimization.is_simple_api_call());
   2265   // Bail out if object is a global object as we don't want to
   2266   // repatch it to global receiver.
   2267   if (object->IsGlobalObject()) return Handle<Code>::null();
   2268   if (!cell.is_null()) return Handle<Code>::null();
   2269   if (!object->IsJSObject()) return Handle<Code>::null();
   2270   int depth = optimization.GetPrototypeDepthOfExpectedType(
   2271       Handle<JSObject>::cast(object), holder);
   2272   if (depth == kInvalidProtoDepth) return Handle<Code>::null();
   2273 
   2274   Label miss, miss_before_stack_reserved;
   2275   GenerateNameCheck(name, &miss_before_stack_reserved);
   2276 
   2277   // Get the receiver from the stack.
   2278   const int argc = arguments().immediate();
   2279   __ ldr(r1, MemOperand(sp, argc * kPointerSize));
   2280 
   2281   // Check that the receiver isn't a smi.
   2282   __ JumpIfSmi(r1, &miss_before_stack_reserved);
   2283 
   2284   __ IncrementCounter(counters->call_const(), 1, r0, r3);
   2285   __ IncrementCounter(counters->call_const_fast_api(), 1, r0, r3);
   2286 
   2287   ReserveSpaceForFastApiCall(masm(), r0);
   2288 
   2289   // Check that the maps haven't changed and find a Holder as a side effect.
   2290   CheckPrototypes(Handle<JSObject>::cast(object), r1, holder, r0, r3, r4, name,
   2291                   depth, &miss);
   2292 
   2293   GenerateFastApiDirectCall(masm(), optimization, argc);
   2294 
   2295   __ bind(&miss);
   2296   FreeSpaceForFastApiCall(masm());
   2297 
   2298   __ bind(&miss_before_stack_reserved);
   2299   GenerateMissBranch();
   2300 
   2301   // Return the generated code.
   2302   return GetCode(function);
   2303 }
   2304 
   2305 
   2306 Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
   2307                                                    Handle<JSObject> holder,
   2308                                                    Handle<JSFunction> function,
   2309                                                    Handle<String> name,
   2310                                                    CheckType check) {
   2311   // ----------- S t a t e -------------
   2312   //  -- r2    : name
   2313   //  -- lr    : return address
   2314   // -----------------------------------
   2315   if (HasCustomCallGenerator(function)) {
   2316     Handle<Code> code = CompileCustomCall(object, holder,
   2317                                           Handle<JSGlobalPropertyCell>::null(),
   2318                                           function, name);
   2319     // A null handle means bail out to the regular compiler code below.
   2320     if (!code.is_null()) return code;
   2321   }
   2322 
   2323   Label miss;
   2324   GenerateNameCheck(name, &miss);
   2325 
   2326   // Get the receiver from the stack
   2327   const int argc = arguments().immediate();
   2328   __ ldr(r1, MemOperand(sp, argc * kPointerSize));
   2329 
   2330   // Check that the receiver isn't a smi.
   2331   if (check != NUMBER_CHECK) {
   2332     __ JumpIfSmi(r1, &miss);
   2333   }
   2334 
   2335   // Make sure that it's okay not to patch the on stack receiver
   2336   // unless we're doing a receiver map check.
   2337   ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
   2338   switch (check) {
   2339     case RECEIVER_MAP_CHECK:
   2340       __ IncrementCounter(masm()->isolate()->counters()->call_const(),
   2341                           1, r0, r3);
   2342 
   2343       // Check that the maps haven't changed.
   2344       CheckPrototypes(Handle<JSObject>::cast(object), r1, holder, r0, r3, r4,
   2345                       name, &miss);
   2346 
   2347       // Patch the receiver on the stack with the global proxy if
   2348       // necessary.
   2349       if (object->IsGlobalObject()) {
   2350         __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
   2351         __ str(r3, MemOperand(sp, argc * kPointerSize));
   2352       }
   2353       break;
   2354 
   2355     case STRING_CHECK:
   2356       if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
   2357         // Check that the object is a two-byte string or a symbol.
   2358         __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
   2359         __ b(ge, &miss);
   2360         // Check that the maps starting from the prototype haven't changed.
   2361         GenerateDirectLoadGlobalFunctionPrototype(
   2362             masm(), Context::STRING_FUNCTION_INDEX, r0, &miss);
   2363         CheckPrototypes(
   2364             Handle<JSObject>(JSObject::cast(object->GetPrototype())),
   2365             r0, holder, r3, r1, r4, name, &miss);
   2366       } else {
   2367         // Calling non-strict non-builtins with a value as the receiver
   2368         // requires boxing.
   2369         __ jmp(&miss);
   2370       }
   2371       break;
   2372 
   2373     case NUMBER_CHECK:
   2374       if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
   2375         Label fast;
   2376         // Check that the object is a smi or a heap number.
   2377         __ JumpIfSmi(r1, &fast);
   2378         __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE);
   2379         __ b(ne, &miss);
   2380         __ bind(&fast);
   2381         // Check that the maps starting from the prototype haven't changed.
   2382         GenerateDirectLoadGlobalFunctionPrototype(
   2383             masm(), Context::NUMBER_FUNCTION_INDEX, r0, &miss);
   2384         CheckPrototypes(
   2385             Handle<JSObject>(JSObject::cast(object->GetPrototype())),
   2386             r0, holder, r3, r1, r4, name, &miss);
   2387       } else {
   2388         // Calling non-strict non-builtins with a value as the receiver
   2389         // requires boxing.
   2390         __ jmp(&miss);
   2391       }
   2392       break;
   2393 
   2394     case BOOLEAN_CHECK:
   2395       if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
   2396         Label fast;
   2397         // Check that the object is a boolean.
   2398         __ LoadRoot(ip, Heap::kTrueValueRootIndex);
   2399         __ cmp(r1, ip);
   2400         __ b(eq, &fast);
   2401         __ LoadRoot(ip, Heap::kFalseValueRootIndex);
   2402         __ cmp(r1, ip);
   2403         __ b(ne, &miss);
   2404         __ bind(&fast);
   2405         // Check that the maps starting from the prototype haven't changed.
   2406         GenerateDirectLoadGlobalFunctionPrototype(
   2407             masm(), Context::BOOLEAN_FUNCTION_INDEX, r0, &miss);
   2408         CheckPrototypes(
   2409             Handle<JSObject>(JSObject::cast(object->GetPrototype())),
   2410             r0, holder, r3, r1, r4, name, &miss);
   2411       } else {
   2412         // Calling non-strict non-builtins with a value as the receiver
   2413         // requires boxing.
   2414         __ jmp(&miss);
   2415       }
   2416       break;
   2417   }
   2418 
   2419   CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
   2420       ? CALL_AS_FUNCTION
   2421       : CALL_AS_METHOD;
   2422   __ InvokeFunction(
   2423       function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind);
   2424 
   2425   // Handle call cache miss.
   2426   __ bind(&miss);
   2427   GenerateMissBranch();
   2428 
   2429   // Return the generated code.
   2430   return GetCode(function);
   2431 }
   2432 
   2433 
   2434 Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
   2435                                                       Handle<JSObject> holder,
   2436                                                       Handle<String> name) {
   2437   // ----------- S t a t e -------------
   2438   //  -- r2    : name
   2439   //  -- lr    : return address
   2440   // -----------------------------------
   2441   Label miss;
   2442   GenerateNameCheck(name, &miss);
   2443 
   2444   // Get the number of arguments.
   2445   const int argc = arguments().immediate();
   2446   LookupResult lookup(isolate());
   2447   LookupPostInterceptor(holder, name, &lookup);
   2448 
   2449   // Get the receiver from the stack.
   2450   __ ldr(r1, MemOperand(sp, argc * kPointerSize));
   2451 
   2452   CallInterceptorCompiler compiler(this, arguments(), r2, extra_state_);
   2453   compiler.Compile(masm(), object, holder, name, &lookup, r1, r3, r4, r0,
   2454                    &miss);
   2455 
   2456   // Move returned value, the function to call, to r1.
   2457   __ mov(r1, r0);
   2458   // Restore receiver.
   2459   __ ldr(r0, MemOperand(sp, argc * kPointerSize));
   2460 
   2461   GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
   2462 
   2463   // Handle call cache miss.
   2464   __ bind(&miss);
   2465   GenerateMissBranch();
   2466 
   2467   // Return the generated code.
   2468   return GetCode(INTERCEPTOR, name);
   2469 }
   2470 
   2471 
   2472 Handle<Code> CallStubCompiler::CompileCallGlobal(
   2473     Handle<JSObject> object,
   2474     Handle<GlobalObject> holder,
   2475     Handle<JSGlobalPropertyCell> cell,
   2476     Handle<JSFunction> function,
   2477     Handle<String> name) {
   2478   // ----------- S t a t e -------------
   2479   //  -- r2    : name
   2480   //  -- lr    : return address
   2481   // -----------------------------------
   2482   if (HasCustomCallGenerator(function)) {
   2483     Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
   2484     // A null handle means bail out to the regular compiler code below.
   2485     if (!code.is_null()) return code;
   2486   }
   2487 
   2488   Label miss;
   2489   GenerateNameCheck(name, &miss);
   2490 
   2491   // Get the number of arguments.
   2492   const int argc = arguments().immediate();
   2493   GenerateGlobalReceiverCheck(object, holder, name, &miss);
   2494   GenerateLoadFunctionFromCell(cell, function, &miss);
   2495 
   2496   // Patch the receiver on the stack with the global proxy if
   2497   // necessary.
   2498   if (object->IsGlobalObject()) {
   2499     __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
   2500     __ str(r3, MemOperand(sp, argc * kPointerSize));
   2501   }
   2502 
   2503   // Set up the context (function already in r1).
   2504   __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
   2505 
   2506   // Jump to the cached code (tail call).
   2507   Counters* counters = masm()->isolate()->counters();
   2508   __ IncrementCounter(counters->call_global_inline(), 1, r3, r4);
   2509   ParameterCount expected(function->shared()->formal_parameter_count());
   2510   CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
   2511       ? CALL_AS_FUNCTION
   2512       : CALL_AS_METHOD;
   2513   // We call indirectly through the code field in the function to
   2514   // allow recompilation to take effect without changing any of the
   2515   // call sites.
   2516   __ ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
   2517   __ InvokeCode(r3, expected, arguments(), JUMP_FUNCTION,
   2518                 NullCallWrapper(), call_kind);
   2519 
   2520   // Handle call cache miss.
   2521   __ bind(&miss);
   2522   __ IncrementCounter(counters->call_global_inline_miss(), 1, r1, r3);
   2523   GenerateMissBranch();
   2524 
   2525   // Return the generated code.
   2526   return GetCode(NORMAL, name);
   2527 }
   2528 
   2529 
   2530 Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
   2531                                                   int index,
   2532                                                   Handle<Map> transition,
   2533                                                   Handle<String> name) {
   2534   // ----------- S t a t e -------------
   2535   //  -- r0    : value
   2536   //  -- r1    : receiver
   2537   //  -- r2    : name
   2538   //  -- lr    : return address
   2539   // -----------------------------------
   2540   Label miss;
   2541 
   2542   GenerateStoreField(masm(), object, index, transition, r1, r2, r3, &miss);
   2543   __ bind(&miss);
   2544   Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
   2545   __ Jump(ic, RelocInfo::CODE_TARGET);
   2546 
   2547   // Return the generated code.
   2548   return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name);
   2549 }
   2550 
   2551 
   2552 Handle<Code> StoreStubCompiler::CompileStoreCallback(
   2553     Handle<JSObject> object,
   2554     Handle<AccessorInfo> callback,
   2555     Handle<String> name) {
   2556   // ----------- S t a t e -------------
   2557   //  -- r0    : value
   2558   //  -- r1    : receiver
   2559   //  -- r2    : name
   2560   //  -- lr    : return address
   2561   // -----------------------------------
   2562   Label miss;
   2563 
   2564   // Check that the map of the object hasn't changed.
   2565   __ CheckMap(r1, r3, Handle<Map>(object->map()), &miss,
   2566               DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
   2567 
   2568   // Perform global security token check if needed.
   2569   if (object->IsJSGlobalProxy()) {
   2570     __ CheckAccessGlobalProxy(r1, r3, &miss);
   2571   }
   2572 
   2573   // Stub never generated for non-global objects that require access
   2574   // checks.
   2575   ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
   2576 
   2577   __ push(r1);  // receiver
   2578   __ mov(ip, Operand(callback));  // callback info
   2579   __ Push(ip, r2, r0);
   2580 
   2581   // Do tail-call to the runtime system.
   2582   ExternalReference store_callback_property =
   2583       ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
   2584                         masm()->isolate());
   2585   __ TailCallExternalReference(store_callback_property, 4, 1);
   2586 
   2587   // Handle store cache miss.
   2588   __ bind(&miss);
   2589   Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
   2590   __ Jump(ic, RelocInfo::CODE_TARGET);
   2591 
   2592   // Return the generated code.
   2593   return GetCode(CALLBACKS, name);
   2594 }
   2595 
   2596 
   2597 Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
   2598     Handle<JSObject> receiver,
   2599     Handle<String> name) {
   2600   // ----------- S t a t e -------------
   2601   //  -- r0    : value
   2602   //  -- r1    : receiver
   2603   //  -- r2    : name
   2604   //  -- lr    : return address
   2605   // -----------------------------------
   2606   Label miss;
   2607 
   2608   // Check that the map of the object hasn't changed.
   2609   __ CheckMap(r1, r3, Handle<Map>(receiver->map()), &miss,
   2610               DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
   2611 
   2612   // Perform global security token check if needed.
   2613   if (receiver->IsJSGlobalProxy()) {
   2614     __ CheckAccessGlobalProxy(r1, r3, &miss);
   2615   }
   2616 
   2617   // Stub is never generated for non-global objects that require access
   2618   // checks.
   2619   ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
   2620 
   2621   __ Push(r1, r2, r0);  // Receiver, name, value.
   2622 
   2623   __ mov(r0, Operand(Smi::FromInt(strict_mode_)));
   2624   __ push(r0);  // strict mode
   2625 
   2626   // Do tail-call to the runtime system.
   2627   ExternalReference store_ic_property =
   2628       ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
   2629                         masm()->isolate());
   2630   __ TailCallExternalReference(store_ic_property, 4, 1);
   2631 
   2632   // Handle store cache miss.
   2633   __ bind(&miss);
   2634   Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
   2635   __ Jump(ic, RelocInfo::CODE_TARGET);
   2636 
   2637   // Return the generated code.
   2638   return GetCode(INTERCEPTOR, name);
   2639 }
   2640 
   2641 
   2642 Handle<Code> StoreStubCompiler::CompileStoreGlobal(
   2643     Handle<GlobalObject> object,
   2644     Handle<JSGlobalPropertyCell> cell,
   2645     Handle<String> name) {
   2646   // ----------- S t a t e -------------
   2647   //  -- r0    : value
   2648   //  -- r1    : receiver
   2649   //  -- r2    : name
   2650   //  -- lr    : return address
   2651   // -----------------------------------
   2652   Label miss;
   2653 
   2654   // Check that the map of the global has not changed.
   2655   __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
   2656   __ cmp(r3, Operand(Handle<Map>(object->map())));
   2657   __ b(ne, &miss);
   2658 
   2659   // Check that the value in the cell is not the hole. If it is, this
   2660   // cell could have been deleted and reintroducing the global needs
   2661   // to update the property details in the property dictionary of the
   2662   // global object. We bail out to the runtime system to do that.
   2663   __ mov(r4, Operand(cell));
   2664   __ LoadRoot(r5, Heap::kTheHoleValueRootIndex);
   2665   __ ldr(r6, FieldMemOperand(r4, JSGlobalPropertyCell::kValueOffset));
   2666   __ cmp(r5, r6);
   2667   __ b(eq, &miss);
   2668 
   2669   // Store the value in the cell.
   2670   __ str(r0, FieldMemOperand(r4, JSGlobalPropertyCell::kValueOffset));
   2671   // Cells are always rescanned, so no write barrier here.
   2672 
   2673   Counters* counters = masm()->isolate()->counters();
   2674   __ IncrementCounter(counters->named_store_global_inline(), 1, r4, r3);
   2675   __ Ret();
   2676 
   2677   // Handle store cache miss.
   2678   __ bind(&miss);
   2679   __ IncrementCounter(counters->named_store_global_inline_miss(), 1, r4, r3);
   2680   Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
   2681   __ Jump(ic, RelocInfo::CODE_TARGET);
   2682 
   2683   // Return the generated code.
   2684   return GetCode(NORMAL, name);
   2685 }
   2686 
   2687 
   2688 Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
   2689                                                       Handle<JSObject> object,
   2690                                                       Handle<JSObject> last) {
   2691   // ----------- S t a t e -------------
   2692   //  -- r0    : receiver
   2693   //  -- lr    : return address
   2694   // -----------------------------------
   2695   Label miss;
   2696 
   2697   // Check that receiver is not a smi.
   2698   __ JumpIfSmi(r0, &miss);
   2699 
   2700   // Check the maps of the full prototype chain.
   2701   CheckPrototypes(object, r0, last, r3, r1, r4, name, &miss);
   2702 
   2703   // If the last object in the prototype chain is a global object,
   2704   // check that the global property cell is empty.
   2705   if (last->IsGlobalObject()) {
   2706     GenerateCheckPropertyCell(
   2707         masm(), Handle<GlobalObject>::cast(last), name, r1, &miss);
   2708   }
   2709 
   2710   // Return undefined if maps of the full prototype chain are still the
   2711   // same and no global property with this name contains a value.
   2712   __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
   2713   __ Ret();
   2714 
   2715   __ bind(&miss);
   2716   GenerateLoadMiss(masm(), Code::LOAD_IC);
   2717 
   2718   // Return the generated code.
   2719   return GetCode(NONEXISTENT, factory()->empty_string());
   2720 }
   2721 
   2722 
   2723 Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
   2724                                                 Handle<JSObject> holder,
   2725                                                 int index,
   2726                                                 Handle<String> name) {
   2727   // ----------- S t a t e -------------
   2728   //  -- r0    : receiver
   2729   //  -- r2    : name
   2730   //  -- lr    : return address
   2731   // -----------------------------------
   2732   Label miss;
   2733 
   2734   GenerateLoadField(object, holder, r0, r3, r1, r4, index, name, &miss);
   2735   __ bind(&miss);
   2736   GenerateLoadMiss(masm(), Code::LOAD_IC);
   2737 
   2738   // Return the generated code.
   2739   return GetCode(FIELD, name);
   2740 }
   2741 
   2742 
   2743 Handle<Code> LoadStubCompiler::CompileLoadCallback(
   2744     Handle<String> name,
   2745     Handle<JSObject> object,
   2746     Handle<JSObject> holder,
   2747     Handle<AccessorInfo> callback) {
   2748   // ----------- S t a t e -------------
   2749   //  -- r0    : receiver
   2750   //  -- r2    : name
   2751   //  -- lr    : return address
   2752   // -----------------------------------
   2753   Label miss;
   2754   GenerateLoadCallback(object, holder, r0, r2, r3, r1, r4, callback, name,
   2755                        &miss);
   2756   __ bind(&miss);
   2757   GenerateLoadMiss(masm(), Code::LOAD_IC);
   2758 
   2759   // Return the generated code.
   2760   return GetCode(CALLBACKS, name);
   2761 }
   2762 
   2763 
   2764 Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
   2765                                                    Handle<JSObject> holder,
   2766                                                    Handle<JSFunction> value,
   2767                                                    Handle<String> name) {
   2768   // ----------- S t a t e -------------
   2769   //  -- r0    : receiver
   2770   //  -- r2    : name
   2771   //  -- lr    : return address
   2772   // -----------------------------------
   2773   Label miss;
   2774 
   2775   GenerateLoadConstant(object, holder, r0, r3, r1, r4, value, name, &miss);
   2776   __ bind(&miss);
   2777   GenerateLoadMiss(masm(), Code::LOAD_IC);
   2778 
   2779   // Return the generated code.
   2780   return GetCode(CONSTANT_FUNCTION, name);
   2781 }
   2782 
   2783 
   2784 Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> object,
   2785                                                       Handle<JSObject> holder,
   2786                                                       Handle<String> name) {
   2787   // ----------- S t a t e -------------
   2788   //  -- r0    : receiver
   2789   //  -- r2    : name
   2790   //  -- lr    : return address
   2791   // -----------------------------------
   2792   Label miss;
   2793 
   2794   LookupResult lookup(isolate());
   2795   LookupPostInterceptor(holder, name, &lookup);
   2796   GenerateLoadInterceptor(object, holder, &lookup, r0, r2, r3, r1, r4, name,
   2797                           &miss);
   2798   __ bind(&miss);
   2799   GenerateLoadMiss(masm(), Code::LOAD_IC);
   2800 
   2801   // Return the generated code.
   2802   return GetCode(INTERCEPTOR, name);
   2803 }
   2804 
   2805 
   2806 Handle<Code> LoadStubCompiler::CompileLoadGlobal(
   2807     Handle<JSObject> object,
   2808     Handle<GlobalObject> holder,
   2809     Handle<JSGlobalPropertyCell> cell,
   2810     Handle<String> name,
   2811     bool is_dont_delete) {
   2812   // ----------- S t a t e -------------
   2813   //  -- r0    : receiver
   2814   //  -- r2    : name
   2815   //  -- lr    : return address
   2816   // -----------------------------------
   2817   Label miss;
   2818 
   2819   // Check that the map of the global has not changed.
   2820   __ JumpIfSmi(r0, &miss);
   2821   CheckPrototypes(object, r0, holder, r3, r4, r1, name, &miss);
   2822 
   2823   // Get the value from the cell.
   2824   __ mov(r3, Operand(cell));
   2825   __ ldr(r4, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
   2826 
   2827   // Check for deleted property if property can actually be deleted.
   2828   if (!is_dont_delete) {
   2829     __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
   2830     __ cmp(r4, ip);
   2831     __ b(eq, &miss);
   2832   }
   2833 
   2834   __ mov(r0, r4);
   2835   Counters* counters = masm()->isolate()->counters();
   2836   __ IncrementCounter(counters->named_load_global_stub(), 1, r1, r3);
   2837   __ Ret();
   2838 
   2839   __ bind(&miss);
   2840   __ IncrementCounter(counters->named_load_global_stub_miss(), 1, r1, r3);
   2841   GenerateLoadMiss(masm(), Code::LOAD_IC);
   2842 
   2843   // Return the generated code.
   2844   return GetCode(NORMAL, name);
   2845 }
   2846 
   2847 
   2848 Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
   2849                                                      Handle<JSObject> receiver,
   2850                                                      Handle<JSObject> holder,
   2851                                                      int index) {
   2852   // ----------- S t a t e -------------
   2853   //  -- lr    : return address
   2854   //  -- r0    : key
   2855   //  -- r1    : receiver
   2856   // -----------------------------------
   2857   Label miss;
   2858 
   2859   // Check the key is the cached one.
   2860   __ cmp(r0, Operand(name));
   2861   __ b(ne, &miss);
   2862 
   2863   GenerateLoadField(receiver, holder, r1, r2, r3, r4, index, name, &miss);
   2864   __ bind(&miss);
   2865   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
   2866 
   2867   return GetCode(FIELD, name);
   2868 }
   2869 
   2870 
   2871 Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback(
   2872     Handle<String> name,
   2873     Handle<JSObject> receiver,
   2874     Handle<JSObject> holder,
   2875     Handle<AccessorInfo> callback) {
   2876   // ----------- S t a t e -------------
   2877   //  -- lr    : return address
   2878   //  -- r0    : key
   2879   //  -- r1    : receiver
   2880   // -----------------------------------
   2881   Label miss;
   2882 
   2883   // Check the key is the cached one.
   2884   __ cmp(r0, Operand(name));
   2885   __ b(ne, &miss);
   2886 
   2887   GenerateLoadCallback(receiver, holder, r1, r0, r2, r3, r4, callback, name,
   2888                        &miss);
   2889   __ bind(&miss);
   2890   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
   2891 
   2892   return GetCode(CALLBACKS, name);
   2893 }
   2894 
   2895 
   2896 Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
   2897     Handle<String> name,
   2898     Handle<JSObject> receiver,
   2899     Handle<JSObject> holder,
   2900     Handle<JSFunction> value) {
   2901   // ----------- S t a t e -------------
   2902   //  -- lr    : return address
   2903   //  -- r0    : key
   2904   //  -- r1    : receiver
   2905   // -----------------------------------
   2906   Label miss;
   2907 
   2908   // Check the key is the cached one.
   2909   __ cmp(r0, Operand(name));
   2910   __ b(ne, &miss);
   2911 
   2912   GenerateLoadConstant(receiver, holder, r1, r2, r3, r4, value, name, &miss);
   2913   __ bind(&miss);
   2914   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
   2915 
   2916   // Return the generated code.
   2917   return GetCode(CONSTANT_FUNCTION, name);
   2918 }
   2919 
   2920 
   2921 Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
   2922     Handle<JSObject> receiver,
   2923     Handle<JSObject> holder,
   2924     Handle<String> name) {
   2925   // ----------- S t a t e -------------
   2926   //  -- lr    : return address
   2927   //  -- r0    : key
   2928   //  -- r1    : receiver
   2929   // -----------------------------------
   2930   Label miss;
   2931 
   2932   // Check the key is the cached one.
   2933   __ cmp(r0, Operand(name));
   2934   __ b(ne, &miss);
   2935 
   2936   LookupResult lookup(isolate());
   2937   LookupPostInterceptor(holder, name, &lookup);
   2938   GenerateLoadInterceptor(receiver, holder, &lookup, r1, r0, r2, r3, r4, name,
   2939                           &miss);
   2940   __ bind(&miss);
   2941   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
   2942 
   2943   return GetCode(INTERCEPTOR, name);
   2944 }
   2945 
   2946 
   2947 Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
   2948     Handle<String> name) {
   2949   // ----------- S t a t e -------------
   2950   //  -- lr    : return address
   2951   //  -- r0    : key
   2952   //  -- r1    : receiver
   2953   // -----------------------------------
   2954   Label miss;
   2955 
   2956   // Check the key is the cached one.
   2957   __ cmp(r0, Operand(name));
   2958   __ b(ne, &miss);
   2959 
   2960   GenerateLoadArrayLength(masm(), r1, r2, &miss);
   2961   __ bind(&miss);
   2962   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
   2963 
   2964   return GetCode(CALLBACKS, name);
   2965 }
   2966 
   2967 
   2968 Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
   2969     Handle<String> name) {
   2970   // ----------- S t a t e -------------
   2971   //  -- lr    : return address
   2972   //  -- r0    : key
   2973   //  -- r1    : receiver
   2974   // -----------------------------------
   2975   Label miss;
   2976 
   2977   Counters* counters = masm()->isolate()->counters();
   2978   __ IncrementCounter(counters->keyed_load_string_length(), 1, r2, r3);
   2979 
   2980   // Check the key is the cached one.
   2981   __ cmp(r0, Operand(name));
   2982   __ b(ne, &miss);
   2983 
   2984   GenerateLoadStringLength(masm(), r1, r2, r3, &miss, true);
   2985   __ bind(&miss);
   2986   __ DecrementCounter(counters->keyed_load_string_length(), 1, r2, r3);
   2987 
   2988   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
   2989 
   2990   return GetCode(CALLBACKS, name);
   2991 }
   2992 
   2993 
   2994 Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
   2995     Handle<String> name) {
   2996   // ----------- S t a t e -------------
   2997   //  -- lr    : return address
   2998   //  -- r0    : key
   2999   //  -- r1    : receiver
   3000   // -----------------------------------
   3001   Label miss;
   3002 
   3003   Counters* counters = masm()->isolate()->counters();
   3004   __ IncrementCounter(counters->keyed_load_function_prototype(), 1, r2, r3);
   3005 
   3006   // Check the name hasn't changed.
   3007   __ cmp(r0, Operand(name));
   3008   __ b(ne, &miss);
   3009 
   3010   GenerateLoadFunctionPrototype(masm(), r1, r2, r3, &miss);
   3011   __ bind(&miss);
   3012   __ DecrementCounter(counters->keyed_load_function_prototype(), 1, r2, r3);
   3013   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
   3014 
   3015   return GetCode(CALLBACKS, name);
   3016 }
   3017 
   3018 
   3019 Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
   3020     Handle<Map> receiver_map) {
   3021   // ----------- S t a t e -------------
   3022   //  -- lr    : return address
   3023   //  -- r0    : key
   3024   //  -- r1    : receiver
   3025   // -----------------------------------
   3026   ElementsKind elements_kind = receiver_map->elements_kind();
   3027   Handle<Code> stub = KeyedLoadElementStub(elements_kind).GetCode();
   3028 
   3029   __ DispatchMap(r1, r2, receiver_map, stub, DO_SMI_CHECK);
   3030 
   3031   Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
   3032   __ Jump(ic, RelocInfo::CODE_TARGET);
   3033 
   3034   // Return the generated code.
   3035   return GetCode(NORMAL, factory()->empty_string());
   3036 }
   3037 
   3038 
   3039 Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
   3040     MapHandleList* receiver_maps,
   3041     CodeHandleList* handler_ics) {
   3042   // ----------- S t a t e -------------
   3043   //  -- lr    : return address
   3044   //  -- r0    : key
   3045   //  -- r1    : receiver
   3046   // -----------------------------------
   3047   Label miss;
   3048   __ JumpIfSmi(r1, &miss);
   3049 
   3050   int receiver_count = receiver_maps->length();
   3051   __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
   3052   for (int current = 0; current < receiver_count; ++current) {
   3053     __ mov(ip, Operand(receiver_maps->at(current)));
   3054     __ cmp(r2, ip);
   3055     __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET, eq);
   3056   }
   3057 
   3058   __ bind(&miss);
   3059   Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
   3060   __ Jump(miss_ic, RelocInfo::CODE_TARGET, al);
   3061 
   3062   // Return the generated code.
   3063   return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
   3064 }
   3065 
   3066 
   3067 Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
   3068                                                        int index,
   3069                                                        Handle<Map> transition,
   3070                                                        Handle<String> name) {
   3071   // ----------- S t a t e -------------
   3072   //  -- r0    : value
   3073   //  -- r1    : name
   3074   //  -- r2    : receiver
   3075   //  -- lr    : return address
   3076   // -----------------------------------
   3077   Label miss;
   3078 
   3079   Counters* counters = masm()->isolate()->counters();
   3080   __ IncrementCounter(counters->keyed_store_field(), 1, r3, r4);
   3081 
   3082   // Check that the name has not changed.
   3083   __ cmp(r1, Operand(name));
   3084   __ b(ne, &miss);
   3085 
   3086   // r3 is used as scratch register. r1 and r2 keep their values if a jump to
   3087   // the miss label is generated.
   3088   GenerateStoreField(masm(), object, index, transition, r2, r1, r3, &miss);
   3089   __ bind(&miss);
   3090 
   3091   __ DecrementCounter(counters->keyed_store_field(), 1, r3, r4);
   3092   Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
   3093   __ Jump(ic, RelocInfo::CODE_TARGET);
   3094 
   3095   // Return the generated code.
   3096   return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name);
   3097 }
   3098 
   3099 
   3100 Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
   3101     Handle<Map> receiver_map) {
   3102   // ----------- S t a t e -------------
   3103   //  -- r0    : value
   3104   //  -- r1    : key
   3105   //  -- r2    : receiver
   3106   //  -- lr    : return address
   3107   //  -- r3    : scratch
   3108   // -----------------------------------
   3109   ElementsKind elements_kind = receiver_map->elements_kind();
   3110   bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
   3111   Handle<Code> stub =
   3112       KeyedStoreElementStub(is_js_array, elements_kind, grow_mode_).GetCode();
   3113 
   3114   __ DispatchMap(r2, r3, receiver_map, stub, DO_SMI_CHECK);
   3115 
   3116   Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
   3117   __ Jump(ic, RelocInfo::CODE_TARGET);
   3118 
   3119   // Return the generated code.
   3120   return GetCode(NORMAL, factory()->empty_string());
   3121 }
   3122 
   3123 
   3124 Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
   3125     MapHandleList* receiver_maps,
   3126     CodeHandleList* handler_stubs,
   3127     MapHandleList* transitioned_maps) {
   3128   // ----------- S t a t e -------------
   3129   //  -- r0    : value
   3130   //  -- r1    : key
   3131   //  -- r2    : receiver
   3132   //  -- lr    : return address
   3133   //  -- r3    : scratch
   3134   // -----------------------------------
   3135   Label miss;
   3136   __ JumpIfSmi(r2, &miss);
   3137 
   3138   int receiver_count = receiver_maps->length();
   3139   __ ldr(r3, FieldMemOperand(r2, HeapObject::kMapOffset));
   3140   for (int i = 0; i < receiver_count; ++i) {
   3141     __ mov(ip, Operand(receiver_maps->at(i)));
   3142     __ cmp(r3, ip);
   3143     if (transitioned_maps->at(i).is_null()) {
   3144       __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq);
   3145     } else {
   3146       Label next_map;
   3147       __ b(ne, &next_map);
   3148       __ mov(r3, Operand(transitioned_maps->at(i)));
   3149       __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, al);
   3150       __ bind(&next_map);
   3151     }
   3152   }
   3153 
   3154   __ bind(&miss);
   3155   Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
   3156   __ Jump(miss_ic, RelocInfo::CODE_TARGET, al);
   3157 
   3158   // Return the generated code.
   3159   return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
   3160 }
   3161 
   3162 
   3163 Handle<Code> ConstructStubCompiler::CompileConstructStub(
   3164     Handle<JSFunction> function) {
   3165   // ----------- S t a t e -------------
   3166   //  -- r0    : argc
   3167   //  -- r1    : constructor
   3168   //  -- lr    : return address
   3169   //  -- [sp]  : last argument
   3170   // -----------------------------------
   3171   Label generic_stub_call;
   3172 
   3173   // Use r7 for holding undefined which is used in several places below.
   3174   __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
   3175 
   3176 #ifdef ENABLE_DEBUGGER_SUPPORT
   3177   // Check to see whether there are any break points in the function code. If
   3178   // there are jump to the generic constructor stub which calls the actual
   3179   // code for the function thereby hitting the break points.
   3180   __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
   3181   __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kDebugInfoOffset));
   3182   __ cmp(r2, r7);
   3183   __ b(ne, &generic_stub_call);
   3184 #endif
   3185 
   3186   // Load the initial map and verify that it is in fact a map.
   3187   // r1: constructor function
   3188   // r7: undefined
   3189   __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
   3190   __ JumpIfSmi(r2, &generic_stub_call);
   3191   __ CompareObjectType(r2, r3, r4, MAP_TYPE);
   3192   __ b(ne, &generic_stub_call);
   3193 
   3194 #ifdef DEBUG
   3195   // Cannot construct functions this way.
   3196   // r0: argc
   3197   // r1: constructor function
   3198   // r2: initial map
   3199   // r7: undefined
   3200   __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE);
   3201   __ Check(ne, "Function constructed by construct stub.");
   3202 #endif
   3203 
   3204   // Now allocate the JSObject in new space.
   3205   // r0: argc
   3206   // r1: constructor function
   3207   // r2: initial map
   3208   // r7: undefined
   3209   __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
   3210   __ AllocateInNewSpace(r3, r4, r5, r6, &generic_stub_call, SIZE_IN_WORDS);
   3211 
   3212   // Allocated the JSObject, now initialize the fields. Map is set to initial
   3213   // map and properties and elements are set to empty fixed array.
   3214   // r0: argc
   3215   // r1: constructor function
   3216   // r2: initial map
   3217   // r3: object size (in words)
   3218   // r4: JSObject (not tagged)
   3219   // r7: undefined
   3220   __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
   3221   __ mov(r5, r4);
   3222   ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
   3223   __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
   3224   ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
   3225   __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
   3226   ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
   3227   __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
   3228 
   3229   // Calculate the location of the first argument. The stack contains only the
   3230   // argc arguments.
   3231   __ add(r1, sp, Operand(r0, LSL, kPointerSizeLog2));
   3232 
   3233   // Fill all the in-object properties with undefined.
   3234   // r0: argc
   3235   // r1: first argument
   3236   // r3: object size (in words)
   3237   // r4: JSObject (not tagged)
   3238   // r5: First in-object property of JSObject (not tagged)
   3239   // r7: undefined
   3240   // Fill the initialized properties with a constant value or a passed argument
   3241   // depending on the this.x = ...; assignment in the function.
   3242   Handle<SharedFunctionInfo> shared(function->shared());
   3243   for (int i = 0; i < shared->this_property_assignments_count(); i++) {
   3244     if (shared->IsThisPropertyAssignmentArgument(i)) {
   3245       Label not_passed, next;
   3246       // Check if the argument assigned to the property is actually passed.
   3247       int arg_number = shared->GetThisPropertyAssignmentArgument(i);
   3248       __ cmp(r0, Operand(arg_number));
   3249       __ b(le, &not_passed);
   3250       // Argument passed - find it on the stack.
   3251       __ ldr(r2, MemOperand(r1, (arg_number + 1) * -kPointerSize));
   3252       __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
   3253       __ b(&next);
   3254       __ bind(&not_passed);
   3255       // Set the property to undefined.
   3256       __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
   3257       __ bind(&next);
   3258     } else {
   3259       // Set the property to the constant value.
   3260       Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
   3261       __ mov(r2, Operand(constant));
   3262       __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
   3263     }
   3264   }
   3265 
   3266   // Fill the unused in-object property fields with undefined.
   3267   ASSERT(function->has_initial_map());
   3268   for (int i = shared->this_property_assignments_count();
   3269        i < function->initial_map()->inobject_properties();
   3270        i++) {
   3271       __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
   3272   }
   3273 
   3274   // r0: argc
   3275   // r4: JSObject (not tagged)
   3276   // Move argc to r1 and the JSObject to return to r0 and tag it.
   3277   __ mov(r1, r0);
   3278   __ mov(r0, r4);
   3279   __ orr(r0, r0, Operand(kHeapObjectTag));
   3280 
   3281   // r0: JSObject
   3282   // r1: argc
   3283   // Remove caller arguments and receiver from the stack and return.
   3284   __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2));
   3285   __ add(sp, sp, Operand(kPointerSize));
   3286   Counters* counters = masm()->isolate()->counters();
   3287   __ IncrementCounter(counters->constructed_objects(), 1, r1, r2);
   3288   __ IncrementCounter(counters->constructed_objects_stub(), 1, r1, r2);
   3289   __ Jump(lr);
   3290 
   3291   // Jump to the generic stub in case the specialized code cannot handle the
   3292   // construction.
   3293   __ bind(&generic_stub_call);
   3294   Handle<Code> code = masm()->isolate()->builtins()->JSConstructStubGeneric();
   3295   __ Jump(code, RelocInfo::CODE_TARGET);
   3296 
   3297   // Return the generated code.
   3298   return GetCode();
   3299 }
   3300 
   3301 
   3302 #undef __
   3303 #define __ ACCESS_MASM(masm)
   3304 
   3305 
   3306 void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
   3307     MacroAssembler* masm) {
   3308   // ---------- S t a t e --------------
   3309   //  -- lr     : return address
   3310   //  -- r0     : key
   3311   //  -- r1     : receiver
   3312   // -----------------------------------
   3313   Label slow, miss_force_generic;
   3314 
   3315   Register key = r0;
   3316   Register receiver = r1;
   3317 
   3318   __ JumpIfNotSmi(key, &miss_force_generic);
   3319   __ mov(r2, Operand(key, ASR, kSmiTagSize));
   3320   __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset));
   3321   __ LoadFromNumberDictionary(&slow, r4, key, r0, r2, r3, r5);
   3322   __ Ret();
   3323 
   3324   __ bind(&slow);
   3325   __ IncrementCounter(
   3326       masm->isolate()->counters()->keyed_load_external_array_slow(),
   3327       1, r2, r3);
   3328 
   3329   // ---------- S t a t e --------------
   3330   //  -- lr     : return address
   3331   //  -- r0     : key
   3332   //  -- r1     : receiver
   3333   // -----------------------------------
   3334   Handle<Code> slow_ic =
   3335       masm->isolate()->builtins()->KeyedLoadIC_Slow();
   3336   __ Jump(slow_ic, RelocInfo::CODE_TARGET);
   3337 
   3338   // Miss case, call the runtime.
   3339   __ bind(&miss_force_generic);
   3340 
   3341   // ---------- S t a t e --------------
   3342   //  -- lr     : return address
   3343   //  -- r0     : key
   3344   //  -- r1     : receiver
   3345   // -----------------------------------
   3346 
   3347   Handle<Code> miss_ic =
   3348       masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
   3349   __ Jump(miss_ic, RelocInfo::CODE_TARGET);
   3350 }
   3351 
   3352 
   3353 static bool IsElementTypeSigned(ElementsKind elements_kind) {
   3354   switch (elements_kind) {
   3355     case EXTERNAL_BYTE_ELEMENTS:
   3356     case EXTERNAL_SHORT_ELEMENTS:
   3357     case EXTERNAL_INT_ELEMENTS:
   3358       return true;
   3359 
   3360     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
   3361     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
   3362     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
   3363     case EXTERNAL_PIXEL_ELEMENTS:
   3364       return false;
   3365 
   3366     case EXTERNAL_FLOAT_ELEMENTS:
   3367     case EXTERNAL_DOUBLE_ELEMENTS:
   3368     case FAST_ELEMENTS:
   3369     case FAST_SMI_ONLY_ELEMENTS:
   3370     case FAST_DOUBLE_ELEMENTS:
   3371     case DICTIONARY_ELEMENTS:
   3372     case NON_STRICT_ARGUMENTS_ELEMENTS:
   3373       UNREACHABLE();
   3374       return false;
   3375   }
   3376   return false;
   3377 }
   3378 
   3379 
   3380 void KeyedLoadStubCompiler::GenerateLoadExternalArray(
   3381     MacroAssembler* masm,
   3382     ElementsKind elements_kind) {
   3383   // ---------- S t a t e --------------
   3384   //  -- lr     : return address
   3385   //  -- r0     : key
   3386   //  -- r1     : receiver
   3387   // -----------------------------------
   3388   Label miss_force_generic, slow, failed_allocation;
   3389 
   3390   Register key = r0;
   3391   Register receiver = r1;
   3392 
   3393   // This stub is meant to be tail-jumped to, the receiver must already
   3394   // have been verified by the caller to not be a smi.
   3395 
   3396   // Check that the key is a smi.
   3397   __ JumpIfNotSmi(key, &miss_force_generic);
   3398 
   3399   __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
   3400   // r3: elements array
   3401 
   3402   // Check that the index is in range.
   3403   __ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset));
   3404   __ cmp(key, ip);
   3405   // Unsigned comparison catches both negative and too-large values.
   3406   __ b(hs, &miss_force_generic);
   3407 
   3408   __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
   3409   // r3: base pointer of external storage
   3410 
   3411   // We are not untagging smi key and instead work with it
   3412   // as if it was premultiplied by 2.
   3413   STATIC_ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
   3414 
   3415   Register value = r2;
   3416   switch (elements_kind) {
   3417     case EXTERNAL_BYTE_ELEMENTS:
   3418       __ ldrsb(value, MemOperand(r3, key, LSR, 1));
   3419       break;
   3420     case EXTERNAL_PIXEL_ELEMENTS:
   3421     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
   3422       __ ldrb(value, MemOperand(r3, key, LSR, 1));
   3423       break;
   3424     case EXTERNAL_SHORT_ELEMENTS:
   3425       __ ldrsh(value, MemOperand(r3, key, LSL, 0));
   3426       break;
   3427     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
   3428       __ ldrh(value, MemOperand(r3, key, LSL, 0));
   3429       break;
   3430     case EXTERNAL_INT_ELEMENTS:
   3431     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
   3432       __ ldr(value, MemOperand(r3, key, LSL, 1));
   3433       break;
   3434     case EXTERNAL_FLOAT_ELEMENTS:
   3435       if (CpuFeatures::IsSupported(VFP3)) {
   3436         CpuFeatures::Scope scope(VFP3);
   3437         __ add(r2, r3, Operand(key, LSL, 1));
   3438         __ vldr(s0, r2, 0);
   3439       } else {
   3440         __ ldr(value, MemOperand(r3, key, LSL, 1));
   3441       }
   3442       break;
   3443     case EXTERNAL_DOUBLE_ELEMENTS:
   3444       if (CpuFeatures::IsSupported(VFP3)) {
   3445         CpuFeatures::Scope scope(VFP3);
   3446         __ add(r2, r3, Operand(key, LSL, 2));
   3447         __ vldr(d0, r2, 0);
   3448       } else {
   3449         __ add(r4, r3, Operand(key, LSL, 2));
   3450         // r4: pointer to the beginning of the double we want to load.
   3451         __ ldr(r2, MemOperand(r4, 0));
   3452         __ ldr(r3, MemOperand(r4, Register::kSizeInBytes));
   3453       }
   3454       break;
   3455     case FAST_ELEMENTS:
   3456     case FAST_SMI_ONLY_ELEMENTS:
   3457     case FAST_DOUBLE_ELEMENTS:
   3458     case DICTIONARY_ELEMENTS:
   3459     case NON_STRICT_ARGUMENTS_ELEMENTS:
   3460       UNREACHABLE();
   3461       break;
   3462   }
   3463 
   3464   // For integer array types:
   3465   // r2: value
   3466   // For float array type:
   3467   // s0: value (if VFP3 is supported)
   3468   // r2: value (if VFP3 is not supported)
   3469   // For double array type:
   3470   // d0: value (if VFP3 is supported)
   3471   // r2/r3: value (if VFP3 is not supported)
   3472 
   3473   if (elements_kind == EXTERNAL_INT_ELEMENTS) {
   3474     // For the Int and UnsignedInt array types, we need to see whether
   3475     // the value can be represented in a Smi. If not, we need to convert
   3476     // it to a HeapNumber.
   3477     Label box_int;
   3478     __ cmp(value, Operand(0xC0000000));
   3479     __ b(mi, &box_int);
   3480     // Tag integer as smi and return it.
   3481     __ mov(r0, Operand(value, LSL, kSmiTagSize));
   3482     __ Ret();
   3483 
   3484     __ bind(&box_int);
   3485     // Allocate a HeapNumber for the result and perform int-to-double
   3486     // conversion.  Don't touch r0 or r1 as they are needed if allocation
   3487     // fails.
   3488     __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
   3489     __ AllocateHeapNumber(r5, r3, r4, r6, &slow);
   3490     // Now we can use r0 for the result as key is not needed any more.
   3491     __ mov(r0, r5);
   3492 
   3493     if (CpuFeatures::IsSupported(VFP3)) {
   3494       CpuFeatures::Scope scope(VFP3);
   3495       __ vmov(s0, value);
   3496       __ vcvt_f64_s32(d0, s0);
   3497       __ sub(r3, r0, Operand(kHeapObjectTag));
   3498       __ vstr(d0, r3, HeapNumber::kValueOffset);
   3499       __ Ret();
   3500     } else {
   3501       Register dst1 = r1;
   3502       Register dst2 = r3;
   3503       FloatingPointHelper::Destination dest =
   3504           FloatingPointHelper::kCoreRegisters;
   3505       FloatingPointHelper::ConvertIntToDouble(masm,
   3506                                               value,
   3507                                               dest,
   3508                                               d0,
   3509                                               dst1,
   3510                                               dst2,
   3511                                               r9,
   3512                                               s0);
   3513       __ str(dst1, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
   3514       __ str(dst2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
   3515       __ Ret();
   3516     }
   3517   } else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
   3518     // The test is different for unsigned int values. Since we need
   3519     // the value to be in the range of a positive smi, we can't
   3520     // handle either of the top two bits being set in the value.
   3521     if (CpuFeatures::IsSupported(VFP3)) {
   3522       CpuFeatures::Scope scope(VFP3);
   3523       Label box_int, done;
   3524       __ tst(value, Operand(0xC0000000));
   3525       __ b(ne, &box_int);
   3526       // Tag integer as smi and return it.
   3527       __ mov(r0, Operand(value, LSL, kSmiTagSize));
   3528       __ Ret();
   3529 
   3530       __ bind(&box_int);
   3531       __ vmov(s0, value);
   3532       // Allocate a HeapNumber for the result and perform int-to-double
   3533       // conversion. Don't use r0 and r1 as AllocateHeapNumber clobbers all
   3534       // registers - also when jumping due to exhausted young space.
   3535       __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
   3536       __ AllocateHeapNumber(r2, r3, r4, r6, &slow);
   3537 
   3538       __ vcvt_f64_u32(d0, s0);
   3539       __ sub(r1, r2, Operand(kHeapObjectTag));
   3540       __ vstr(d0, r1, HeapNumber::kValueOffset);
   3541 
   3542       __ mov(r0, r2);
   3543       __ Ret();
   3544     } else {
   3545       // Check whether unsigned integer fits into smi.
   3546       Label box_int_0, box_int_1, done;
   3547       __ tst(value, Operand(0x80000000));
   3548       __ b(ne, &box_int_0);
   3549       __ tst(value, Operand(0x40000000));
   3550       __ b(ne, &box_int_1);
   3551       // Tag integer as smi and return it.
   3552       __ mov(r0, Operand(value, LSL, kSmiTagSize));
   3553       __ Ret();
   3554 
   3555       Register hiword = value;  // r2.
   3556       Register loword = r3;
   3557 
   3558       __ bind(&box_int_0);
   3559       // Integer does not have leading zeros.
   3560       GenerateUInt2Double(masm, hiword, loword, r4, 0);
   3561       __ b(&done);
   3562 
   3563       __ bind(&box_int_1);
   3564       // Integer has one leading zero.
   3565       GenerateUInt2Double(masm, hiword, loword, r4, 1);
   3566 
   3567 
   3568       __ bind(&done);
   3569       // Integer was converted to double in registers hiword:loword.
   3570       // Wrap it into a HeapNumber. Don't use r0 and r1 as AllocateHeapNumber
   3571       // clobbers all registers - also when jumping due to exhausted young
   3572       // space.
   3573       __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
   3574       __ AllocateHeapNumber(r4, r5, r7, r6, &slow);
   3575 
   3576       __ str(hiword, FieldMemOperand(r4, HeapNumber::kExponentOffset));
   3577       __ str(loword, FieldMemOperand(r4, HeapNumber::kMantissaOffset));
   3578 
   3579       __ mov(r0, r4);
   3580       __ Ret();
   3581     }
   3582   } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
   3583     // For the floating-point array type, we need to always allocate a
   3584     // HeapNumber.
   3585     if (CpuFeatures::IsSupported(VFP3)) {
   3586       CpuFeatures::Scope scope(VFP3);
   3587       // Allocate a HeapNumber for the result. Don't use r0 and r1 as
   3588       // AllocateHeapNumber clobbers all registers - also when jumping due to
   3589       // exhausted young space.
   3590       __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
   3591       __ AllocateHeapNumber(r2, r3, r4, r6, &slow);
   3592       __ vcvt_f64_f32(d0, s0);
   3593       __ sub(r1, r2, Operand(kHeapObjectTag));
   3594       __ vstr(d0, r1, HeapNumber::kValueOffset);
   3595 
   3596       __ mov(r0, r2);
   3597       __ Ret();
   3598     } else {
   3599       // Allocate a HeapNumber for the result. Don't use r0 and r1 as
   3600       // AllocateHeapNumber clobbers all registers - also when jumping due to
   3601       // exhausted young space.
   3602       __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
   3603       __ AllocateHeapNumber(r3, r4, r5, r6, &slow);
   3604       // VFP is not available, do manual single to double conversion.
   3605 
   3606       // r2: floating point value (binary32)
   3607       // r3: heap number for result
   3608 
   3609       // Extract mantissa to r0. OK to clobber r0 now as there are no jumps to
   3610       // the slow case from here.
   3611       __ and_(r0, value, Operand(kBinary32MantissaMask));
   3612 
   3613       // Extract exponent to r1. OK to clobber r1 now as there are no jumps to
   3614       // the slow case from here.
   3615       __ mov(r1, Operand(value, LSR, kBinary32MantissaBits));
   3616       __ and_(r1, r1, Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
   3617 
   3618       Label exponent_rebiased;
   3619       __ teq(r1, Operand(0x00));
   3620       __ b(eq, &exponent_rebiased);
   3621 
   3622       __ teq(r1, Operand(0xff));
   3623       __ mov(r1, Operand(0x7ff), LeaveCC, eq);
   3624       __ b(eq, &exponent_rebiased);
   3625 
   3626       // Rebias exponent.
   3627       __ add(r1,
   3628              r1,
   3629              Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
   3630 
   3631       __ bind(&exponent_rebiased);
   3632       __ and_(r2, value, Operand(kBinary32SignMask));
   3633       value = no_reg;
   3634       __ orr(r2, r2, Operand(r1, LSL, HeapNumber::kMantissaBitsInTopWord));
   3635 
   3636       // Shift mantissa.
   3637       static const int kMantissaShiftForHiWord =
   3638           kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
   3639 
   3640       static const int kMantissaShiftForLoWord =
   3641           kBitsPerInt - kMantissaShiftForHiWord;
   3642 
   3643       __ orr(r2, r2, Operand(r0, LSR, kMantissaShiftForHiWord));
   3644       __ mov(r0, Operand(r0, LSL, kMantissaShiftForLoWord));
   3645 
   3646       __ str(r2, FieldMemOperand(r3, HeapNumber::kExponentOffset));
   3647       __ str(r0, FieldMemOperand(r3, HeapNumber::kMantissaOffset));
   3648 
   3649       __ mov(r0, r3);
   3650       __ Ret();
   3651     }
   3652   } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
   3653     if (CpuFeatures::IsSupported(VFP3)) {
   3654       CpuFeatures::Scope scope(VFP3);
   3655       // Allocate a HeapNumber for the result. Don't use r0 and r1 as
   3656       // AllocateHeapNumber clobbers all registers - also when jumping due to
   3657       // exhausted young space.
   3658       __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
   3659       __ AllocateHeapNumber(r2, r3, r4, r6, &slow);
   3660       __ sub(r1, r2, Operand(kHeapObjectTag));
   3661       __ vstr(d0, r1, HeapNumber::kValueOffset);
   3662 
   3663       __ mov(r0, r2);
   3664       __ Ret();
   3665     } else {
   3666       // Allocate a HeapNumber for the result. Don't use r0 and r1 as
   3667       // AllocateHeapNumber clobbers all registers - also when jumping due to
   3668       // exhausted young space.
   3669       __ LoadRoot(r7, Heap::kHeapNumberMapRootIndex);
   3670       __ AllocateHeapNumber(r4, r5, r6, r7, &slow);
   3671 
   3672       __ str(r2, FieldMemOperand(r4, HeapNumber::kMantissaOffset));
   3673       __ str(r3, FieldMemOperand(r4, HeapNumber::kExponentOffset));
   3674       __ mov(r0, r4);
   3675       __ Ret();
   3676     }
   3677 
   3678   } else {
   3679     // Tag integer as smi and return it.
   3680     __ mov(r0, Operand(value, LSL, kSmiTagSize));
   3681     __ Ret();
   3682   }
   3683 
   3684   // Slow case, key and receiver still in r0 and r1.
   3685   __ bind(&slow);
   3686   __ IncrementCounter(
   3687       masm->isolate()->counters()->keyed_load_external_array_slow(),
   3688       1, r2, r3);
   3689 
   3690   // ---------- S t a t e --------------
   3691   //  -- lr     : return address
   3692   //  -- r0     : key
   3693   //  -- r1     : receiver
   3694   // -----------------------------------
   3695 
   3696   __ Push(r1, r0);
   3697 
   3698   __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
   3699 
   3700   __ bind(&miss_force_generic);
   3701   Handle<Code> stub =
   3702       masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
   3703   __ Jump(stub, RelocInfo::CODE_TARGET);
   3704 }
   3705 
   3706 
   3707 void KeyedStoreStubCompiler::GenerateStoreExternalArray(
   3708     MacroAssembler* masm,
   3709     ElementsKind elements_kind) {
   3710   // ---------- S t a t e --------------
   3711   //  -- r0     : value
   3712   //  -- r1     : key
   3713   //  -- r2     : receiver
   3714   //  -- lr     : return address
   3715   // -----------------------------------
   3716   Label slow, check_heap_number, miss_force_generic;
   3717 
   3718   // Register usage.
   3719   Register value = r0;
   3720   Register key = r1;
   3721   Register receiver = r2;
   3722   // r3 mostly holds the elements array or the destination external array.
   3723 
   3724   // This stub is meant to be tail-jumped to, the receiver must already
   3725   // have been verified by the caller to not be a smi.
   3726 
   3727   // Check that the key is a smi.
   3728   __ JumpIfNotSmi(key, &miss_force_generic);
   3729 
   3730   __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
   3731 
   3732   // Check that the index is in range
   3733   __ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset));
   3734   __ cmp(key, ip);
   3735   // Unsigned comparison catches both negative and too-large values.
   3736   __ b(hs, &miss_force_generic);
   3737 
   3738   // Handle both smis and HeapNumbers in the fast path. Go to the
   3739   // runtime for all other kinds of values.
   3740   // r3: external array.
   3741   if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
   3742     // Double to pixel conversion is only implemented in the runtime for now.
   3743     __ JumpIfNotSmi(value, &slow);
   3744   } else {
   3745     __ JumpIfNotSmi(value, &check_heap_number);
   3746   }
   3747   __ SmiUntag(r5, value);
   3748   __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
   3749 
   3750   // r3: base pointer of external storage.
   3751   // r5: value (integer).
   3752   switch (elements_kind) {
   3753     case EXTERNAL_PIXEL_ELEMENTS:
   3754       // Clamp the value to [0..255].
   3755       __ Usat(r5, 8, Operand(r5));
   3756       __ strb(r5, MemOperand(r3, key, LSR, 1));
   3757       break;
   3758     case EXTERNAL_BYTE_ELEMENTS:
   3759     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
   3760       __ strb(r5, MemOperand(r3, key, LSR, 1));
   3761       break;
   3762     case EXTERNAL_SHORT_ELEMENTS:
   3763     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
   3764       __ strh(r5, MemOperand(r3, key, LSL, 0));
   3765       break;
   3766     case EXTERNAL_INT_ELEMENTS:
   3767     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
   3768       __ str(r5, MemOperand(r3, key, LSL, 1));
   3769       break;
   3770     case EXTERNAL_FLOAT_ELEMENTS:
   3771       // Perform int-to-float conversion and store to memory.
   3772       __ SmiUntag(r4, key);
   3773       StoreIntAsFloat(masm, r3, r4, r5, r6, r7, r9);
   3774       break;
   3775     case EXTERNAL_DOUBLE_ELEMENTS:
   3776       __ add(r3, r3, Operand(key, LSL, 2));
   3777       // r3: effective address of the double element
   3778       FloatingPointHelper::Destination destination;
   3779       if (CpuFeatures::IsSupported(VFP3)) {
   3780         destination = FloatingPointHelper::kVFPRegisters;
   3781       } else {
   3782         destination = FloatingPointHelper::kCoreRegisters;
   3783       }
   3784       FloatingPointHelper::ConvertIntToDouble(
   3785           masm, r5, destination,
   3786           d0, r6, r7,  // These are: double_dst, dst1, dst2.
   3787           r4, s2);  // These are: scratch2, single_scratch.
   3788       if (destination == FloatingPointHelper::kVFPRegisters) {
   3789         CpuFeatures::Scope scope(VFP3);
   3790         __ vstr(d0, r3, 0);
   3791       } else {
   3792         __ str(r6, MemOperand(r3, 0));
   3793         __ str(r7, MemOperand(r3, Register::kSizeInBytes));
   3794       }
   3795       break;
   3796     case FAST_ELEMENTS:
   3797     case FAST_SMI_ONLY_ELEMENTS:
   3798     case FAST_DOUBLE_ELEMENTS:
   3799     case DICTIONARY_ELEMENTS:
   3800     case NON_STRICT_ARGUMENTS_ELEMENTS:
   3801       UNREACHABLE();
   3802       break;
   3803   }
   3804 
   3805   // Entry registers are intact, r0 holds the value which is the return value.
   3806   __ Ret();
   3807 
   3808   if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
   3809     // r3: external array.
   3810     __ bind(&check_heap_number);
   3811     __ CompareObjectType(value, r5, r6, HEAP_NUMBER_TYPE);
   3812     __ b(ne, &slow);
   3813 
   3814     __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
   3815 
   3816     // r3: base pointer of external storage.
   3817 
   3818     // The WebGL specification leaves the behavior of storing NaN and
   3819     // +/-Infinity into integer arrays basically undefined. For more
   3820     // reproducible behavior, convert these to zero.
   3821     if (CpuFeatures::IsSupported(VFP3)) {
   3822       CpuFeatures::Scope scope(VFP3);
   3823 
   3824       if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
   3825         // vldr requires offset to be a multiple of 4 so we can not
   3826         // include -kHeapObjectTag into it.
   3827         __ sub(r5, r0, Operand(kHeapObjectTag));
   3828         __ vldr(d0, r5, HeapNumber::kValueOffset);
   3829         __ add(r5, r3, Operand(key, LSL, 1));
   3830         __ vcvt_f32_f64(s0, d0);
   3831         __ vstr(s0, r5, 0);
   3832       } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
   3833         __ sub(r5, r0, Operand(kHeapObjectTag));
   3834         __ vldr(d0, r5, HeapNumber::kValueOffset);
   3835         __ add(r5, r3, Operand(key, LSL, 2));
   3836         __ vstr(d0, r5, 0);
   3837       } else {
   3838         // Hoisted load.  vldr requires offset to be a multiple of 4 so we can
   3839         // not include -kHeapObjectTag into it.
   3840         __ sub(r5, value, Operand(kHeapObjectTag));
   3841         __ vldr(d0, r5, HeapNumber::kValueOffset);
   3842         __ EmitECMATruncate(r5, d0, s2, r6, r7, r9);
   3843 
   3844         switch (elements_kind) {
   3845           case EXTERNAL_BYTE_ELEMENTS:
   3846           case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
   3847             __ strb(r5, MemOperand(r3, key, LSR, 1));
   3848             break;
   3849           case EXTERNAL_SHORT_ELEMENTS:
   3850           case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
   3851             __ strh(r5, MemOperand(r3, key, LSL, 0));
   3852             break;
   3853           case EXTERNAL_INT_ELEMENTS:
   3854           case EXTERNAL_UNSIGNED_INT_ELEMENTS:
   3855             __ str(r5, MemOperand(r3, key, LSL, 1));
   3856             break;
   3857           case EXTERNAL_PIXEL_ELEMENTS:
   3858           case EXTERNAL_FLOAT_ELEMENTS:
   3859           case EXTERNAL_DOUBLE_ELEMENTS:
   3860           case FAST_ELEMENTS:
   3861           case FAST_SMI_ONLY_ELEMENTS:
   3862           case FAST_DOUBLE_ELEMENTS:
   3863           case DICTIONARY_ELEMENTS:
   3864           case NON_STRICT_ARGUMENTS_ELEMENTS:
   3865             UNREACHABLE();
   3866             break;
   3867         }
   3868       }
   3869 
   3870       // Entry registers are intact, r0 holds the value which is the return
   3871       // value.
   3872       __ Ret();
   3873     } else {
   3874       // VFP3 is not available do manual conversions.
   3875       __ ldr(r5, FieldMemOperand(value, HeapNumber::kExponentOffset));
   3876       __ ldr(r6, FieldMemOperand(value, HeapNumber::kMantissaOffset));
   3877 
   3878       if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
   3879         Label done, nan_or_infinity_or_zero;
   3880         static const int kMantissaInHiWordShift =
   3881             kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
   3882 
   3883         static const int kMantissaInLoWordShift =
   3884             kBitsPerInt - kMantissaInHiWordShift;
   3885 
   3886         // Test for all special exponent values: zeros, subnormal numbers, NaNs
   3887         // and infinities. All these should be converted to 0.
   3888         __ mov(r7, Operand(HeapNumber::kExponentMask));
   3889         __ and_(r9, r5, Operand(r7), SetCC);
   3890         __ b(eq, &nan_or_infinity_or_zero);
   3891 
   3892         __ teq(r9, Operand(r7));
   3893         __ mov(r9, Operand(kBinary32ExponentMask), LeaveCC, eq);
   3894         __ b(eq, &nan_or_infinity_or_zero);
   3895 
   3896         // Rebias exponent.
   3897         __ mov(r9, Operand(r9, LSR, HeapNumber::kExponentShift));
   3898         __ add(r9,
   3899                r9,
   3900                Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
   3901 
   3902         __ cmp(r9, Operand(kBinary32MaxExponent));
   3903         __ and_(r5, r5, Operand(HeapNumber::kSignMask), LeaveCC, gt);
   3904         __ orr(r5, r5, Operand(kBinary32ExponentMask), LeaveCC, gt);
   3905         __ b(gt, &done);
   3906 
   3907         __ cmp(r9, Operand(kBinary32MinExponent));
   3908         __ and_(r5, r5, Operand(HeapNumber::kSignMask), LeaveCC, lt);
   3909         __ b(lt, &done);
   3910 
   3911         __ and_(r7, r5, Operand(HeapNumber::kSignMask));
   3912         __ and_(r5, r5, Operand(HeapNumber::kMantissaMask));
   3913         __ orr(r7, r7, Operand(r5, LSL, kMantissaInHiWordShift));
   3914         __ orr(r7, r7, Operand(r6, LSR, kMantissaInLoWordShift));
   3915         __ orr(r5, r7, Operand(r9, LSL, kBinary32ExponentShift));
   3916 
   3917         __ bind(&done);
   3918         __ str(r5, MemOperand(r3, key, LSL, 1));
   3919         // Entry registers are intact, r0 holds the value which is the return
   3920         // value.
   3921         __ Ret();
   3922 
   3923         __ bind(&nan_or_infinity_or_zero);
   3924         __ and_(r7, r5, Operand(HeapNumber::kSignMask));
   3925         __ and_(r5, r5, Operand(HeapNumber::kMantissaMask));
   3926         __ orr(r9, r9, r7);
   3927         __ orr(r9, r9, Operand(r5, LSL, kMantissaInHiWordShift));
   3928         __ orr(r5, r9, Operand(r6, LSR, kMantissaInLoWordShift));
   3929         __ b(&done);
   3930       } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
   3931         __ add(r7, r3, Operand(key, LSL, 2));
   3932         // r7: effective address of destination element.
   3933         __ str(r6, MemOperand(r7, 0));
   3934         __ str(r5, MemOperand(r7, Register::kSizeInBytes));
   3935         __ Ret();
   3936       } else {
   3937         bool is_signed_type = IsElementTypeSigned(elements_kind);
   3938         int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
   3939         int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
   3940 
   3941         Label done, sign;
   3942 
   3943         // Test for all special exponent values: zeros, subnormal numbers, NaNs
   3944         // and infinities. All these should be converted to 0.
   3945         __ mov(r7, Operand(HeapNumber::kExponentMask));
   3946         __ and_(r9, r5, Operand(r7), SetCC);
   3947         __ mov(r5, Operand(0, RelocInfo::NONE), LeaveCC, eq);
   3948         __ b(eq, &done);
   3949 
   3950         __ teq(r9, Operand(r7));
   3951         __ mov(r5, Operand(0, RelocInfo::NONE), LeaveCC, eq);
   3952         __ b(eq, &done);
   3953 
   3954         // Unbias exponent.
   3955         __ mov(r9, Operand(r9, LSR, HeapNumber::kExponentShift));
   3956         __ sub(r9, r9, Operand(HeapNumber::kExponentBias), SetCC);
   3957         // If exponent is negative then result is 0.
   3958         __ mov(r5, Operand(0, RelocInfo::NONE), LeaveCC, mi);
   3959         __ b(mi, &done);
   3960 
   3961         // If exponent is too big then result is minimal value.
   3962         __ cmp(r9, Operand(meaningfull_bits - 1));
   3963         __ mov(r5, Operand(min_value), LeaveCC, ge);
   3964         __ b(ge, &done);
   3965 
   3966         __ and_(r7, r5, Operand(HeapNumber::kSignMask), SetCC);
   3967         __ and_(r5, r5, Operand(HeapNumber::kMantissaMask));
   3968         __ orr(r5, r5, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
   3969 
   3970         __ rsb(r9, r9, Operand(HeapNumber::kMantissaBitsInTopWord), SetCC);
   3971         __ mov(r5, Operand(r5, LSR, r9), LeaveCC, pl);
   3972         __ b(pl, &sign);
   3973 
   3974         __ rsb(r9, r9, Operand(0, RelocInfo::NONE));
   3975         __ mov(r5, Operand(r5, LSL, r9));
   3976         __ rsb(r9, r9, Operand(meaningfull_bits));
   3977         __ orr(r5, r5, Operand(r6, LSR, r9));
   3978 
   3979         __ bind(&sign);
   3980         __ teq(r7, Operand(0, RelocInfo::NONE));
   3981         __ rsb(r5, r5, Operand(0, RelocInfo::NONE), LeaveCC, ne);
   3982 
   3983         __ bind(&done);
   3984         switch (elements_kind) {
   3985           case EXTERNAL_BYTE_ELEMENTS:
   3986           case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
   3987             __ strb(r5, MemOperand(r3, key, LSR, 1));
   3988             break;
   3989           case EXTERNAL_SHORT_ELEMENTS:
   3990           case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
   3991             __ strh(r5, MemOperand(r3, key, LSL, 0));
   3992             break;
   3993           case EXTERNAL_INT_ELEMENTS:
   3994           case EXTERNAL_UNSIGNED_INT_ELEMENTS:
   3995             __ str(r5, MemOperand(r3, key, LSL, 1));
   3996             break;
   3997           case EXTERNAL_PIXEL_ELEMENTS:
   3998           case EXTERNAL_FLOAT_ELEMENTS:
   3999           case EXTERNAL_DOUBLE_ELEMENTS:
   4000           case FAST_ELEMENTS:
   4001           case FAST_SMI_ONLY_ELEMENTS:
   4002           case FAST_DOUBLE_ELEMENTS:
   4003           case DICTIONARY_ELEMENTS:
   4004           case NON_STRICT_ARGUMENTS_ELEMENTS:
   4005             UNREACHABLE();
   4006             break;
   4007         }
   4008       }
   4009     }
   4010   }
   4011 
   4012   // Slow case, key and receiver still in r0 and r1.
   4013   __ bind(&slow);
   4014   __ IncrementCounter(
   4015       masm->isolate()->counters()->keyed_load_external_array_slow(),
   4016       1, r2, r3);
   4017 
   4018   // ---------- S t a t e --------------
   4019   //  -- lr     : return address
   4020   //  -- r0     : key
   4021   //  -- r1     : receiver
   4022   // -----------------------------------
   4023   Handle<Code> slow_ic =
   4024       masm->isolate()->builtins()->KeyedStoreIC_Slow();
   4025   __ Jump(slow_ic, RelocInfo::CODE_TARGET);
   4026 
   4027   // Miss case, call the runtime.
   4028   __ bind(&miss_force_generic);
   4029 
   4030   // ---------- S t a t e --------------
   4031   //  -- lr     : return address
   4032   //  -- r0     : key
   4033   //  -- r1     : receiver
   4034   // -----------------------------------
   4035 
   4036   Handle<Code> miss_ic =
   4037       masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
   4038   __ Jump(miss_ic, RelocInfo::CODE_TARGET);
   4039 }
   4040 
   4041 
   4042 void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
   4043   // ----------- S t a t e -------------
   4044   //  -- lr    : return address
   4045   //  -- r0    : key
   4046   //  -- r1    : receiver
   4047   // -----------------------------------
   4048   Label miss_force_generic;
   4049 
   4050   // This stub is meant to be tail-jumped to, the receiver must already
   4051   // have been verified by the caller to not be a smi.
   4052 
   4053   // Check that the key is a smi.
   4054   __ JumpIfNotSmi(r0, &miss_force_generic);
   4055 
   4056   // Get the elements array.
   4057   __ ldr(r2, FieldMemOperand(r1, JSObject::kElementsOffset));
   4058   __ AssertFastElements(r2);
   4059 
   4060   // Check that the key is within bounds.
   4061   __ ldr(r3, FieldMemOperand(r2, FixedArray::kLengthOffset));
   4062   __ cmp(r0, Operand(r3));
   4063   __ b(hs, &miss_force_generic);
   4064 
   4065   // Load the result and make sure it's not the hole.
   4066   __ add(r3, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
   4067   STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
   4068   __ ldr(r4,
   4069          MemOperand(r3, r0, LSL, kPointerSizeLog2 - kSmiTagSize));
   4070   __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
   4071   __ cmp(r4, ip);
   4072   __ b(eq, &miss_force_generic);
   4073   __ mov(r0, r4);
   4074   __ Ret();
   4075 
   4076   __ bind(&miss_force_generic);
   4077   Handle<Code> stub =
   4078       masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
   4079   __ Jump(stub, RelocInfo::CODE_TARGET);
   4080 }
   4081 
   4082 
   4083 void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
   4084     MacroAssembler* masm) {
   4085   // ----------- S t a t e -------------
   4086   //  -- lr    : return address
   4087   //  -- r0    : key
   4088   //  -- r1    : receiver
   4089   // -----------------------------------
   4090   Label miss_force_generic, slow_allocate_heapnumber;
   4091 
   4092   Register key_reg = r0;
   4093   Register receiver_reg = r1;
   4094   Register elements_reg = r2;
   4095   Register heap_number_reg = r2;
   4096   Register indexed_double_offset = r3;
   4097   Register scratch = r4;
   4098   Register scratch2 = r5;
   4099   Register scratch3 = r6;
   4100   Register heap_number_map = r7;
   4101 
   4102   // This stub is meant to be tail-jumped to, the receiver must already
   4103   // have been verified by the caller to not be a smi.
   4104 
   4105   // Check that the key is a smi.
   4106   __ JumpIfNotSmi(key_reg, &miss_force_generic);
   4107 
   4108   // Get the elements array.
   4109   __ ldr(elements_reg,
   4110          FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
   4111 
   4112   // Check that the key is within bounds.
   4113   __ ldr(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
   4114   __ cmp(key_reg, Operand(scratch));
   4115   __ b(hs, &miss_force_generic);
   4116 
   4117   // Load the upper word of the double in the fixed array and test for NaN.
   4118   __ add(indexed_double_offset, elements_reg,
   4119          Operand(key_reg, LSL, kDoubleSizeLog2 - kSmiTagSize));
   4120   uint32_t upper_32_offset = FixedArray::kHeaderSize + sizeof(kHoleNanLower32);
   4121   __ ldr(scratch, FieldMemOperand(indexed_double_offset, upper_32_offset));
   4122   __ cmp(scratch, Operand(kHoleNanUpper32));
   4123   __ b(&miss_force_generic, eq);
   4124 
   4125   // Non-NaN. Allocate a new heap number and copy the double value into it.
   4126   __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
   4127   __ AllocateHeapNumber(heap_number_reg, scratch2, scratch3,
   4128                         heap_number_map, &slow_allocate_heapnumber);
   4129 
   4130   // Don't need to reload the upper 32 bits of the double, it's already in
   4131   // scratch.
   4132   __ str(scratch, FieldMemOperand(heap_number_reg,
   4133                                   HeapNumber::kExponentOffset));
   4134   __ ldr(scratch, FieldMemOperand(indexed_double_offset,
   4135                                   FixedArray::kHeaderSize));
   4136   __ str(scratch, FieldMemOperand(heap_number_reg,
   4137                                   HeapNumber::kMantissaOffset));
   4138 
   4139   __ mov(r0, heap_number_reg);
   4140   __ Ret();
   4141 
   4142   __ bind(&slow_allocate_heapnumber);
   4143   Handle<Code> slow_ic =
   4144       masm->isolate()->builtins()->KeyedLoadIC_Slow();
   4145   __ Jump(slow_ic, RelocInfo::CODE_TARGET);
   4146 
   4147   __ bind(&miss_force_generic);
   4148   Handle<Code> miss_ic =
   4149       masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
   4150   __ Jump(miss_ic, RelocInfo::CODE_TARGET);
   4151 }
   4152 
   4153 
   4154 void KeyedStoreStubCompiler::GenerateStoreFastElement(
   4155     MacroAssembler* masm,
   4156     bool is_js_array,
   4157     ElementsKind elements_kind,
   4158     KeyedAccessGrowMode grow_mode) {
   4159   // ----------- S t a t e -------------
   4160   //  -- r0    : value
   4161   //  -- r1    : key
   4162   //  -- r2    : receiver
   4163   //  -- lr    : return address
   4164   //  -- r3    : scratch
   4165   //  -- r4    : scratch (elements)
   4166   // -----------------------------------
   4167   Label miss_force_generic, transition_elements_kind, grow, slow;
   4168   Label finish_store, check_capacity;
   4169 
   4170   Register value_reg = r0;
   4171   Register key_reg = r1;
   4172   Register receiver_reg = r2;
   4173   Register scratch = r4;
   4174   Register elements_reg = r3;
   4175   Register length_reg = r5;
   4176   Register scratch2 = r6;
   4177 
   4178   // This stub is meant to be tail-jumped to, the receiver must already
   4179   // have been verified by the caller to not be a smi.
   4180 
   4181   // Check that the key is a smi.
   4182   __ JumpIfNotSmi(key_reg, &miss_force_generic);
   4183 
   4184   if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
   4185     __ JumpIfNotSmi(value_reg, &transition_elements_kind);
   4186   }
   4187 
   4188   // Check that the key is within bounds.
   4189   __ ldr(elements_reg,
   4190          FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
   4191   if (is_js_array) {
   4192     __ ldr(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
   4193   } else {
   4194     __ ldr(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
   4195   }
   4196   // Compare smis.
   4197   __ cmp(key_reg, scratch);
   4198   if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
   4199     __ b(hs, &grow);
   4200   } else {
   4201     __ b(hs, &miss_force_generic);
   4202   }
   4203 
   4204   // Make sure elements is a fast element array, not 'cow'.
   4205   __ CheckMap(elements_reg,
   4206               scratch,
   4207               Heap::kFixedArrayMapRootIndex,
   4208               &miss_force_generic,
   4209               DONT_DO_SMI_CHECK);
   4210 
   4211   __ bind(&finish_store);
   4212   if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
   4213     __ add(scratch,
   4214            elements_reg,
   4215            Operand(FixedArray::kHeaderSize - kHeapObjectTag));
   4216     STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
   4217     __ add(scratch,
   4218            scratch,
   4219            Operand(key_reg, LSL, kPointerSizeLog2 - kSmiTagSize));
   4220     __ str(value_reg, MemOperand(scratch));
   4221   } else {
   4222     ASSERT(elements_kind == FAST_ELEMENTS);
   4223     __ add(scratch,
   4224            elements_reg,
   4225            Operand(FixedArray::kHeaderSize - kHeapObjectTag));
   4226     STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
   4227     __ add(scratch,
   4228            scratch,
   4229            Operand(key_reg, LSL, kPointerSizeLog2 - kSmiTagSize));
   4230     __ str(value_reg, MemOperand(scratch));
   4231     __ mov(receiver_reg, value_reg);
   4232     __ RecordWrite(elements_reg,  // Object.
   4233                    scratch,       // Address.
   4234                    receiver_reg,  // Value.
   4235                    kLRHasNotBeenSaved,
   4236                    kDontSaveFPRegs);
   4237   }
   4238   // value_reg (r0) is preserved.
   4239   // Done.
   4240   __ Ret();
   4241 
   4242   __ bind(&miss_force_generic);
   4243   Handle<Code> ic =
   4244       masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
   4245   __ Jump(ic, RelocInfo::CODE_TARGET);
   4246 
   4247   __ bind(&transition_elements_kind);
   4248   Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
   4249   __ Jump(ic_miss, RelocInfo::CODE_TARGET);
   4250 
   4251   if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
   4252     // Grow the array by a single element if possible.
   4253     __ bind(&grow);
   4254 
   4255     // Make sure the array is only growing by a single element, anything else
   4256     // must be handled by the runtime. Flags already set by previous compare.
   4257     __ b(ne, &miss_force_generic);
   4258 
   4259     // Check for the empty array, and preallocate a small backing store if
   4260     // possible.
   4261     __ ldr(length_reg,
   4262            FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
   4263     __ ldr(elements_reg,
   4264            FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
   4265     __ CompareRoot(elements_reg, Heap::kEmptyFixedArrayRootIndex);
   4266     __ b(ne, &check_capacity);
   4267 
   4268     int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
   4269     __ AllocateInNewSpace(size, elements_reg, scratch, scratch2, &slow,
   4270                           TAG_OBJECT);
   4271 
   4272     __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
   4273     __ str(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset));
   4274     __ mov(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
   4275     __ str(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
   4276     __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
   4277     for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
   4278       __ str(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i)));
   4279     }
   4280 
   4281     // Store the element at index zero.
   4282     __ str(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0)));
   4283 
   4284     // Install the new backing store in the JSArray.
   4285     __ str(elements_reg,
   4286            FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
   4287     __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
   4288                         scratch, kLRHasNotBeenSaved, kDontSaveFPRegs,
   4289                         EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
   4290 
   4291     // Increment the length of the array.
   4292     __ mov(length_reg, Operand(Smi::FromInt(1)));
   4293     __ str(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
   4294     __ Ret();
   4295 
   4296     __ bind(&check_capacity);
   4297     // Check for cow elements, in general they are not handled by this stub
   4298     __ CheckMap(elements_reg,
   4299                 scratch,
   4300                 Heap::kFixedCOWArrayMapRootIndex,
   4301                 &miss_force_generic,
   4302                 DONT_DO_SMI_CHECK);
   4303 
   4304     __ ldr(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
   4305     __ cmp(length_reg, scratch);
   4306     __ b(hs, &slow);
   4307 
   4308     // Grow the array and finish the store.
   4309     __ add(length_reg, length_reg, Operand(Smi::FromInt(1)));
   4310     __ str(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
   4311     __ jmp(&finish_store);
   4312 
   4313     __ bind(&slow);
   4314     Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
   4315     __ Jump(ic_slow, RelocInfo::CODE_TARGET);
   4316   }
   4317 }
   4318 
   4319 
   4320 void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
   4321     MacroAssembler* masm,
   4322     bool is_js_array,
   4323     KeyedAccessGrowMode grow_mode) {
   4324   // ----------- S t a t e -------------
   4325   //  -- r0    : value
   4326   //  -- r1    : key
   4327   //  -- r2    : receiver
   4328   //  -- lr    : return address
   4329   //  -- r3    : scratch
   4330   //  -- r4    : scratch
   4331   //  -- r5    : scratch
   4332   // -----------------------------------
   4333   Label miss_force_generic, transition_elements_kind, grow, slow;
   4334   Label finish_store, check_capacity;
   4335 
   4336   Register value_reg = r0;
   4337   Register key_reg = r1;
   4338   Register receiver_reg = r2;
   4339   Register elements_reg = r3;
   4340   Register scratch1 = r4;
   4341   Register scratch2 = r5;
   4342   Register scratch3 = r6;
   4343   Register scratch4 = r7;
   4344   Register length_reg = r7;
   4345 
   4346   // This stub is meant to be tail-jumped to, the receiver must already
   4347   // have been verified by the caller to not be a smi.
   4348   __ JumpIfNotSmi(key_reg, &miss_force_generic);
   4349 
   4350   __ ldr(elements_reg,
   4351          FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
   4352 
   4353   // Check that the key is within bounds.
   4354   if (is_js_array) {
   4355     __ ldr(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
   4356   } else {
   4357     __ ldr(scratch1,
   4358            FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
   4359   }
   4360   // Compare smis, unsigned compare catches both negative and out-of-bound
   4361   // indexes.
   4362   __ cmp(key_reg, scratch1);
   4363   if (grow_mode == ALLOW_JSARRAY_GROWTH) {
   4364     __ b(hs, &grow);
   4365   } else {
   4366     __ b(hs, &miss_force_generic);
   4367   }
   4368 
   4369   __ bind(&finish_store);
   4370   __ StoreNumberToDoubleElements(value_reg,
   4371                                  key_reg,
   4372                                  receiver_reg,
   4373                                  elements_reg,
   4374                                  scratch1,
   4375                                  scratch2,
   4376                                  scratch3,
   4377                                  scratch4,
   4378                                  &transition_elements_kind);
   4379   __ Ret();
   4380 
   4381   // Handle store cache miss, replacing the ic with the generic stub.
   4382   __ bind(&miss_force_generic);
   4383   Handle<Code> ic =
   4384       masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
   4385   __ Jump(ic, RelocInfo::CODE_TARGET);
   4386 
   4387   __ bind(&transition_elements_kind);
   4388   Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
   4389   __ Jump(ic_miss, RelocInfo::CODE_TARGET);
   4390 
   4391   if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
   4392     // Grow the array by a single element if possible.
   4393     __ bind(&grow);
   4394 
   4395     // Make sure the array is only growing by a single element, anything else
   4396     // must be handled by the runtime. Flags already set by previous compare.
   4397     __ b(ne, &miss_force_generic);
   4398 
   4399     // Transition on values that can't be stored in a FixedDoubleArray.
   4400     Label value_is_smi;
   4401     __ JumpIfSmi(value_reg, &value_is_smi);
   4402     __ ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
   4403     __ CompareRoot(scratch1, Heap::kHeapNumberMapRootIndex);
   4404     __ b(ne, &transition_elements_kind);
   4405     __ bind(&value_is_smi);
   4406 
   4407     // Check for the empty array, and preallocate a small backing store if
   4408     // possible.
   4409     __ ldr(length_reg,
   4410            FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
   4411     __ ldr(elements_reg,
   4412            FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
   4413     __ CompareRoot(elements_reg, Heap::kEmptyFixedArrayRootIndex);
   4414     __ b(ne, &check_capacity);
   4415 
   4416     int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
   4417     __ AllocateInNewSpace(size, elements_reg, scratch1, scratch2, &slow,
   4418                           TAG_OBJECT);
   4419 
   4420     // Initialize the new FixedDoubleArray. Leave elements unitialized for
   4421     // efficiency, they are guaranteed to be initialized before use.
   4422     __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
   4423     __ str(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
   4424     __ mov(scratch1,
   4425            Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
   4426     __ str(scratch1,
   4427            FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
   4428 
   4429     // Install the new backing store in the JSArray.
   4430     __ str(elements_reg,
   4431            FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
   4432     __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
   4433                         scratch1, kLRHasNotBeenSaved, kDontSaveFPRegs,
   4434                         EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
   4435 
   4436     // Increment the length of the array.
   4437     __ mov(length_reg, Operand(Smi::FromInt(1)));
   4438     __ str(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
   4439     __ ldr(elements_reg,
   4440            FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
   4441     __ jmp(&finish_store);
   4442 
   4443     __ bind(&check_capacity);
   4444     // Make sure that the backing store can hold additional elements.
   4445     __ ldr(scratch1,
   4446            FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
   4447     __ cmp(length_reg, scratch1);
   4448     __ b(hs, &slow);
   4449 
   4450     // Grow the array and finish the store.
   4451     __ add(length_reg, length_reg, Operand(Smi::FromInt(1)));
   4452     __ str(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
   4453     __ jmp(&finish_store);
   4454 
   4455     __ bind(&slow);
   4456     Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
   4457     __ Jump(ic_slow, RelocInfo::CODE_TARGET);
   4458   }
   4459 }
   4460 
   4461 
   4462 #undef __
   4463 
   4464 } }  // namespace v8::internal
   4465 
   4466 #endif  // V8_TARGET_ARCH_ARM
   4467