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