Home | History | Annotate | Download | only in ia32
      1 // Copyright 2011 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include "v8.h"
     29 
     30 #if defined(V8_TARGET_ARCH_IA32)
     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 name,
     47                        Register offset,
     48                        Register extra) {
     49   ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
     50   ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
     51 
     52   Label miss;
     53 
     54   if (extra.is_valid()) {
     55     // Get the code entry from the cache.
     56     __ mov(extra, Operand::StaticArray(offset, times_2, value_offset));
     57 
     58     // Check that the key in the entry matches the name.
     59     __ cmp(name, Operand::StaticArray(offset, times_2, key_offset));
     60     __ j(not_equal, &miss, not_taken);
     61 
     62     // Check that the flags match what we're looking for.
     63     __ mov(offset, FieldOperand(extra, Code::kFlagsOffset));
     64     __ and_(offset, ~Code::kFlagsNotUsedInLookup);
     65     __ cmp(offset, flags);
     66     __ j(not_equal, &miss);
     67 
     68     // Jump to the first instruction in the code stub.
     69     __ add(Operand(extra), Immediate(Code::kHeaderSize - kHeapObjectTag));
     70     __ jmp(Operand(extra));
     71 
     72     __ bind(&miss);
     73   } else {
     74     // Save the offset on the stack.
     75     __ push(offset);
     76 
     77     // Check that the key in the entry matches the name.
     78     __ cmp(name, Operand::StaticArray(offset, times_2, key_offset));
     79     __ j(not_equal, &miss, not_taken);
     80 
     81     // Get the code entry from the cache.
     82     __ mov(offset, Operand::StaticArray(offset, times_2, value_offset));
     83 
     84     // Check that the flags match what we're looking for.
     85     __ mov(offset, FieldOperand(offset, Code::kFlagsOffset));
     86     __ and_(offset, ~Code::kFlagsNotUsedInLookup);
     87     __ cmp(offset, flags);
     88     __ j(not_equal, &miss);
     89 
     90     // Restore offset and re-load code entry from cache.
     91     __ pop(offset);
     92     __ mov(offset, Operand::StaticArray(offset, times_2, value_offset));
     93 
     94     // Jump to the first instruction in the code stub.
     95     __ add(Operand(offset), Immediate(Code::kHeaderSize - kHeapObjectTag));
     96     __ jmp(Operand(offset));
     97 
     98     // Pop at miss.
     99     __ bind(&miss);
    100     __ pop(offset);
    101   }
    102 }
    103 
    104 
    105 // Helper function used to check that the dictionary doesn't contain
    106 // the property. This function may return false negatives, so miss_label
    107 // must always call a backup property check that is complete.
    108 // This function is safe to call if the receiver has fast properties.
    109 // Name must be a symbol and receiver must be a heap object.
    110 static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
    111                                              Label* miss_label,
    112                                              Register receiver,
    113                                              String* name,
    114                                              Register r0,
    115                                              Register r1) {
    116   ASSERT(name->IsSymbol());
    117   Counters* counters = masm->isolate()->counters();
    118   __ IncrementCounter(counters->negative_lookups(), 1);
    119   __ IncrementCounter(counters->negative_lookups_miss(), 1);
    120 
    121   Label done;
    122   __ mov(r0, FieldOperand(receiver, HeapObject::kMapOffset));
    123 
    124   const int kInterceptorOrAccessCheckNeededMask =
    125       (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
    126 
    127   // Bail out if the receiver has a named interceptor or requires access checks.
    128   __ test_b(FieldOperand(r0, Map::kBitFieldOffset),
    129             kInterceptorOrAccessCheckNeededMask);
    130   __ j(not_zero, miss_label, not_taken);
    131 
    132   // Check that receiver is a JSObject.
    133   __ CmpInstanceType(r0, FIRST_JS_OBJECT_TYPE);
    134   __ j(below, miss_label, not_taken);
    135 
    136   // Load properties array.
    137   Register properties = r0;
    138   __ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
    139 
    140   // Check that the properties array is a dictionary.
    141   __ cmp(FieldOperand(properties, HeapObject::kMapOffset),
    142          Immediate(masm->isolate()->factory()->hash_table_map()));
    143   __ j(not_equal, miss_label);
    144 
    145   // Compute the capacity mask.
    146   const int kCapacityOffset =
    147       StringDictionary::kHeaderSize +
    148       StringDictionary::kCapacityIndex * kPointerSize;
    149 
    150   // Generate an unrolled loop that performs a few probes before
    151   // giving up.
    152   static const int kProbes = 4;
    153   const int kElementsStartOffset =
    154       StringDictionary::kHeaderSize +
    155       StringDictionary::kElementsStartIndex * kPointerSize;
    156 
    157   // If names of slots in range from 1 to kProbes - 1 for the hash value are
    158   // not equal to the name and kProbes-th slot is not used (its name is the
    159   // undefined value), it guarantees the hash table doesn't contain the
    160   // property. It's true even if some slots represent deleted properties
    161   // (their names are the null value).
    162   for (int i = 0; i < kProbes; i++) {
    163     // r0 points to properties hash.
    164     // Compute the masked index: (hash + i + i * i) & mask.
    165     Register index = r1;
    166     // Capacity is smi 2^n.
    167     __ mov(index, FieldOperand(properties, kCapacityOffset));
    168     __ dec(index);
    169     __ and_(Operand(index),
    170             Immediate(Smi::FromInt(name->Hash() +
    171                                    StringDictionary::GetProbeOffset(i))));
    172 
    173     // Scale the index by multiplying by the entry size.
    174     ASSERT(StringDictionary::kEntrySize == 3);
    175     __ lea(index, Operand(index, index, times_2, 0));  // index *= 3.
    176 
    177     Register entity_name = r1;
    178     // Having undefined at this place means the name is not contained.
    179     ASSERT_EQ(kSmiTagSize, 1);
    180     __ mov(entity_name, Operand(properties, index, times_half_pointer_size,
    181                                 kElementsStartOffset - kHeapObjectTag));
    182     __ cmp(entity_name, masm->isolate()->factory()->undefined_value());
    183     if (i != kProbes - 1) {
    184       __ j(equal, &done, taken);
    185 
    186       // Stop if found the property.
    187       __ cmp(entity_name, Handle<String>(name));
    188       __ j(equal, miss_label, not_taken);
    189 
    190       // Check if the entry name is not a symbol.
    191       __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
    192       __ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset),
    193                 kIsSymbolMask);
    194       __ j(zero, miss_label, not_taken);
    195     } else {
    196       // Give up probing if still not found the undefined value.
    197       __ j(not_equal, miss_label, not_taken);
    198     }
    199   }
    200 
    201   __ bind(&done);
    202   __ DecrementCounter(counters->negative_lookups_miss(), 1);
    203 }
    204 
    205 
    206 void StubCache::GenerateProbe(MacroAssembler* masm,
    207                               Code::Flags flags,
    208                               Register receiver,
    209                               Register name,
    210                               Register scratch,
    211                               Register extra,
    212                               Register extra2) {
    213   Isolate* isolate = Isolate::Current();
    214   Label miss;
    215   USE(extra2);  // The register extra2 is not used on the ia32 platform.
    216 
    217   // Make sure that code is valid. The shifting code relies on the
    218   // entry size being 8.
    219   ASSERT(sizeof(Entry) == 8);
    220 
    221   // Make sure the flags does not name a specific type.
    222   ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
    223 
    224   // Make sure that there are no register conflicts.
    225   ASSERT(!scratch.is(receiver));
    226   ASSERT(!scratch.is(name));
    227   ASSERT(!extra.is(receiver));
    228   ASSERT(!extra.is(name));
    229   ASSERT(!extra.is(scratch));
    230 
    231   // Check scratch and extra registers are valid, and extra2 is unused.
    232   ASSERT(!scratch.is(no_reg));
    233   ASSERT(extra2.is(no_reg));
    234 
    235   // Check that the receiver isn't a smi.
    236   __ test(receiver, Immediate(kSmiTagMask));
    237   __ j(zero, &miss, not_taken);
    238 
    239   // Get the map of the receiver and compute the hash.
    240   __ mov(scratch, FieldOperand(name, String::kHashFieldOffset));
    241   __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
    242   __ xor_(scratch, flags);
    243   __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
    244 
    245   // Probe the primary table.
    246   ProbeTable(isolate, masm, flags, kPrimary, name, scratch, extra);
    247 
    248   // Primary miss: Compute hash for secondary probe.
    249   __ mov(scratch, FieldOperand(name, String::kHashFieldOffset));
    250   __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
    251   __ xor_(scratch, flags);
    252   __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
    253   __ sub(scratch, Operand(name));
    254   __ add(Operand(scratch), Immediate(flags));
    255   __ and_(scratch, (kSecondaryTableSize - 1) << kHeapObjectTagSize);
    256 
    257   // Probe the secondary table.
    258   ProbeTable(isolate, masm, flags, kSecondary, name, scratch, extra);
    259 
    260   // Cache miss: Fall-through and let caller handle the miss by
    261   // entering the runtime system.
    262   __ bind(&miss);
    263 }
    264 
    265 
    266 void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
    267                                                        int index,
    268                                                        Register prototype) {
    269   __ LoadGlobalFunction(index, prototype);
    270   __ LoadGlobalFunctionInitialMap(prototype, prototype);
    271   // Load the prototype from the initial map.
    272   __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
    273 }
    274 
    275 
    276 void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
    277     MacroAssembler* masm, int index, Register prototype, Label* miss) {
    278   // Check we're still in the same context.
    279   __ cmp(Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)),
    280          masm->isolate()->global());
    281   __ j(not_equal, miss);
    282   // Get the global function with the given index.
    283   JSFunction* function =
    284       JSFunction::cast(masm->isolate()->global_context()->get(index));
    285   // Load its initial map. The global functions all have initial maps.
    286   __ Set(prototype, Immediate(Handle<Map>(function->initial_map())));
    287   // Load the prototype from the initial map.
    288   __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
    289 }
    290 
    291 
    292 void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
    293                                            Register receiver,
    294                                            Register scratch,
    295                                            Label* miss_label) {
    296   // Check that the receiver isn't a smi.
    297   __ test(receiver, Immediate(kSmiTagMask));
    298   __ j(zero, miss_label, not_taken);
    299 
    300   // Check that the object is a JS array.
    301   __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
    302   __ j(not_equal, miss_label, not_taken);
    303 
    304   // Load length directly from the JS array.
    305   __ mov(eax, FieldOperand(receiver, JSArray::kLengthOffset));
    306   __ ret(0);
    307 }
    308 
    309 
    310 // Generate code to check if an object is a string.  If the object is
    311 // a string, the map's instance type is left in the scratch register.
    312 static void GenerateStringCheck(MacroAssembler* masm,
    313                                 Register receiver,
    314                                 Register scratch,
    315                                 Label* smi,
    316                                 Label* non_string_object) {
    317   // Check that the object isn't a smi.
    318   __ test(receiver, Immediate(kSmiTagMask));
    319   __ j(zero, smi, not_taken);
    320 
    321   // Check that the object is a string.
    322   __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
    323   __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
    324   ASSERT(kNotStringTag != 0);
    325   __ test(scratch, Immediate(kNotStringTag));
    326   __ j(not_zero, non_string_object, not_taken);
    327 }
    328 
    329 
    330 void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
    331                                             Register receiver,
    332                                             Register scratch1,
    333                                             Register scratch2,
    334                                             Label* miss,
    335                                             bool support_wrappers) {
    336   Label check_wrapper;
    337 
    338   // Check if the object is a string leaving the instance type in the
    339   // scratch register.
    340   GenerateStringCheck(masm, receiver, scratch1, miss,
    341                       support_wrappers ? &check_wrapper : miss);
    342 
    343   // Load length from the string and convert to a smi.
    344   __ mov(eax, FieldOperand(receiver, String::kLengthOffset));
    345   __ ret(0);
    346 
    347   if (support_wrappers) {
    348     // Check if the object is a JSValue wrapper.
    349     __ bind(&check_wrapper);
    350     __ cmp(scratch1, JS_VALUE_TYPE);
    351     __ j(not_equal, miss, not_taken);
    352 
    353     // Check if the wrapped value is a string and load the length
    354     // directly if it is.
    355     __ mov(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
    356     GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
    357     __ mov(eax, FieldOperand(scratch2, String::kLengthOffset));
    358     __ ret(0);
    359   }
    360 }
    361 
    362 
    363 void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
    364                                                  Register receiver,
    365                                                  Register scratch1,
    366                                                  Register scratch2,
    367                                                  Label* miss_label) {
    368   __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
    369   __ mov(eax, Operand(scratch1));
    370   __ ret(0);
    371 }
    372 
    373 
    374 // Load a fast property out of a holder object (src). In-object properties
    375 // are loaded directly otherwise the property is loaded from the properties
    376 // fixed array.
    377 void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
    378                                             Register dst, Register src,
    379                                             JSObject* holder, int index) {
    380   // Adjust for the number of properties stored in the holder.
    381   index -= holder->map()->inobject_properties();
    382   if (index < 0) {
    383     // Get the property straight out of the holder.
    384     int offset = holder->map()->instance_size() + (index * kPointerSize);
    385     __ mov(dst, FieldOperand(src, offset));
    386   } else {
    387     // Calculate the offset into the properties array.
    388     int offset = index * kPointerSize + FixedArray::kHeaderSize;
    389     __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
    390     __ mov(dst, FieldOperand(dst, offset));
    391   }
    392 }
    393 
    394 
    395 static void PushInterceptorArguments(MacroAssembler* masm,
    396                                      Register receiver,
    397                                      Register holder,
    398                                      Register name,
    399                                      JSObject* holder_obj) {
    400   __ push(name);
    401   InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
    402   ASSERT(!masm->isolate()->heap()->InNewSpace(interceptor));
    403   Register scratch = name;
    404   __ mov(scratch, Immediate(Handle<Object>(interceptor)));
    405   __ push(scratch);
    406   __ push(receiver);
    407   __ push(holder);
    408   __ push(FieldOperand(scratch, InterceptorInfo::kDataOffset));
    409 }
    410 
    411 
    412 static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
    413                                                    Register receiver,
    414                                                    Register holder,
    415                                                    Register name,
    416                                                    JSObject* holder_obj) {
    417   PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
    418   __ CallExternalReference(
    419       ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
    420                         masm->isolate()),
    421       5);
    422 }
    423 
    424 
    425 // Number of pointers to be reserved on stack for fast API call.
    426 static const int kFastApiCallArguments = 3;
    427 
    428 
    429 // Reserves space for the extra arguments to API function in the
    430 // caller's frame.
    431 //
    432 // These arguments are set by CheckPrototypes and GenerateFastApiCall.
    433 static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
    434   // ----------- S t a t e -------------
    435   //  -- esp[0] : return address
    436   //  -- esp[4] : last argument in the internal frame of the caller
    437   // -----------------------------------
    438   __ pop(scratch);
    439   for (int i = 0; i < kFastApiCallArguments; i++) {
    440     __ push(Immediate(Smi::FromInt(0)));
    441   }
    442   __ push(scratch);
    443 }
    444 
    445 
    446 // Undoes the effects of ReserveSpaceForFastApiCall.
    447 static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
    448   // ----------- S t a t e -------------
    449   //  -- esp[0]  : return address.
    450   //  -- esp[4]  : last fast api call extra argument.
    451   //  -- ...
    452   //  -- esp[kFastApiCallArguments * 4] : first fast api call extra argument.
    453   //  -- esp[kFastApiCallArguments * 4 + 4] : last argument in the internal
    454   //                                          frame.
    455   // -----------------------------------
    456   __ pop(scratch);
    457   __ add(Operand(esp), Immediate(kPointerSize * kFastApiCallArguments));
    458   __ push(scratch);
    459 }
    460 
    461 
    462 // Generates call to API function.
    463 static MaybeObject* GenerateFastApiCall(MacroAssembler* masm,
    464                                         const CallOptimization& optimization,
    465                                         int argc) {
    466   // ----------- S t a t e -------------
    467   //  -- esp[0]              : return address
    468   //  -- esp[4]              : object passing the type check
    469   //                           (last fast api call extra argument,
    470   //                            set by CheckPrototypes)
    471   //  -- esp[8]              : api function
    472   //                           (first fast api call extra argument)
    473   //  -- esp[12]             : api call data
    474   //  -- esp[16]             : last argument
    475   //  -- ...
    476   //  -- esp[(argc + 3) * 4] : first argument
    477   //  -- esp[(argc + 4) * 4] : receiver
    478   // -----------------------------------
    479   // Get the function and setup the context.
    480   JSFunction* function = optimization.constant_function();
    481   __ mov(edi, Immediate(Handle<JSFunction>(function)));
    482   __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
    483 
    484   // Pass the additional arguments.
    485   __ mov(Operand(esp, 2 * kPointerSize), edi);
    486   Object* call_data = optimization.api_call_info()->data();
    487   Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info());
    488   if (masm->isolate()->heap()->InNewSpace(call_data)) {
    489     __ mov(ecx, api_call_info_handle);
    490     __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset));
    491     __ mov(Operand(esp, 3 * kPointerSize), ebx);
    492   } else {
    493     __ mov(Operand(esp, 3 * kPointerSize),
    494            Immediate(Handle<Object>(call_data)));
    495   }
    496 
    497   // Prepare arguments.
    498   __ lea(eax, Operand(esp, 3 * kPointerSize));
    499 
    500   Object* callback = optimization.api_call_info()->callback();
    501   Address api_function_address = v8::ToCData<Address>(callback);
    502   ApiFunction fun(api_function_address);
    503 
    504   const int kApiArgc = 1;  // API function gets reference to the v8::Arguments.
    505 
    506   // Allocate the v8::Arguments structure in the arguments' space since
    507   // it's not controlled by GC.
    508   const int kApiStackSpace = 4;
    509 
    510   __ PrepareCallApiFunction(kApiArgc + kApiStackSpace, ebx);
    511 
    512   __ mov(ApiParameterOperand(1), eax);  // v8::Arguments::implicit_args_.
    513   __ add(Operand(eax), Immediate(argc * kPointerSize));
    514   __ mov(ApiParameterOperand(2), eax);  // v8::Arguments::values_.
    515   __ Set(ApiParameterOperand(3), Immediate(argc));  // v8::Arguments::length_.
    516   // v8::Arguments::is_construct_call_.
    517   __ Set(ApiParameterOperand(4), Immediate(0));
    518 
    519   // v8::InvocationCallback's argument.
    520   __ lea(eax, ApiParameterOperand(1));
    521   __ mov(ApiParameterOperand(0), eax);
    522 
    523   // Emitting a stub call may try to allocate (if the code is not
    524   // already generated).  Do not allow the assembler to perform a
    525   // garbage collection but instead return the allocation failure
    526   // object.
    527   return masm->TryCallApiFunctionAndReturn(&fun,
    528                                            argc + kFastApiCallArguments + 1);
    529 }
    530 
    531 
    532 class CallInterceptorCompiler BASE_EMBEDDED {
    533  public:
    534   CallInterceptorCompiler(StubCompiler* stub_compiler,
    535                           const ParameterCount& arguments,
    536                           Register name)
    537       : stub_compiler_(stub_compiler),
    538         arguments_(arguments),
    539         name_(name) {}
    540 
    541   MaybeObject* Compile(MacroAssembler* masm,
    542                        JSObject* object,
    543                        JSObject* holder,
    544                        String* name,
    545                        LookupResult* lookup,
    546                        Register receiver,
    547                        Register scratch1,
    548                        Register scratch2,
    549                        Register scratch3,
    550                        Label* miss) {
    551     ASSERT(holder->HasNamedInterceptor());
    552     ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
    553 
    554     // Check that the receiver isn't a smi.
    555     __ test(receiver, Immediate(kSmiTagMask));
    556     __ j(zero, miss, not_taken);
    557 
    558     CallOptimization optimization(lookup);
    559 
    560     if (optimization.is_constant_call()) {
    561       return CompileCacheable(masm,
    562                               object,
    563                               receiver,
    564                               scratch1,
    565                               scratch2,
    566                               scratch3,
    567                               holder,
    568                               lookup,
    569                               name,
    570                               optimization,
    571                               miss);
    572     } else {
    573       CompileRegular(masm,
    574                      object,
    575                      receiver,
    576                      scratch1,
    577                      scratch2,
    578                      scratch3,
    579                      name,
    580                      holder,
    581                      miss);
    582       return masm->isolate()->heap()->undefined_value();  // Success.
    583     }
    584   }
    585 
    586  private:
    587   MaybeObject* CompileCacheable(MacroAssembler* masm,
    588                                 JSObject* object,
    589                                 Register receiver,
    590                                 Register scratch1,
    591                                 Register scratch2,
    592                                 Register scratch3,
    593                                 JSObject* interceptor_holder,
    594                                 LookupResult* lookup,
    595                                 String* name,
    596                                 const CallOptimization& optimization,
    597                                 Label* miss_label) {
    598     ASSERT(optimization.is_constant_call());
    599     ASSERT(!lookup->holder()->IsGlobalObject());
    600 
    601     int depth1 = kInvalidProtoDepth;
    602     int depth2 = kInvalidProtoDepth;
    603     bool can_do_fast_api_call = false;
    604     if (optimization.is_simple_api_call() &&
    605         !lookup->holder()->IsGlobalObject()) {
    606       depth1 =
    607           optimization.GetPrototypeDepthOfExpectedType(object,
    608                                                        interceptor_holder);
    609       if (depth1 == kInvalidProtoDepth) {
    610         depth2 =
    611             optimization.GetPrototypeDepthOfExpectedType(interceptor_holder,
    612                                                          lookup->holder());
    613       }
    614       can_do_fast_api_call = (depth1 != kInvalidProtoDepth) ||
    615                              (depth2 != kInvalidProtoDepth);
    616     }
    617 
    618     Counters* counters = masm->isolate()->counters();
    619     __ IncrementCounter(counters->call_const_interceptor(), 1);
    620 
    621     if (can_do_fast_api_call) {
    622       __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1);
    623       ReserveSpaceForFastApiCall(masm, scratch1);
    624     }
    625 
    626     // Check that the maps from receiver to interceptor's holder
    627     // haven't changed and thus we can invoke interceptor.
    628     Label miss_cleanup;
    629     Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
    630     Register holder =
    631         stub_compiler_->CheckPrototypes(object, receiver,
    632                                         interceptor_holder, scratch1,
    633                                         scratch2, scratch3, name, depth1, miss);
    634 
    635     // Invoke an interceptor and if it provides a value,
    636     // branch to |regular_invoke|.
    637     Label regular_invoke;
    638     LoadWithInterceptor(masm, receiver, holder, interceptor_holder,
    639                         &regular_invoke);
    640 
    641     // Interceptor returned nothing for this property.  Try to use cached
    642     // constant function.
    643 
    644     // Check that the maps from interceptor's holder to constant function's
    645     // holder haven't changed and thus we can use cached constant function.
    646     if (interceptor_holder != lookup->holder()) {
    647       stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
    648                                       lookup->holder(), scratch1,
    649                                       scratch2, scratch3, name, depth2, miss);
    650     } else {
    651       // CheckPrototypes has a side effect of fetching a 'holder'
    652       // for API (object which is instanceof for the signature).  It's
    653       // safe to omit it here, as if present, it should be fetched
    654       // by the previous CheckPrototypes.
    655       ASSERT(depth2 == kInvalidProtoDepth);
    656     }
    657 
    658     // Invoke function.
    659     if (can_do_fast_api_call) {
    660       MaybeObject* result =
    661           GenerateFastApiCall(masm, optimization, arguments_.immediate());
    662       if (result->IsFailure()) return result;
    663     } else {
    664       __ InvokeFunction(optimization.constant_function(), arguments_,
    665                         JUMP_FUNCTION);
    666     }
    667 
    668     // Deferred code for fast API call case---clean preallocated space.
    669     if (can_do_fast_api_call) {
    670       __ bind(&miss_cleanup);
    671       FreeSpaceForFastApiCall(masm, scratch1);
    672       __ jmp(miss_label);
    673     }
    674 
    675     // Invoke a regular function.
    676     __ bind(&regular_invoke);
    677     if (can_do_fast_api_call) {
    678       FreeSpaceForFastApiCall(masm, scratch1);
    679     }
    680 
    681     return masm->isolate()->heap()->undefined_value();  // Success.
    682   }
    683 
    684   void CompileRegular(MacroAssembler* masm,
    685                       JSObject* object,
    686                       Register receiver,
    687                       Register scratch1,
    688                       Register scratch2,
    689                       Register scratch3,
    690                       String* name,
    691                       JSObject* interceptor_holder,
    692                       Label* miss_label) {
    693     Register holder =
    694         stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
    695                                         scratch1, scratch2, scratch3, name,
    696                                         miss_label);
    697 
    698     __ EnterInternalFrame();
    699     // Save the name_ register across the call.
    700     __ push(name_);
    701 
    702     PushInterceptorArguments(masm,
    703                              receiver,
    704                              holder,
    705                              name_,
    706                              interceptor_holder);
    707 
    708     __ CallExternalReference(
    709         ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
    710                           masm->isolate()),
    711         5);
    712 
    713     // Restore the name_ register.
    714     __ pop(name_);
    715     __ LeaveInternalFrame();
    716   }
    717 
    718   void LoadWithInterceptor(MacroAssembler* masm,
    719                            Register receiver,
    720                            Register holder,
    721                            JSObject* holder_obj,
    722                            Label* interceptor_succeeded) {
    723     __ EnterInternalFrame();
    724     __ push(holder);  // Save the holder.
    725     __ push(name_);  // Save the name.
    726 
    727     CompileCallLoadPropertyWithInterceptor(masm,
    728                                            receiver,
    729                                            holder,
    730                                            name_,
    731                                            holder_obj);
    732 
    733     __ pop(name_);  // Restore the name.
    734     __ pop(receiver);  // Restore the holder.
    735     __ LeaveInternalFrame();
    736 
    737     __ cmp(eax, masm->isolate()->factory()->no_interceptor_result_sentinel());
    738     __ j(not_equal, interceptor_succeeded);
    739   }
    740 
    741   StubCompiler* stub_compiler_;
    742   const ParameterCount& arguments_;
    743   Register name_;
    744 };
    745 
    746 
    747 void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
    748   ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
    749   Code* code = NULL;
    750   if (kind == Code::LOAD_IC) {
    751     code = masm->isolate()->builtins()->builtin(Builtins::kLoadIC_Miss);
    752   } else {
    753     code = masm->isolate()->builtins()->builtin(Builtins::kKeyedLoadIC_Miss);
    754   }
    755 
    756   Handle<Code> ic(code);
    757   __ jmp(ic, RelocInfo::CODE_TARGET);
    758 }
    759 
    760 
    761 // Both name_reg and receiver_reg are preserved on jumps to miss_label,
    762 // but may be destroyed if store is successful.
    763 void StubCompiler::GenerateStoreField(MacroAssembler* masm,
    764                                       JSObject* object,
    765                                       int index,
    766                                       Map* transition,
    767                                       Register receiver_reg,
    768                                       Register name_reg,
    769                                       Register scratch,
    770                                       Label* miss_label) {
    771   // Check that the object isn't a smi.
    772   __ test(receiver_reg, Immediate(kSmiTagMask));
    773   __ j(zero, miss_label, not_taken);
    774 
    775   // Check that the map of the object hasn't changed.
    776   __ cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset),
    777          Immediate(Handle<Map>(object->map())));
    778   __ j(not_equal, miss_label, not_taken);
    779 
    780   // Perform global security token check if needed.
    781   if (object->IsJSGlobalProxy()) {
    782     __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
    783   }
    784 
    785   // Stub never generated for non-global objects that require access
    786   // checks.
    787   ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
    788 
    789   // Perform map transition for the receiver if necessary.
    790   if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
    791     // The properties must be extended before we can store the value.
    792     // We jump to a runtime call that extends the properties array.
    793     __ pop(scratch);  // Return address.
    794     __ push(receiver_reg);
    795     __ push(Immediate(Handle<Map>(transition)));
    796     __ push(eax);
    797     __ push(scratch);
    798     __ TailCallExternalReference(
    799         ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
    800                           masm->isolate()),
    801         3,
    802         1);
    803     return;
    804   }
    805 
    806   if (transition != NULL) {
    807     // Update the map of the object; no write barrier updating is
    808     // needed because the map is never in new space.
    809     __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset),
    810            Immediate(Handle<Map>(transition)));
    811   }
    812 
    813   // Adjust for the number of properties stored in the object. Even in the
    814   // face of a transition we can use the old map here because the size of the
    815   // object and the number of in-object properties is not going to change.
    816   index -= object->map()->inobject_properties();
    817 
    818   if (index < 0) {
    819     // Set the property straight into the object.
    820     int offset = object->map()->instance_size() + (index * kPointerSize);
    821     __ mov(FieldOperand(receiver_reg, offset), eax);
    822 
    823     // Update the write barrier for the array address.
    824     // Pass the value being stored in the now unused name_reg.
    825     __ mov(name_reg, Operand(eax));
    826     __ RecordWrite(receiver_reg, offset, name_reg, scratch);
    827   } else {
    828     // Write to the properties array.
    829     int offset = index * kPointerSize + FixedArray::kHeaderSize;
    830     // Get the properties array (optimistically).
    831     __ mov(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
    832     __ mov(FieldOperand(scratch, offset), eax);
    833 
    834     // Update the write barrier for the array address.
    835     // Pass the value being stored in the now unused name_reg.
    836     __ mov(name_reg, Operand(eax));
    837     __ RecordWrite(scratch, offset, name_reg, receiver_reg);
    838   }
    839 
    840   // Return the value (register eax).
    841   __ ret(0);
    842 }
    843 
    844 
    845 // Generate code to check that a global property cell is empty. Create
    846 // the property cell at compilation time if no cell exists for the
    847 // property.
    848 MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCell(
    849     MacroAssembler* masm,
    850     GlobalObject* global,
    851     String* name,
    852     Register scratch,
    853     Label* miss) {
    854   Object* probe;
    855   { MaybeObject* maybe_probe = global->EnsurePropertyCell(name);
    856     if (!maybe_probe->ToObject(&probe)) return maybe_probe;
    857   }
    858   JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
    859   ASSERT(cell->value()->IsTheHole());
    860   if (Serializer::enabled()) {
    861     __ mov(scratch, Immediate(Handle<Object>(cell)));
    862     __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
    863            Immediate(masm->isolate()->factory()->the_hole_value()));
    864   } else {
    865     __ cmp(Operand::Cell(Handle<JSGlobalPropertyCell>(cell)),
    866            Immediate(masm->isolate()->factory()->the_hole_value()));
    867   }
    868   __ j(not_equal, miss, not_taken);
    869   return cell;
    870 }
    871 
    872 
    873 // Calls GenerateCheckPropertyCell for each global object in the prototype chain
    874 // from object to (but not including) holder.
    875 MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCells(
    876     MacroAssembler* masm,
    877     JSObject* object,
    878     JSObject* holder,
    879     String* name,
    880     Register scratch,
    881     Label* miss) {
    882   JSObject* current = object;
    883   while (current != holder) {
    884     if (current->IsGlobalObject()) {
    885       // Returns a cell or a failure.
    886       MaybeObject* result = GenerateCheckPropertyCell(
    887           masm,
    888           GlobalObject::cast(current),
    889           name,
    890           scratch,
    891           miss);
    892       if (result->IsFailure()) return result;
    893     }
    894     ASSERT(current->IsJSObject());
    895     current = JSObject::cast(current->GetPrototype());
    896   }
    897   return NULL;
    898 }
    899 
    900 
    901 #undef __
    902 #define __ ACCESS_MASM(masm())
    903 
    904 
    905 Register StubCompiler::CheckPrototypes(JSObject* object,
    906                                        Register object_reg,
    907                                        JSObject* holder,
    908                                        Register holder_reg,
    909                                        Register scratch1,
    910                                        Register scratch2,
    911                                        String* name,
    912                                        int save_at_depth,
    913                                        Label* miss) {
    914   // Make sure there's no overlap between holder and object registers.
    915   ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
    916   ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
    917          && !scratch2.is(scratch1));
    918 
    919   // Keep track of the current object in register reg.
    920   Register reg = object_reg;
    921   JSObject* current = object;
    922   int depth = 0;
    923 
    924   if (save_at_depth == depth) {
    925     __ mov(Operand(esp, kPointerSize), reg);
    926   }
    927 
    928   // Traverse the prototype chain and check the maps in the prototype chain for
    929   // fast and global objects or do negative lookup for normal objects.
    930   while (current != holder) {
    931     depth++;
    932 
    933     // Only global objects and objects that do not require access
    934     // checks are allowed in stubs.
    935     ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
    936 
    937     ASSERT(current->GetPrototype()->IsJSObject());
    938     JSObject* prototype = JSObject::cast(current->GetPrototype());
    939     if (!current->HasFastProperties() &&
    940         !current->IsJSGlobalObject() &&
    941         !current->IsJSGlobalProxy()) {
    942       if (!name->IsSymbol()) {
    943         MaybeObject* maybe_lookup_result = heap()->LookupSymbol(name);
    944         Object* lookup_result = NULL;  // Initialization to please compiler.
    945         if (!maybe_lookup_result->ToObject(&lookup_result)) {
    946           set_failure(Failure::cast(maybe_lookup_result));
    947           return reg;
    948         }
    949         name = String::cast(lookup_result);
    950       }
    951       ASSERT(current->property_dictionary()->FindEntry(name) ==
    952              StringDictionary::kNotFound);
    953 
    954       GenerateDictionaryNegativeLookup(masm(),
    955                                        miss,
    956                                        reg,
    957                                        name,
    958                                        scratch1,
    959                                        scratch2);
    960       __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
    961       reg = holder_reg;  // from now the object is in holder_reg
    962       __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
    963     } else if (heap()->InNewSpace(prototype)) {
    964       // Get the map of the current object.
    965       __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
    966       __ cmp(Operand(scratch1), Immediate(Handle<Map>(current->map())));
    967       // Branch on the result of the map check.
    968       __ j(not_equal, miss, not_taken);
    969       // Check access rights to the global object.  This has to happen
    970       // after the map check so that we know that the object is
    971       // actually a global object.
    972       if (current->IsJSGlobalProxy()) {
    973         __ CheckAccessGlobalProxy(reg, scratch1, miss);
    974 
    975         // Restore scratch register to be the map of the object.
    976         // We load the prototype from the map in the scratch register.
    977         __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
    978       }
    979       // The prototype is in new space; we cannot store a reference
    980       // to it in the code. Load it from the map.
    981       reg = holder_reg;  // from now the object is in holder_reg
    982       __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
    983     } else {
    984       // Check the map of the current object.
    985       __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
    986              Immediate(Handle<Map>(current->map())));
    987       // Branch on the result of the map check.
    988       __ j(not_equal, miss, not_taken);
    989       // Check access rights to the global object.  This has to happen
    990       // after the map check so that we know that the object is
    991       // actually a global object.
    992       if (current->IsJSGlobalProxy()) {
    993         __ CheckAccessGlobalProxy(reg, scratch1, miss);
    994       }
    995       // The prototype is in old space; load it directly.
    996       reg = holder_reg;  // from now the object is in holder_reg
    997       __ mov(reg, Handle<JSObject>(prototype));
    998     }
    999 
   1000     if (save_at_depth == depth) {
   1001       __ mov(Operand(esp, kPointerSize), reg);
   1002     }
   1003 
   1004     // Go to the next object in the prototype chain.
   1005     current = prototype;
   1006   }
   1007   ASSERT(current == holder);
   1008 
   1009   // Log the check depth.
   1010   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
   1011 
   1012   // Check the holder map.
   1013   __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
   1014          Immediate(Handle<Map>(holder->map())));
   1015   __ j(not_equal, miss, not_taken);
   1016 
   1017   // Perform security check for access to the global object.
   1018   ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
   1019   if (holder->IsJSGlobalProxy()) {
   1020     __ CheckAccessGlobalProxy(reg, scratch1, miss);
   1021   };
   1022 
   1023   // If we've skipped any global objects, it's not enough to verify
   1024   // that their maps haven't changed.  We also need to check that the
   1025   // property cell for the property is still empty.
   1026   MaybeObject* result = GenerateCheckPropertyCells(masm(),
   1027                                                    object,
   1028                                                    holder,
   1029                                                    name,
   1030                                                    scratch1,
   1031                                                    miss);
   1032   if (result->IsFailure()) set_failure(Failure::cast(result));
   1033 
   1034   // Return the register containing the holder.
   1035   return reg;
   1036 }
   1037 
   1038 
   1039 void StubCompiler::GenerateLoadField(JSObject* object,
   1040                                      JSObject* holder,
   1041                                      Register receiver,
   1042                                      Register scratch1,
   1043                                      Register scratch2,
   1044                                      Register scratch3,
   1045                                      int index,
   1046                                      String* name,
   1047                                      Label* miss) {
   1048   // Check that the receiver isn't a smi.
   1049   __ test(receiver, Immediate(kSmiTagMask));
   1050   __ j(zero, miss, not_taken);
   1051 
   1052   // Check the prototype chain.
   1053   Register reg =
   1054       CheckPrototypes(object, receiver, holder,
   1055                       scratch1, scratch2, scratch3, name, miss);
   1056 
   1057   // Get the value from the properties.
   1058   GenerateFastPropertyLoad(masm(), eax, reg, holder, index);
   1059   __ ret(0);
   1060 }
   1061 
   1062 
   1063 MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object,
   1064                                                 JSObject* holder,
   1065                                                 Register receiver,
   1066                                                 Register name_reg,
   1067                                                 Register scratch1,
   1068                                                 Register scratch2,
   1069                                                 Register scratch3,
   1070                                                 AccessorInfo* callback,
   1071                                                 String* name,
   1072                                                 Label* miss) {
   1073   // Check that the receiver isn't a smi.
   1074   __ test(receiver, Immediate(kSmiTagMask));
   1075   __ j(zero, miss, not_taken);
   1076 
   1077   // Check that the maps haven't changed.
   1078   Register reg =
   1079       CheckPrototypes(object, receiver, holder, scratch1,
   1080                       scratch2, scratch3, name, miss);
   1081 
   1082   Handle<AccessorInfo> callback_handle(callback);
   1083 
   1084   // Insert additional parameters into the stack frame above return address.
   1085   ASSERT(!scratch3.is(reg));
   1086   __ pop(scratch3);  // Get return address to place it below.
   1087 
   1088   __ push(receiver);  // receiver
   1089   __ mov(scratch2, Operand(esp));
   1090   ASSERT(!scratch2.is(reg));
   1091   __ push(reg);  // holder
   1092   // Push data from AccessorInfo.
   1093   if (isolate()->heap()->InNewSpace(callback_handle->data())) {
   1094     __ mov(scratch1, Immediate(callback_handle));
   1095     __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset));
   1096   } else {
   1097     __ push(Immediate(Handle<Object>(callback_handle->data())));
   1098   }
   1099 
   1100   // Save a pointer to where we pushed the arguments pointer.
   1101   // This will be passed as the const AccessorInfo& to the C++ callback.
   1102   __ push(scratch2);
   1103 
   1104   __ push(name_reg);  // name
   1105   __ mov(ebx, esp);  // esp points to reference to name (handler).
   1106 
   1107   __ push(scratch3);  // Restore return address.
   1108 
   1109   // Do call through the api.
   1110   Address getter_address = v8::ToCData<Address>(callback->getter());
   1111   ApiFunction fun(getter_address);
   1112 
   1113   // 3 elements array for v8::Agruments::values_, handler for name and pointer
   1114   // to the values (it considered as smi in GC).
   1115   const int kStackSpace = 5;
   1116   const int kApiArgc = 2;
   1117 
   1118   __ PrepareCallApiFunction(kApiArgc, eax);
   1119   __ mov(ApiParameterOperand(0), ebx);  // name.
   1120   __ add(Operand(ebx), Immediate(kPointerSize));
   1121   __ mov(ApiParameterOperand(1), ebx);  // arguments pointer.
   1122 
   1123   // Emitting a stub call may try to allocate (if the code is not
   1124   // already generated).  Do not allow the assembler to perform a
   1125   // garbage collection but instead return the allocation failure
   1126   // object.
   1127   return masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace);
   1128 }
   1129 
   1130 
   1131 void StubCompiler::GenerateLoadConstant(JSObject* object,
   1132                                         JSObject* holder,
   1133                                         Register receiver,
   1134                                         Register scratch1,
   1135                                         Register scratch2,
   1136                                         Register scratch3,
   1137                                         Object* value,
   1138                                         String* name,
   1139                                         Label* miss) {
   1140   // Check that the receiver isn't a smi.
   1141   __ test(receiver, Immediate(kSmiTagMask));
   1142   __ j(zero, miss, not_taken);
   1143 
   1144   // Check that the maps haven't changed.
   1145   CheckPrototypes(object, receiver, holder,
   1146                   scratch1, scratch2, scratch3, name, miss);
   1147 
   1148   // Return the constant value.
   1149   __ mov(eax, Handle<Object>(value));
   1150   __ ret(0);
   1151 }
   1152 
   1153 
   1154 void StubCompiler::GenerateLoadInterceptor(JSObject* object,
   1155                                            JSObject* interceptor_holder,
   1156                                            LookupResult* lookup,
   1157                                            Register receiver,
   1158                                            Register name_reg,
   1159                                            Register scratch1,
   1160                                            Register scratch2,
   1161                                            Register scratch3,
   1162                                            String* name,
   1163                                            Label* miss) {
   1164   ASSERT(interceptor_holder->HasNamedInterceptor());
   1165   ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
   1166 
   1167   // Check that the receiver isn't a smi.
   1168   __ test(receiver, Immediate(kSmiTagMask));
   1169   __ j(zero, miss, not_taken);
   1170 
   1171   // So far the most popular follow ups for interceptor loads are FIELD
   1172   // and CALLBACKS, so inline only them, other cases may be added
   1173   // later.
   1174   bool compile_followup_inline = false;
   1175   if (lookup->IsProperty() && lookup->IsCacheable()) {
   1176     if (lookup->type() == FIELD) {
   1177       compile_followup_inline = true;
   1178     } else if (lookup->type() == CALLBACKS &&
   1179         lookup->GetCallbackObject()->IsAccessorInfo() &&
   1180         AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) {
   1181       compile_followup_inline = true;
   1182     }
   1183   }
   1184 
   1185   if (compile_followup_inline) {
   1186     // Compile the interceptor call, followed by inline code to load the
   1187     // property from further up the prototype chain if the call fails.
   1188     // Check that the maps haven't changed.
   1189     Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
   1190                                           scratch1, scratch2, scratch3,
   1191                                           name, miss);
   1192     ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
   1193 
   1194     // Save necessary data before invoking an interceptor.
   1195     // Requires a frame to make GC aware of pushed pointers.
   1196     __ EnterInternalFrame();
   1197 
   1198     if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
   1199       // CALLBACKS case needs a receiver to be passed into C++ callback.
   1200       __ push(receiver);
   1201     }
   1202     __ push(holder_reg);
   1203     __ push(name_reg);
   1204 
   1205     // Invoke an interceptor.  Note: map checks from receiver to
   1206     // interceptor's holder has been compiled before (see a caller
   1207     // of this method.)
   1208     CompileCallLoadPropertyWithInterceptor(masm(),
   1209                                            receiver,
   1210                                            holder_reg,
   1211                                            name_reg,
   1212                                            interceptor_holder);
   1213 
   1214     // Check if interceptor provided a value for property.  If it's
   1215     // the case, return immediately.
   1216     Label interceptor_failed;
   1217     __ cmp(eax, factory()->no_interceptor_result_sentinel());
   1218     __ j(equal, &interceptor_failed);
   1219     __ LeaveInternalFrame();
   1220     __ ret(0);
   1221 
   1222     __ bind(&interceptor_failed);
   1223     __ pop(name_reg);
   1224     __ pop(holder_reg);
   1225     if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
   1226       __ pop(receiver);
   1227     }
   1228 
   1229     __ LeaveInternalFrame();
   1230 
   1231     // Check that the maps from interceptor's holder to lookup's holder
   1232     // haven't changed.  And load lookup's holder into holder_reg.
   1233     if (interceptor_holder != lookup->holder()) {
   1234       holder_reg = CheckPrototypes(interceptor_holder,
   1235                                    holder_reg,
   1236                                    lookup->holder(),
   1237                                    scratch1,
   1238                                    scratch2,
   1239                                    scratch3,
   1240                                    name,
   1241                                    miss);
   1242     }
   1243 
   1244     if (lookup->type() == FIELD) {
   1245       // We found FIELD property in prototype chain of interceptor's holder.
   1246       // Retrieve a field from field's holder.
   1247       GenerateFastPropertyLoad(masm(), eax, holder_reg,
   1248                                lookup->holder(), lookup->GetFieldIndex());
   1249       __ ret(0);
   1250     } else {
   1251       // We found CALLBACKS property in prototype chain of interceptor's
   1252       // holder.
   1253       ASSERT(lookup->type() == CALLBACKS);
   1254       ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
   1255       AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
   1256       ASSERT(callback != NULL);
   1257       ASSERT(callback->getter() != NULL);
   1258 
   1259       // Tail call to runtime.
   1260       // Important invariant in CALLBACKS case: the code above must be
   1261       // structured to never clobber |receiver| register.
   1262       __ pop(scratch2);  // return address
   1263       __ push(receiver);
   1264       __ push(holder_reg);
   1265       __ mov(holder_reg, Immediate(Handle<AccessorInfo>(callback)));
   1266       __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset));
   1267       __ push(holder_reg);
   1268       __ push(name_reg);
   1269       __ push(scratch2);  // restore return address
   1270 
   1271       ExternalReference ref =
   1272           ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
   1273                             masm()->isolate());
   1274       __ TailCallExternalReference(ref, 5, 1);
   1275     }
   1276   } else {  // !compile_followup_inline
   1277     // Call the runtime system to load the interceptor.
   1278     // Check that the maps haven't changed.
   1279     Register holder_reg =
   1280         CheckPrototypes(object, receiver, interceptor_holder,
   1281                         scratch1, scratch2, scratch3, name, miss);
   1282     __ pop(scratch2);  // save old return address
   1283     PushInterceptorArguments(masm(), receiver, holder_reg,
   1284                              name_reg, interceptor_holder);
   1285     __ push(scratch2);  // restore old return address
   1286 
   1287     ExternalReference ref =
   1288         ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad),
   1289                           isolate());
   1290     __ TailCallExternalReference(ref, 5, 1);
   1291   }
   1292 }
   1293 
   1294 
   1295 void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
   1296   if (kind_ == Code::KEYED_CALL_IC) {
   1297     __ cmp(Operand(ecx), Immediate(Handle<String>(name)));
   1298     __ j(not_equal, miss, not_taken);
   1299   }
   1300 }
   1301 
   1302 
   1303 void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object,
   1304                                                    JSObject* holder,
   1305                                                    String* name,
   1306                                                    Label* miss) {
   1307   ASSERT(holder->IsGlobalObject());
   1308 
   1309   // Get the number of arguments.
   1310   const int argc = arguments().immediate();
   1311 
   1312   // Get the receiver from the stack.
   1313   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
   1314 
   1315   // If the object is the holder then we know that it's a global
   1316   // object which can only happen for contextual calls. In this case,
   1317   // the receiver cannot be a smi.
   1318   if (object != holder) {
   1319     __ test(edx, Immediate(kSmiTagMask));
   1320     __ j(zero, miss, not_taken);
   1321   }
   1322 
   1323   // Check that the maps haven't changed.
   1324   CheckPrototypes(object, edx, holder, ebx, eax, edi, name, miss);
   1325 }
   1326 
   1327 
   1328 void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
   1329                                                     JSFunction* function,
   1330                                                     Label* miss) {
   1331   // Get the value from the cell.
   1332   if (Serializer::enabled()) {
   1333     __ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell)));
   1334     __ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset));
   1335   } else {
   1336     __ mov(edi, Operand::Cell(Handle<JSGlobalPropertyCell>(cell)));
   1337   }
   1338 
   1339   // Check that the cell contains the same function.
   1340   if (isolate()->heap()->InNewSpace(function)) {
   1341     // We can't embed a pointer to a function in new space so we have
   1342     // to verify that the shared function info is unchanged. This has
   1343     // the nice side effect that multiple closures based on the same
   1344     // function can all use this call IC. Before we load through the
   1345     // function, we have to verify that it still is a function.
   1346     __ test(edi, Immediate(kSmiTagMask));
   1347     __ j(zero, miss, not_taken);
   1348     __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
   1349     __ j(not_equal, miss, not_taken);
   1350 
   1351     // Check the shared function info. Make sure it hasn't changed.
   1352     __ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset),
   1353            Immediate(Handle<SharedFunctionInfo>(function->shared())));
   1354     __ j(not_equal, miss, not_taken);
   1355   } else {
   1356     __ cmp(Operand(edi), Immediate(Handle<JSFunction>(function)));
   1357     __ j(not_equal, miss, not_taken);
   1358   }
   1359 }
   1360 
   1361 
   1362 MaybeObject* CallStubCompiler::GenerateMissBranch() {
   1363   MaybeObject* maybe_obj =
   1364       isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
   1365                                                        kind_);
   1366   Object* obj;
   1367   if (!maybe_obj->ToObject(&obj)) return maybe_obj;
   1368   __ jmp(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
   1369   return obj;
   1370 }
   1371 
   1372 
   1373 MUST_USE_RESULT MaybeObject* CallStubCompiler::CompileCallField(
   1374     JSObject* object,
   1375     JSObject* holder,
   1376     int index,
   1377     String* name) {
   1378   // ----------- S t a t e -------------
   1379   //  -- ecx                 : name
   1380   //  -- esp[0]              : return address
   1381   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
   1382   //  -- ...
   1383   //  -- esp[(argc + 1) * 4] : receiver
   1384   // -----------------------------------
   1385   Label miss;
   1386 
   1387   GenerateNameCheck(name, &miss);
   1388 
   1389   // Get the receiver from the stack.
   1390   const int argc = arguments().immediate();
   1391   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
   1392 
   1393   // Check that the receiver isn't a smi.
   1394   __ test(edx, Immediate(kSmiTagMask));
   1395   __ j(zero, &miss, not_taken);
   1396 
   1397   // Do the right check and compute the holder register.
   1398   Register reg = CheckPrototypes(object, edx, holder, ebx, eax, edi,
   1399                                  name, &miss);
   1400 
   1401   GenerateFastPropertyLoad(masm(), edi, reg, holder, index);
   1402 
   1403   // Check that the function really is a function.
   1404   __ test(edi, Immediate(kSmiTagMask));
   1405   __ j(zero, &miss, not_taken);
   1406   __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
   1407   __ j(not_equal, &miss, not_taken);
   1408 
   1409   // Patch the receiver on the stack with the global proxy if
   1410   // necessary.
   1411   if (object->IsGlobalObject()) {
   1412     __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
   1413     __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
   1414   }
   1415 
   1416   // Invoke the function.
   1417   __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
   1418 
   1419   // Handle call cache miss.
   1420   __ bind(&miss);
   1421   MaybeObject* maybe_result = GenerateMissBranch();
   1422   if (maybe_result->IsFailure()) return maybe_result;
   1423 
   1424   // Return the generated code.
   1425   return GetCode(FIELD, name);
   1426 }
   1427 
   1428 
   1429 MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
   1430                                                     JSObject* holder,
   1431                                                     JSGlobalPropertyCell* cell,
   1432                                                     JSFunction* function,
   1433                                                     String* name) {
   1434   // ----------- S t a t e -------------
   1435   //  -- ecx                 : name
   1436   //  -- esp[0]              : return address
   1437   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
   1438   //  -- ...
   1439   //  -- esp[(argc + 1) * 4] : receiver
   1440   // -----------------------------------
   1441 
   1442   // If object is not an array, bail out to regular call.
   1443   if (!object->IsJSArray() || cell != NULL) {
   1444     return isolate()->heap()->undefined_value();
   1445   }
   1446 
   1447   Label miss;
   1448 
   1449   GenerateNameCheck(name, &miss);
   1450 
   1451   // Get the receiver from the stack.
   1452   const int argc = arguments().immediate();
   1453   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
   1454 
   1455   // Check that the receiver isn't a smi.
   1456   __ test(edx, Immediate(kSmiTagMask));
   1457   __ j(zero, &miss);
   1458 
   1459   CheckPrototypes(JSObject::cast(object), edx,
   1460                   holder, ebx,
   1461                   eax, edi, name, &miss);
   1462 
   1463   if (argc == 0) {
   1464     // Noop, return the length.
   1465     __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
   1466     __ ret((argc + 1) * kPointerSize);
   1467   } else {
   1468     Label call_builtin;
   1469 
   1470     // Get the elements array of the object.
   1471     __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset));
   1472 
   1473     // Check that the elements are in fast mode and writable.
   1474     __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
   1475            Immediate(factory()->fixed_array_map()));
   1476     __ j(not_equal, &call_builtin);
   1477 
   1478     if (argc == 1) {  // Otherwise fall through to call builtin.
   1479       Label exit, with_write_barrier, attempt_to_grow_elements;
   1480 
   1481       // Get the array's length into eax and calculate new length.
   1482       __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
   1483       STATIC_ASSERT(kSmiTagSize == 1);
   1484       STATIC_ASSERT(kSmiTag == 0);
   1485       __ add(Operand(eax), Immediate(Smi::FromInt(argc)));
   1486 
   1487       // Get the element's length into ecx.
   1488       __ mov(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
   1489 
   1490       // Check if we could survive without allocation.
   1491       __ cmp(eax, Operand(ecx));
   1492       __ j(greater, &attempt_to_grow_elements);
   1493 
   1494       // Save new length.
   1495       __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
   1496 
   1497       // Push the element.
   1498       __ lea(edx, FieldOperand(ebx,
   1499                                eax, times_half_pointer_size,
   1500                                FixedArray::kHeaderSize - argc * kPointerSize));
   1501       __ mov(ecx, Operand(esp, argc * kPointerSize));
   1502       __ mov(Operand(edx, 0), ecx);
   1503 
   1504       // Check if value is a smi.
   1505       __ test(ecx, Immediate(kSmiTagMask));
   1506       __ j(not_zero, &with_write_barrier);
   1507 
   1508       __ bind(&exit);
   1509       __ ret((argc + 1) * kPointerSize);
   1510 
   1511       __ bind(&with_write_barrier);
   1512 
   1513       __ InNewSpace(ebx, ecx, equal, &exit);
   1514 
   1515       __ RecordWriteHelper(ebx, edx, ecx);
   1516       __ ret((argc + 1) * kPointerSize);
   1517 
   1518       __ bind(&attempt_to_grow_elements);
   1519       if (!FLAG_inline_new) {
   1520         __ jmp(&call_builtin);
   1521       }
   1522 
   1523       ExternalReference new_space_allocation_top =
   1524           ExternalReference::new_space_allocation_top_address(isolate());
   1525       ExternalReference new_space_allocation_limit =
   1526           ExternalReference::new_space_allocation_limit_address(isolate());
   1527 
   1528       const int kAllocationDelta = 4;
   1529       // Load top.
   1530       __ mov(ecx, Operand::StaticVariable(new_space_allocation_top));
   1531 
   1532       // Check if it's the end of elements.
   1533       __ lea(edx, FieldOperand(ebx,
   1534                                eax, times_half_pointer_size,
   1535                                FixedArray::kHeaderSize - argc * kPointerSize));
   1536       __ cmp(edx, Operand(ecx));
   1537       __ j(not_equal, &call_builtin);
   1538       __ add(Operand(ecx), Immediate(kAllocationDelta * kPointerSize));
   1539       __ cmp(ecx, Operand::StaticVariable(new_space_allocation_limit));
   1540       __ j(above, &call_builtin);
   1541 
   1542       // We fit and could grow elements.
   1543       __ mov(Operand::StaticVariable(new_space_allocation_top), ecx);
   1544       __ mov(ecx, Operand(esp, argc * kPointerSize));
   1545 
   1546       // Push the argument...
   1547       __ mov(Operand(edx, 0), ecx);
   1548       // ... and fill the rest with holes.
   1549       for (int i = 1; i < kAllocationDelta; i++) {
   1550         __ mov(Operand(edx, i * kPointerSize),
   1551                Immediate(factory()->the_hole_value()));
   1552       }
   1553 
   1554       // Restore receiver to edx as finish sequence assumes it's here.
   1555       __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
   1556 
   1557       // Increment element's and array's sizes.
   1558       __ add(FieldOperand(ebx, FixedArray::kLengthOffset),
   1559              Immediate(Smi::FromInt(kAllocationDelta)));
   1560       __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
   1561 
   1562       // Elements are in new space, so write barrier is not required.
   1563       __ ret((argc + 1) * kPointerSize);
   1564     }
   1565 
   1566     __ bind(&call_builtin);
   1567     __ TailCallExternalReference(
   1568         ExternalReference(Builtins::c_ArrayPush, isolate()),
   1569         argc + 1,
   1570         1);
   1571   }
   1572 
   1573   __ bind(&miss);
   1574   MaybeObject* maybe_result = GenerateMissBranch();
   1575   if (maybe_result->IsFailure()) return maybe_result;
   1576 
   1577   // Return the generated code.
   1578   return GetCode(function);
   1579 }
   1580 
   1581 
   1582 MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
   1583                                                    JSObject* holder,
   1584                                                    JSGlobalPropertyCell* cell,
   1585                                                    JSFunction* function,
   1586                                                    String* name) {
   1587   // ----------- S t a t e -------------
   1588   //  -- ecx                 : name
   1589   //  -- esp[0]              : return address
   1590   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
   1591   //  -- ...
   1592   //  -- esp[(argc + 1) * 4] : receiver
   1593   // -----------------------------------
   1594 
   1595   // If object is not an array, bail out to regular call.
   1596   if (!object->IsJSArray() || cell != NULL) {
   1597     return heap()->undefined_value();
   1598   }
   1599 
   1600   Label miss, return_undefined, call_builtin;
   1601 
   1602   GenerateNameCheck(name, &miss);
   1603 
   1604   // Get the receiver from the stack.
   1605   const int argc = arguments().immediate();
   1606   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
   1607 
   1608   // Check that the receiver isn't a smi.
   1609   __ test(edx, Immediate(kSmiTagMask));
   1610   __ j(zero, &miss);
   1611   CheckPrototypes(JSObject::cast(object), edx,
   1612                   holder, ebx,
   1613                   eax, edi, name, &miss);
   1614 
   1615   // Get the elements array of the object.
   1616   __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset));
   1617 
   1618   // Check that the elements are in fast mode and writable.
   1619   __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
   1620          Immediate(factory()->fixed_array_map()));
   1621   __ j(not_equal, &call_builtin);
   1622 
   1623   // Get the array's length into ecx and calculate new length.
   1624   __ mov(ecx, FieldOperand(edx, JSArray::kLengthOffset));
   1625   __ sub(Operand(ecx), Immediate(Smi::FromInt(1)));
   1626   __ j(negative, &return_undefined);
   1627 
   1628   // Get the last element.
   1629   STATIC_ASSERT(kSmiTagSize == 1);
   1630   STATIC_ASSERT(kSmiTag == 0);
   1631   __ mov(eax, FieldOperand(ebx,
   1632                            ecx, times_half_pointer_size,
   1633                            FixedArray::kHeaderSize));
   1634   __ cmp(Operand(eax), Immediate(factory()->the_hole_value()));
   1635   __ j(equal, &call_builtin);
   1636 
   1637   // Set the array's length.
   1638   __ mov(FieldOperand(edx, JSArray::kLengthOffset), ecx);
   1639 
   1640   // Fill with the hole.
   1641   __ mov(FieldOperand(ebx,
   1642                       ecx, times_half_pointer_size,
   1643                       FixedArray::kHeaderSize),
   1644          Immediate(factory()->the_hole_value()));
   1645   __ ret((argc + 1) * kPointerSize);
   1646 
   1647   __ bind(&return_undefined);
   1648   __ mov(eax, Immediate(factory()->undefined_value()));
   1649   __ ret((argc + 1) * kPointerSize);
   1650 
   1651   __ bind(&call_builtin);
   1652   __ TailCallExternalReference(
   1653       ExternalReference(Builtins::c_ArrayPop, isolate()),
   1654       argc + 1,
   1655       1);
   1656 
   1657   __ bind(&miss);
   1658   MaybeObject* maybe_result = GenerateMissBranch();
   1659   if (maybe_result->IsFailure()) return maybe_result;
   1660 
   1661   // Return the generated code.
   1662   return GetCode(function);
   1663 }
   1664 
   1665 
   1666 MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
   1667     Object* object,
   1668     JSObject* holder,
   1669     JSGlobalPropertyCell* cell,
   1670     JSFunction* function,
   1671     String* name) {
   1672   // ----------- S t a t e -------------
   1673   //  -- ecx                 : function name
   1674   //  -- esp[0]              : return address
   1675   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
   1676   //  -- ...
   1677   //  -- esp[(argc + 1) * 4] : receiver
   1678   // -----------------------------------
   1679 
   1680   // If object is not a string, bail out to regular call.
   1681   if (!object->IsString() || cell != NULL) {
   1682     return isolate()->heap()->undefined_value();
   1683   }
   1684 
   1685   const int argc = arguments().immediate();
   1686 
   1687   Label miss;
   1688   Label name_miss;
   1689   Label index_out_of_range;
   1690   Label* index_out_of_range_label = &index_out_of_range;
   1691 
   1692   if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) {
   1693     index_out_of_range_label = &miss;
   1694   }
   1695 
   1696   GenerateNameCheck(name, &name_miss);
   1697 
   1698   // Check that the maps starting from the prototype haven't changed.
   1699   GenerateDirectLoadGlobalFunctionPrototype(masm(),
   1700                                             Context::STRING_FUNCTION_INDEX,
   1701                                             eax,
   1702                                             &miss);
   1703   ASSERT(object != holder);
   1704   CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder,
   1705                   ebx, edx, edi, name, &miss);
   1706 
   1707   Register receiver = ebx;
   1708   Register index = edi;
   1709   Register scratch = edx;
   1710   Register result = eax;
   1711   __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
   1712   if (argc > 0) {
   1713     __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
   1714   } else {
   1715     __ Set(index, Immediate(factory()->undefined_value()));
   1716   }
   1717 
   1718   StringCharCodeAtGenerator char_code_at_generator(receiver,
   1719                                                    index,
   1720                                                    scratch,
   1721                                                    result,
   1722                                                    &miss,  // When not a string.
   1723                                                    &miss,  // When not a number.
   1724                                                    index_out_of_range_label,
   1725                                                    STRING_INDEX_IS_NUMBER);
   1726   char_code_at_generator.GenerateFast(masm());
   1727   __ ret((argc + 1) * kPointerSize);
   1728 
   1729   StubRuntimeCallHelper call_helper;
   1730   char_code_at_generator.GenerateSlow(masm(), call_helper);
   1731 
   1732   if (index_out_of_range.is_linked()) {
   1733     __ bind(&index_out_of_range);
   1734     __ Set(eax, Immediate(factory()->nan_value()));
   1735     __ ret((argc + 1) * kPointerSize);
   1736   }
   1737 
   1738   __ bind(&miss);
   1739   // Restore function name in ecx.
   1740   __ Set(ecx, Immediate(Handle<String>(name)));
   1741   __ bind(&name_miss);
   1742   MaybeObject* maybe_result = GenerateMissBranch();
   1743   if (maybe_result->IsFailure()) return maybe_result;
   1744 
   1745   // Return the generated code.
   1746   return GetCode(function);
   1747 }
   1748 
   1749 
   1750 MaybeObject* CallStubCompiler::CompileStringCharAtCall(
   1751     Object* object,
   1752     JSObject* holder,
   1753     JSGlobalPropertyCell* cell,
   1754     JSFunction* function,
   1755     String* name) {
   1756   // ----------- S t a t e -------------
   1757   //  -- ecx                 : function name
   1758   //  -- esp[0]              : return address
   1759   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
   1760   //  -- ...
   1761   //  -- esp[(argc + 1) * 4] : receiver
   1762   // -----------------------------------
   1763 
   1764   // If object is not a string, bail out to regular call.
   1765   if (!object->IsString() || cell != NULL) {
   1766     return heap()->undefined_value();
   1767   }
   1768 
   1769   const int argc = arguments().immediate();
   1770 
   1771   Label miss;
   1772   Label name_miss;
   1773   Label index_out_of_range;
   1774   Label* index_out_of_range_label = &index_out_of_range;
   1775 
   1776   if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) {
   1777     index_out_of_range_label = &miss;
   1778   }
   1779 
   1780   GenerateNameCheck(name, &name_miss);
   1781 
   1782   // Check that the maps starting from the prototype haven't changed.
   1783   GenerateDirectLoadGlobalFunctionPrototype(masm(),
   1784                                             Context::STRING_FUNCTION_INDEX,
   1785                                             eax,
   1786                                             &miss);
   1787   ASSERT(object != holder);
   1788   CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder,
   1789                   ebx, edx, edi, name, &miss);
   1790 
   1791   Register receiver = eax;
   1792   Register index = edi;
   1793   Register scratch1 = ebx;
   1794   Register scratch2 = edx;
   1795   Register result = eax;
   1796   __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
   1797   if (argc > 0) {
   1798     __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
   1799   } else {
   1800     __ Set(index, Immediate(factory()->undefined_value()));
   1801   }
   1802 
   1803   StringCharAtGenerator char_at_generator(receiver,
   1804                                           index,
   1805                                           scratch1,
   1806                                           scratch2,
   1807                                           result,
   1808                                           &miss,  // When not a string.
   1809                                           &miss,  // When not a number.
   1810                                           index_out_of_range_label,
   1811                                           STRING_INDEX_IS_NUMBER);
   1812   char_at_generator.GenerateFast(masm());
   1813   __ ret((argc + 1) * kPointerSize);
   1814 
   1815   StubRuntimeCallHelper call_helper;
   1816   char_at_generator.GenerateSlow(masm(), call_helper);
   1817 
   1818   if (index_out_of_range.is_linked()) {
   1819     __ bind(&index_out_of_range);
   1820     __ Set(eax, Immediate(factory()->empty_string()));
   1821     __ ret((argc + 1) * kPointerSize);
   1822   }
   1823 
   1824   __ bind(&miss);
   1825   // Restore function name in ecx.
   1826   __ Set(ecx, Immediate(Handle<String>(name)));
   1827   __ bind(&name_miss);
   1828   MaybeObject* maybe_result = GenerateMissBranch();
   1829   if (maybe_result->IsFailure()) return maybe_result;
   1830 
   1831   // Return the generated code.
   1832   return GetCode(function);
   1833 }
   1834 
   1835 
   1836 MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
   1837     Object* object,
   1838     JSObject* holder,
   1839     JSGlobalPropertyCell* cell,
   1840     JSFunction* function,
   1841     String* name) {
   1842   // ----------- S t a t e -------------
   1843   //  -- ecx                 : function name
   1844   //  -- esp[0]              : return address
   1845   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
   1846   //  -- ...
   1847   //  -- esp[(argc + 1) * 4] : receiver
   1848   // -----------------------------------
   1849 
   1850   const int argc = arguments().immediate();
   1851 
   1852   // If the object is not a JSObject or we got an unexpected number of
   1853   // arguments, bail out to the regular call.
   1854   if (!object->IsJSObject() || argc != 1) {
   1855     return isolate()->heap()->undefined_value();
   1856   }
   1857 
   1858   Label miss;
   1859   GenerateNameCheck(name, &miss);
   1860 
   1861   if (cell == NULL) {
   1862     __ mov(edx, Operand(esp, 2 * kPointerSize));
   1863 
   1864     STATIC_ASSERT(kSmiTag == 0);
   1865     __ test(edx, Immediate(kSmiTagMask));
   1866     __ j(zero, &miss);
   1867 
   1868     CheckPrototypes(JSObject::cast(object), edx, holder, ebx, eax, edi, name,
   1869                     &miss);
   1870   } else {
   1871     ASSERT(cell->value() == function);
   1872     GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
   1873     GenerateLoadFunctionFromCell(cell, function, &miss);
   1874   }
   1875 
   1876   // Load the char code argument.
   1877   Register code = ebx;
   1878   __ mov(code, Operand(esp, 1 * kPointerSize));
   1879 
   1880   // Check the code is a smi.
   1881   Label slow;
   1882   STATIC_ASSERT(kSmiTag == 0);
   1883   __ test(code, Immediate(kSmiTagMask));
   1884   __ j(not_zero, &slow);
   1885 
   1886   // Convert the smi code to uint16.
   1887   __ and_(code, Immediate(Smi::FromInt(0xffff)));
   1888 
   1889   StringCharFromCodeGenerator char_from_code_generator(code, eax);
   1890   char_from_code_generator.GenerateFast(masm());
   1891   __ ret(2 * kPointerSize);
   1892 
   1893   StubRuntimeCallHelper call_helper;
   1894   char_from_code_generator.GenerateSlow(masm(), call_helper);
   1895 
   1896   // Tail call the full function. We do not have to patch the receiver
   1897   // because the function makes no use of it.
   1898   __ bind(&slow);
   1899   __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
   1900 
   1901   __ bind(&miss);
   1902   // ecx: function name.
   1903   MaybeObject* maybe_result = GenerateMissBranch();
   1904   if (maybe_result->IsFailure()) return maybe_result;
   1905 
   1906   // Return the generated code.
   1907   return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
   1908 }
   1909 
   1910 
   1911 MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object,
   1912                                                     JSObject* holder,
   1913                                                     JSGlobalPropertyCell* cell,
   1914                                                     JSFunction* function,
   1915                                                     String* name) {
   1916   // ----------- S t a t e -------------
   1917   //  -- ecx                 : name
   1918   //  -- esp[0]              : return address
   1919   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
   1920   //  -- ...
   1921   //  -- esp[(argc + 1) * 4] : receiver
   1922   // -----------------------------------
   1923 
   1924   if (!CpuFeatures::IsSupported(SSE2)) {
   1925     return isolate()->heap()->undefined_value();
   1926   }
   1927 
   1928   CpuFeatures::Scope use_sse2(SSE2);
   1929 
   1930   const int argc = arguments().immediate();
   1931 
   1932   // If the object is not a JSObject or we got an unexpected number of
   1933   // arguments, bail out to the regular call.
   1934   if (!object->IsJSObject() || argc != 1) {
   1935     return isolate()->heap()->undefined_value();
   1936   }
   1937 
   1938   Label miss;
   1939   GenerateNameCheck(name, &miss);
   1940 
   1941   if (cell == NULL) {
   1942     __ mov(edx, Operand(esp, 2 * kPointerSize));
   1943 
   1944     STATIC_ASSERT(kSmiTag == 0);
   1945     __ test(edx, Immediate(kSmiTagMask));
   1946     __ j(zero, &miss);
   1947 
   1948     CheckPrototypes(JSObject::cast(object), edx, holder, ebx, eax, edi, name,
   1949                     &miss);
   1950   } else {
   1951     ASSERT(cell->value() == function);
   1952     GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
   1953     GenerateLoadFunctionFromCell(cell, function, &miss);
   1954   }
   1955 
   1956   // Load the (only) argument into eax.
   1957   __ mov(eax, Operand(esp, 1 * kPointerSize));
   1958 
   1959   // Check if the argument is a smi.
   1960   Label smi;
   1961   STATIC_ASSERT(kSmiTag == 0);
   1962   __ test(eax, Immediate(kSmiTagMask));
   1963   __ j(zero, &smi);
   1964 
   1965   // Check if the argument is a heap number and load its value into xmm0.
   1966   Label slow;
   1967   __ CheckMap(eax, factory()->heap_number_map(), &slow, true);
   1968   __ movdbl(xmm0, FieldOperand(eax, HeapNumber::kValueOffset));
   1969 
   1970   // Check if the argument is strictly positive. Note this also
   1971   // discards NaN.
   1972   __ xorpd(xmm1, xmm1);
   1973   __ ucomisd(xmm0, xmm1);
   1974   __ j(below_equal, &slow);
   1975 
   1976   // Do a truncating conversion.
   1977   __ cvttsd2si(eax, Operand(xmm0));
   1978 
   1979   // Check if the result fits into a smi. Note this also checks for
   1980   // 0x80000000 which signals a failed conversion.
   1981   Label wont_fit_into_smi;
   1982   __ test(eax, Immediate(0xc0000000));
   1983   __ j(not_zero, &wont_fit_into_smi);
   1984 
   1985   // Smi tag and return.
   1986   __ SmiTag(eax);
   1987   __ bind(&smi);
   1988   __ ret(2 * kPointerSize);
   1989 
   1990   // Check if the argument is < 2^kMantissaBits.
   1991   Label already_round;
   1992   __ bind(&wont_fit_into_smi);
   1993   __ LoadPowerOf2(xmm1, ebx, HeapNumber::kMantissaBits);
   1994   __ ucomisd(xmm0, xmm1);
   1995   __ j(above_equal, &already_round);
   1996 
   1997   // Save a copy of the argument.
   1998   __ movaps(xmm2, xmm0);
   1999 
   2000   // Compute (argument + 2^kMantissaBits) - 2^kMantissaBits.
   2001   __ addsd(xmm0, xmm1);
   2002   __ subsd(xmm0, xmm1);
   2003 
   2004   // Compare the argument and the tentative result to get the right mask:
   2005   //   if xmm2 < xmm0:
   2006   //     xmm2 = 1...1
   2007   //   else:
   2008   //     xmm2 = 0...0
   2009   __ cmpltsd(xmm2, xmm0);
   2010 
   2011   // Subtract 1 if the argument was less than the tentative result.
   2012   __ LoadPowerOf2(xmm1, ebx, 0);
   2013   __ andpd(xmm1, xmm2);
   2014   __ subsd(xmm0, xmm1);
   2015 
   2016   // Return a new heap number.
   2017   __ AllocateHeapNumber(eax, ebx, edx, &slow);
   2018   __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
   2019   __ ret(2 * kPointerSize);
   2020 
   2021   // Return the argument (when it's an already round heap number).
   2022   __ bind(&already_round);
   2023   __ mov(eax, Operand(esp, 1 * kPointerSize));
   2024   __ ret(2 * kPointerSize);
   2025 
   2026   // Tail call the full function. We do not have to patch the receiver
   2027   // because the function makes no use of it.
   2028   __ bind(&slow);
   2029   __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
   2030 
   2031   __ bind(&miss);
   2032   // ecx: function name.
   2033   MaybeObject* maybe_result = GenerateMissBranch();
   2034   if (maybe_result->IsFailure()) return maybe_result;
   2035 
   2036   // Return the generated code.
   2037   return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
   2038 }
   2039 
   2040 
   2041 MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
   2042                                                   JSObject* holder,
   2043                                                   JSGlobalPropertyCell* cell,
   2044                                                   JSFunction* function,
   2045                                                   String* name) {
   2046   // ----------- S t a t e -------------
   2047   //  -- ecx                 : name
   2048   //  -- esp[0]              : return address
   2049   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
   2050   //  -- ...
   2051   //  -- esp[(argc + 1) * 4] : receiver
   2052   // -----------------------------------
   2053 
   2054   const int argc = arguments().immediate();
   2055 
   2056   // If the object is not a JSObject or we got an unexpected number of
   2057   // arguments, bail out to the regular call.
   2058   if (!object->IsJSObject() || argc != 1) {
   2059     return isolate()->heap()->undefined_value();
   2060   }
   2061 
   2062   Label miss;
   2063   GenerateNameCheck(name, &miss);
   2064 
   2065   if (cell == NULL) {
   2066     __ mov(edx, Operand(esp, 2 * kPointerSize));
   2067 
   2068     STATIC_ASSERT(kSmiTag == 0);
   2069     __ test(edx, Immediate(kSmiTagMask));
   2070     __ j(zero, &miss);
   2071 
   2072     CheckPrototypes(JSObject::cast(object), edx, holder, ebx, eax, edi, name,
   2073                     &miss);
   2074   } else {
   2075     ASSERT(cell->value() == function);
   2076     GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
   2077     GenerateLoadFunctionFromCell(cell, function, &miss);
   2078   }
   2079 
   2080   // Load the (only) argument into eax.
   2081   __ mov(eax, Operand(esp, 1 * kPointerSize));
   2082 
   2083   // Check if the argument is a smi.
   2084   Label not_smi;
   2085   STATIC_ASSERT(kSmiTag == 0);
   2086   __ test(eax, Immediate(kSmiTagMask));
   2087   __ j(not_zero, &not_smi);
   2088 
   2089   // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0
   2090   // otherwise.
   2091   __ mov(ebx, eax);
   2092   __ sar(ebx, kBitsPerInt - 1);
   2093 
   2094   // Do bitwise not or do nothing depending on ebx.
   2095   __ xor_(eax, Operand(ebx));
   2096 
   2097   // Add 1 or do nothing depending on ebx.
   2098   __ sub(eax, Operand(ebx));
   2099 
   2100   // If the result is still negative, go to the slow case.
   2101   // This only happens for the most negative smi.
   2102   Label slow;
   2103   __ j(negative, &slow);
   2104 
   2105   // Smi case done.
   2106   __ ret(2 * kPointerSize);
   2107 
   2108   // Check if the argument is a heap number and load its exponent and
   2109   // sign into ebx.
   2110   __ bind(&not_smi);
   2111   __ CheckMap(eax, factory()->heap_number_map(), &slow, true);
   2112   __ mov(ebx, FieldOperand(eax, HeapNumber::kExponentOffset));
   2113 
   2114   // Check the sign of the argument. If the argument is positive,
   2115   // just return it.
   2116   Label negative_sign;
   2117   __ test(ebx, Immediate(HeapNumber::kSignMask));
   2118   __ j(not_zero, &negative_sign);
   2119   __ ret(2 * kPointerSize);
   2120 
   2121   // If the argument is negative, clear the sign, and return a new
   2122   // number.
   2123   __ bind(&negative_sign);
   2124   __ and_(ebx, ~HeapNumber::kSignMask);
   2125   __ mov(ecx, FieldOperand(eax, HeapNumber::kMantissaOffset));
   2126   __ AllocateHeapNumber(eax, edi, edx, &slow);
   2127   __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ebx);
   2128   __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx);
   2129   __ ret(2 * kPointerSize);
   2130 
   2131   // Tail call the full function. We do not have to patch the receiver
   2132   // because the function makes no use of it.
   2133   __ bind(&slow);
   2134   __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
   2135 
   2136   __ bind(&miss);
   2137   // ecx: function name.
   2138   MaybeObject* maybe_result = GenerateMissBranch();
   2139   if (maybe_result->IsFailure()) return maybe_result;
   2140 
   2141   // Return the generated code.
   2142   return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
   2143 }
   2144 
   2145 
   2146 MaybeObject* CallStubCompiler::CompileFastApiCall(
   2147     const CallOptimization& optimization,
   2148     Object* object,
   2149     JSObject* holder,
   2150     JSGlobalPropertyCell* cell,
   2151     JSFunction* function,
   2152     String* name) {
   2153   ASSERT(optimization.is_simple_api_call());
   2154   // Bail out if object is a global object as we don't want to
   2155   // repatch it to global receiver.
   2156   if (object->IsGlobalObject()) return heap()->undefined_value();
   2157   if (cell != NULL) return heap()->undefined_value();
   2158   int depth = optimization.GetPrototypeDepthOfExpectedType(
   2159             JSObject::cast(object), holder);
   2160   if (depth == kInvalidProtoDepth) return heap()->undefined_value();
   2161 
   2162   Label miss, miss_before_stack_reserved;
   2163 
   2164   GenerateNameCheck(name, &miss_before_stack_reserved);
   2165 
   2166   // Get the receiver from the stack.
   2167   const int argc = arguments().immediate();
   2168   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
   2169 
   2170   // Check that the receiver isn't a smi.
   2171   __ test(edx, Immediate(kSmiTagMask));
   2172   __ j(zero, &miss_before_stack_reserved, not_taken);
   2173 
   2174   Counters* counters = isolate()->counters();
   2175   __ IncrementCounter(counters->call_const(), 1);
   2176   __ IncrementCounter(counters->call_const_fast_api(), 1);
   2177 
   2178   // Allocate space for v8::Arguments implicit values. Must be initialized
   2179   // before calling any runtime function.
   2180   __ sub(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize));
   2181 
   2182   // Check that the maps haven't changed and find a Holder as a side effect.
   2183   CheckPrototypes(JSObject::cast(object), edx, holder,
   2184                   ebx, eax, edi, name, depth, &miss);
   2185 
   2186   // Move the return address on top of the stack.
   2187   __ mov(eax, Operand(esp, 3 * kPointerSize));
   2188   __ mov(Operand(esp, 0 * kPointerSize), eax);
   2189 
   2190   // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains
   2191   // duplicate of return address and will be overwritten.
   2192   MaybeObject* result = GenerateFastApiCall(masm(), optimization, argc);
   2193   if (result->IsFailure()) return result;
   2194 
   2195   __ bind(&miss);
   2196   __ add(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize));
   2197 
   2198   __ bind(&miss_before_stack_reserved);
   2199   MaybeObject* maybe_result = GenerateMissBranch();
   2200   if (maybe_result->IsFailure()) return maybe_result;
   2201 
   2202   // Return the generated code.
   2203   return GetCode(function);
   2204 }
   2205 
   2206 
   2207 MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
   2208                                                    JSObject* holder,
   2209                                                    JSFunction* function,
   2210                                                    String* name,
   2211                                                    CheckType check) {
   2212   // ----------- S t a t e -------------
   2213   //  -- ecx                 : name
   2214   //  -- esp[0]              : return address
   2215   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
   2216   //  -- ...
   2217   //  -- esp[(argc + 1) * 4] : receiver
   2218   // -----------------------------------
   2219 
   2220   if (HasCustomCallGenerator(function)) {
   2221     MaybeObject* maybe_result = CompileCustomCall(
   2222         object, holder, NULL, function, name);
   2223     Object* result;
   2224     if (!maybe_result->ToObject(&result)) return maybe_result;
   2225     // undefined means bail out to regular compiler.
   2226     if (!result->IsUndefined()) return result;
   2227   }
   2228 
   2229   Label miss;
   2230 
   2231   GenerateNameCheck(name, &miss);
   2232 
   2233   // Get the receiver from the stack.
   2234   const int argc = arguments().immediate();
   2235   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
   2236 
   2237   // Check that the receiver isn't a smi.
   2238   if (check != NUMBER_CHECK) {
   2239     __ test(edx, Immediate(kSmiTagMask));
   2240     __ j(zero, &miss, not_taken);
   2241   }
   2242 
   2243   // Make sure that it's okay not to patch the on stack receiver
   2244   // unless we're doing a receiver map check.
   2245   ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
   2246 
   2247   SharedFunctionInfo* function_info = function->shared();
   2248   switch (check) {
   2249     case RECEIVER_MAP_CHECK:
   2250       __ IncrementCounter(isolate()->counters()->call_const(), 1);
   2251 
   2252       // Check that the maps haven't changed.
   2253       CheckPrototypes(JSObject::cast(object), edx, holder,
   2254                       ebx, eax, edi, name, &miss);
   2255 
   2256       // Patch the receiver on the stack with the global proxy if
   2257       // necessary.
   2258       if (object->IsGlobalObject()) {
   2259         __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
   2260         __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
   2261       }
   2262       break;
   2263 
   2264     case STRING_CHECK:
   2265       if (!function->IsBuiltin() && !function_info->strict_mode()) {
   2266         // Calling non-strict non-builtins with a value as the receiver
   2267         // requires boxing.
   2268         __ jmp(&miss);
   2269       } else {
   2270         // Check that the object is a string or a symbol.
   2271         __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, eax);
   2272         __ j(above_equal, &miss, not_taken);
   2273         // Check that the maps starting from the prototype haven't changed.
   2274         GenerateDirectLoadGlobalFunctionPrototype(
   2275             masm(), Context::STRING_FUNCTION_INDEX, eax, &miss);
   2276         CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder,
   2277                         ebx, edx, edi, name, &miss);
   2278       }
   2279       break;
   2280 
   2281     case NUMBER_CHECK: {
   2282       if (!function->IsBuiltin() && !function_info->strict_mode()) {
   2283         // Calling non-strict non-builtins with a value as the receiver
   2284         // requires boxing.
   2285         __ jmp(&miss);
   2286       } else {
   2287         Label fast;
   2288         // Check that the object is a smi or a heap number.
   2289         __ test(edx, Immediate(kSmiTagMask));
   2290         __ j(zero, &fast, taken);
   2291         __ CmpObjectType(edx, HEAP_NUMBER_TYPE, eax);
   2292         __ j(not_equal, &miss, not_taken);
   2293         __ bind(&fast);
   2294         // Check that the maps starting from the prototype haven't changed.
   2295         GenerateDirectLoadGlobalFunctionPrototype(
   2296             masm(), Context::NUMBER_FUNCTION_INDEX, eax, &miss);
   2297         CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder,
   2298                         ebx, edx, edi, name, &miss);
   2299       }
   2300       break;
   2301     }
   2302 
   2303     case BOOLEAN_CHECK: {
   2304       if (!function->IsBuiltin() && !function_info->strict_mode()) {
   2305         // Calling non-strict non-builtins with a value as the receiver
   2306         // requires boxing.
   2307         __ jmp(&miss);
   2308       } else {
   2309         Label fast;
   2310         // Check that the object is a boolean.
   2311         __ cmp(edx, factory()->true_value());
   2312         __ j(equal, &fast, taken);
   2313         __ cmp(edx, factory()->false_value());
   2314         __ j(not_equal, &miss, not_taken);
   2315         __ bind(&fast);
   2316         // Check that the maps starting from the prototype haven't changed.
   2317         GenerateDirectLoadGlobalFunctionPrototype(
   2318             masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, &miss);
   2319         CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder,
   2320                         ebx, edx, edi, name, &miss);
   2321       }
   2322       break;
   2323     }
   2324 
   2325     default:
   2326       UNREACHABLE();
   2327   }
   2328 
   2329   __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
   2330 
   2331   // Handle call cache miss.
   2332   __ bind(&miss);
   2333   MaybeObject* maybe_result = GenerateMissBranch();
   2334   if (maybe_result->IsFailure()) return maybe_result;
   2335 
   2336   // Return the generated code.
   2337   return GetCode(function);
   2338 }
   2339 
   2340 
   2341 MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
   2342                                                       JSObject* holder,
   2343                                                       String* name) {
   2344   // ----------- S t a t e -------------
   2345   //  -- ecx                 : name
   2346   //  -- esp[0]              : return address
   2347   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
   2348   //  -- ...
   2349   //  -- esp[(argc + 1) * 4] : receiver
   2350   // -----------------------------------
   2351   Label miss;
   2352 
   2353   GenerateNameCheck(name, &miss);
   2354 
   2355   // Get the number of arguments.
   2356   const int argc = arguments().immediate();
   2357 
   2358   LookupResult lookup;
   2359   LookupPostInterceptor(holder, name, &lookup);
   2360 
   2361   // Get the receiver from the stack.
   2362   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
   2363 
   2364   CallInterceptorCompiler compiler(this, arguments(), ecx);
   2365   MaybeObject* result = compiler.Compile(masm(),
   2366                                          object,
   2367                                          holder,
   2368                                          name,
   2369                                          &lookup,
   2370                                          edx,
   2371                                          ebx,
   2372                                          edi,
   2373                                          eax,
   2374                                          &miss);
   2375   if (result->IsFailure()) return result;
   2376 
   2377   // Restore receiver.
   2378   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
   2379 
   2380   // Check that the function really is a function.
   2381   __ test(eax, Immediate(kSmiTagMask));
   2382   __ j(zero, &miss, not_taken);
   2383   __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
   2384   __ j(not_equal, &miss, not_taken);
   2385 
   2386   // Patch the receiver on the stack with the global proxy if
   2387   // necessary.
   2388   if (object->IsGlobalObject()) {
   2389     __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
   2390     __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
   2391   }
   2392 
   2393   // Invoke the function.
   2394   __ mov(edi, eax);
   2395   __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
   2396 
   2397   // Handle load cache miss.
   2398   __ bind(&miss);
   2399   MaybeObject* maybe_result = GenerateMissBranch();
   2400   if (maybe_result->IsFailure()) return maybe_result;
   2401 
   2402   // Return the generated code.
   2403   return GetCode(INTERCEPTOR, name);
   2404 }
   2405 
   2406 
   2407 MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
   2408                                                  GlobalObject* holder,
   2409                                                  JSGlobalPropertyCell* cell,
   2410                                                  JSFunction* function,
   2411                                                  String* name) {
   2412   // ----------- S t a t e -------------
   2413   //  -- ecx                 : name
   2414   //  -- esp[0]              : return address
   2415   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
   2416   //  -- ...
   2417   //  -- esp[(argc + 1) * 4] : receiver
   2418   // -----------------------------------
   2419 
   2420   if (HasCustomCallGenerator(function)) {
   2421     MaybeObject* maybe_result = CompileCustomCall(
   2422         object, holder, cell, function, name);
   2423     Object* result;
   2424     if (!maybe_result->ToObject(&result)) return maybe_result;
   2425     // undefined means bail out to regular compiler.
   2426     if (!result->IsUndefined()) return result;
   2427   }
   2428 
   2429   Label miss;
   2430 
   2431   GenerateNameCheck(name, &miss);
   2432 
   2433   // Get the number of arguments.
   2434   const int argc = arguments().immediate();
   2435 
   2436   GenerateGlobalReceiverCheck(object, holder, name, &miss);
   2437 
   2438   GenerateLoadFunctionFromCell(cell, function, &miss);
   2439 
   2440   // Patch the receiver on the stack with the global proxy.
   2441   if (object->IsGlobalObject()) {
   2442     __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
   2443     __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
   2444   }
   2445 
   2446   // Setup the context (function already in edi).
   2447   __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
   2448 
   2449   // Jump to the cached code (tail call).
   2450   Counters* counters = isolate()->counters();
   2451   __ IncrementCounter(counters->call_global_inline(), 1);
   2452   ASSERT(function->is_compiled());
   2453   ParameterCount expected(function->shared()->formal_parameter_count());
   2454   if (V8::UseCrankshaft()) {
   2455     // TODO(kasperl): For now, we always call indirectly through the
   2456     // code field in the function to allow recompilation to take effect
   2457     // without changing any of the call sites.
   2458     __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
   2459                   expected, arguments(), JUMP_FUNCTION);
   2460   } else {
   2461     Handle<Code> code(function->code());
   2462     __ InvokeCode(code, expected, arguments(),
   2463                   RelocInfo::CODE_TARGET, JUMP_FUNCTION);
   2464   }
   2465 
   2466   // Handle call cache miss.
   2467   __ bind(&miss);
   2468   __ IncrementCounter(counters->call_global_inline_miss(), 1);
   2469   MaybeObject* maybe_result = GenerateMissBranch();
   2470   if (maybe_result->IsFailure()) return maybe_result;
   2471 
   2472   // Return the generated code.
   2473   return GetCode(NORMAL, name);
   2474 }
   2475 
   2476 
   2477 MaybeObject* StoreStubCompiler::CompileStoreField(JSObject* object,
   2478                                                   int index,
   2479                                                   Map* transition,
   2480                                                   String* name) {
   2481   // ----------- S t a t e -------------
   2482   //  -- eax    : value
   2483   //  -- ecx    : name
   2484   //  -- edx    : receiver
   2485   //  -- esp[0] : return address
   2486   // -----------------------------------
   2487   Label miss;
   2488 
   2489   // Generate store field code.  Trashes the name register.
   2490   GenerateStoreField(masm(),
   2491                      object,
   2492                      index,
   2493                      transition,
   2494                      edx, ecx, ebx,
   2495                      &miss);
   2496 
   2497   // Handle store cache miss.
   2498   __ bind(&miss);
   2499   __ mov(ecx, Immediate(Handle<String>(name)));  // restore name
   2500   Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
   2501   __ jmp(ic, RelocInfo::CODE_TARGET);
   2502 
   2503   // Return the generated code.
   2504   return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
   2505 }
   2506 
   2507 
   2508 MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object,
   2509                                                      AccessorInfo* callback,
   2510                                                      String* name) {
   2511   // ----------- S t a t e -------------
   2512   //  -- eax    : value
   2513   //  -- ecx    : name
   2514   //  -- edx    : receiver
   2515   //  -- esp[0] : return address
   2516   // -----------------------------------
   2517   Label miss;
   2518 
   2519   // Check that the object isn't a smi.
   2520   __ test(edx, Immediate(kSmiTagMask));
   2521   __ j(zero, &miss, not_taken);
   2522 
   2523   // Check that the map of the object hasn't changed.
   2524   __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
   2525          Immediate(Handle<Map>(object->map())));
   2526   __ j(not_equal, &miss, not_taken);
   2527 
   2528   // Perform global security token check if needed.
   2529   if (object->IsJSGlobalProxy()) {
   2530     __ CheckAccessGlobalProxy(edx, ebx, &miss);
   2531   }
   2532 
   2533   // Stub never generated for non-global objects that require access
   2534   // checks.
   2535   ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
   2536 
   2537   __ pop(ebx);  // remove the return address
   2538   __ push(edx);  // receiver
   2539   __ push(Immediate(Handle<AccessorInfo>(callback)));  // callback info
   2540   __ push(ecx);  // name
   2541   __ push(eax);  // value
   2542   __ push(ebx);  // restore return address
   2543 
   2544   // Do tail-call to the runtime system.
   2545   ExternalReference store_callback_property =
   2546       ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
   2547   __ TailCallExternalReference(store_callback_property, 4, 1);
   2548 
   2549   // Handle store cache miss.
   2550   __ bind(&miss);
   2551   Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
   2552   __ jmp(ic, RelocInfo::CODE_TARGET);
   2553 
   2554   // Return the generated code.
   2555   return GetCode(CALLBACKS, name);
   2556 }
   2557 
   2558 
   2559 MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
   2560                                                         String* name) {
   2561   // ----------- S t a t e -------------
   2562   //  -- eax    : value
   2563   //  -- ecx    : name
   2564   //  -- edx    : receiver
   2565   //  -- esp[0] : return address
   2566   // -----------------------------------
   2567   Label miss;
   2568 
   2569   // Check that the object isn't a smi.
   2570   __ test(edx, Immediate(kSmiTagMask));
   2571   __ j(zero, &miss, not_taken);
   2572 
   2573   // Check that the map of the object hasn't changed.
   2574   __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
   2575          Immediate(Handle<Map>(receiver->map())));
   2576   __ j(not_equal, &miss, not_taken);
   2577 
   2578   // Perform global security token check if needed.
   2579   if (receiver->IsJSGlobalProxy()) {
   2580     __ CheckAccessGlobalProxy(edx, ebx, &miss);
   2581   }
   2582 
   2583   // Stub never generated for non-global objects that require access
   2584   // checks.
   2585   ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
   2586 
   2587   __ pop(ebx);  // remove the return address
   2588   __ push(edx);  // receiver
   2589   __ push(ecx);  // name
   2590   __ push(eax);  // value
   2591   __ push(Immediate(Smi::FromInt(strict_mode_)));
   2592   __ push(ebx);  // restore return address
   2593 
   2594   // Do tail-call to the runtime system.
   2595   ExternalReference store_ic_property =
   2596       ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
   2597   __ TailCallExternalReference(store_ic_property, 4, 1);
   2598 
   2599   // Handle store cache miss.
   2600   __ bind(&miss);
   2601   Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
   2602   __ jmp(ic, RelocInfo::CODE_TARGET);
   2603 
   2604   // Return the generated code.
   2605   return GetCode(INTERCEPTOR, name);
   2606 }
   2607 
   2608 
   2609 MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
   2610                                                    JSGlobalPropertyCell* cell,
   2611                                                    String* name) {
   2612   // ----------- S t a t e -------------
   2613   //  -- eax    : value
   2614   //  -- ecx    : name
   2615   //  -- edx    : receiver
   2616   //  -- esp[0] : return address
   2617   // -----------------------------------
   2618   Label miss;
   2619 
   2620   // Check that the map of the global has not changed.
   2621   __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
   2622          Immediate(Handle<Map>(object->map())));
   2623   __ j(not_equal, &miss, not_taken);
   2624 
   2625 
   2626   // Compute the cell operand to use.
   2627   Operand cell_operand = Operand::Cell(Handle<JSGlobalPropertyCell>(cell));
   2628   if (Serializer::enabled()) {
   2629     __ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell)));
   2630     cell_operand = FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset);
   2631   }
   2632 
   2633   // Check that the value in the cell is not the hole. If it is, this
   2634   // cell could have been deleted and reintroducing the global needs
   2635   // to update the property details in the property dictionary of the
   2636   // global object. We bail out to the runtime system to do that.
   2637   __ cmp(cell_operand, factory()->the_hole_value());
   2638   __ j(equal, &miss);
   2639 
   2640   // Store the value in the cell.
   2641   __ mov(cell_operand, eax);
   2642 
   2643   // Return the value (register eax).
   2644   Counters* counters = isolate()->counters();
   2645   __ IncrementCounter(counters->named_store_global_inline(), 1);
   2646   __ ret(0);
   2647 
   2648   // Handle store cache miss.
   2649   __ bind(&miss);
   2650   __ IncrementCounter(counters->named_store_global_inline_miss(), 1);
   2651   Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
   2652   __ jmp(ic, RelocInfo::CODE_TARGET);
   2653 
   2654   // Return the generated code.
   2655   return GetCode(NORMAL, name);
   2656 }
   2657 
   2658 
   2659 MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
   2660                                                        int index,
   2661                                                        Map* transition,
   2662                                                        String* name) {
   2663   // ----------- S t a t e -------------
   2664   //  -- eax    : value
   2665   //  -- ecx    : key
   2666   //  -- edx    : receiver
   2667   //  -- esp[0] : return address
   2668   // -----------------------------------
   2669   Label miss;
   2670 
   2671   Counters* counters = isolate()->counters();
   2672   __ IncrementCounter(counters->keyed_store_field(), 1);
   2673 
   2674   // Check that the name has not changed.
   2675   __ cmp(Operand(ecx), Immediate(Handle<String>(name)));
   2676   __ j(not_equal, &miss, not_taken);
   2677 
   2678   // Generate store field code.  Trashes the name register.
   2679   GenerateStoreField(masm(),
   2680                      object,
   2681                      index,
   2682                      transition,
   2683                      edx, ecx, ebx,
   2684                      &miss);
   2685 
   2686   // Handle store cache miss.
   2687   __ bind(&miss);
   2688   __ DecrementCounter(counters->keyed_store_field(), 1);
   2689   Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
   2690   __ jmp(ic, RelocInfo::CODE_TARGET);
   2691 
   2692   // Return the generated code.
   2693   return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
   2694 }
   2695 
   2696 
   2697 MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
   2698     JSObject* receiver) {
   2699   // ----------- S t a t e -------------
   2700   //  -- eax    : value
   2701   //  -- ecx    : key
   2702   //  -- edx    : receiver
   2703   //  -- esp[0] : return address
   2704   // -----------------------------------
   2705   Label miss;
   2706 
   2707   // Check that the receiver isn't a smi.
   2708   __ test(edx, Immediate(kSmiTagMask));
   2709   __ j(zero, &miss, not_taken);
   2710 
   2711   // Check that the map matches.
   2712   __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
   2713          Immediate(Handle<Map>(receiver->map())));
   2714   __ j(not_equal, &miss, not_taken);
   2715 
   2716   // Check that the key is a smi.
   2717   __ test(ecx, Immediate(kSmiTagMask));
   2718   __ j(not_zero, &miss, not_taken);
   2719 
   2720   // Get the elements array and make sure it is a fast element array, not 'cow'.
   2721   __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
   2722   __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
   2723          Immediate(factory()->fixed_array_map()));
   2724   __ j(not_equal, &miss, not_taken);
   2725 
   2726   // Check that the key is within bounds.
   2727   if (receiver->IsJSArray()) {
   2728     __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset));  // Compare smis.
   2729     __ j(above_equal, &miss, not_taken);
   2730   } else {
   2731     __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset));  // Compare smis.
   2732     __ j(above_equal, &miss, not_taken);
   2733   }
   2734 
   2735   // Do the store and update the write barrier. Make sure to preserve
   2736   // the value in register eax.
   2737   __ mov(edx, Operand(eax));
   2738   __ mov(FieldOperand(edi, ecx, times_2, FixedArray::kHeaderSize), eax);
   2739   __ RecordWrite(edi, 0, edx, ecx);
   2740 
   2741   // Done.
   2742   __ ret(0);
   2743 
   2744   // Handle store cache miss.
   2745   __ bind(&miss);
   2746   Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
   2747   __ jmp(ic, RelocInfo::CODE_TARGET);
   2748 
   2749   // Return the generated code.
   2750   return GetCode(NORMAL, NULL);
   2751 }
   2752 
   2753 
   2754 MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name,
   2755                                                       JSObject* object,
   2756                                                       JSObject* last) {
   2757   // ----------- S t a t e -------------
   2758   //  -- eax    : receiver
   2759   //  -- ecx    : name
   2760   //  -- esp[0] : return address
   2761   // -----------------------------------
   2762   Label miss;
   2763 
   2764   // Check that the receiver isn't a smi.
   2765   __ test(eax, Immediate(kSmiTagMask));
   2766   __ j(zero, &miss, not_taken);
   2767 
   2768   ASSERT(last->IsGlobalObject() || last->HasFastProperties());
   2769 
   2770   // Check the maps of the full prototype chain. Also check that
   2771   // global property cells up to (but not including) the last object
   2772   // in the prototype chain are empty.
   2773   CheckPrototypes(object, eax, last, ebx, edx, edi, name, &miss);
   2774 
   2775   // If the last object in the prototype chain is a global object,
   2776   // check that the global property cell is empty.
   2777   if (last->IsGlobalObject()) {
   2778     MaybeObject* cell = GenerateCheckPropertyCell(masm(),
   2779                                                   GlobalObject::cast(last),
   2780                                                   name,
   2781                                                   edx,
   2782                                                   &miss);
   2783     if (cell->IsFailure()) {
   2784       miss.Unuse();
   2785       return cell;
   2786     }
   2787   }
   2788 
   2789   // Return undefined if maps of the full prototype chain are still the
   2790   // same and no global property with this name contains a value.
   2791   __ mov(eax, isolate()->factory()->undefined_value());
   2792   __ ret(0);
   2793 
   2794   __ bind(&miss);
   2795   GenerateLoadMiss(masm(), Code::LOAD_IC);
   2796 
   2797   // Return the generated code.
   2798   return GetCode(NONEXISTENT, isolate()->heap()->empty_string());
   2799 }
   2800 
   2801 
   2802 MaybeObject* LoadStubCompiler::CompileLoadField(JSObject* object,
   2803                                                 JSObject* holder,
   2804                                                 int index,
   2805                                                 String* name) {
   2806   // ----------- S t a t e -------------
   2807   //  -- eax    : receiver
   2808   //  -- ecx    : name
   2809   //  -- esp[0] : return address
   2810   // -----------------------------------
   2811   Label miss;
   2812 
   2813   GenerateLoadField(object, holder, eax, ebx, edx, edi, index, name, &miss);
   2814   __ bind(&miss);
   2815   GenerateLoadMiss(masm(), Code::LOAD_IC);
   2816 
   2817   // Return the generated code.
   2818   return GetCode(FIELD, name);
   2819 }
   2820 
   2821 
   2822 MaybeObject* LoadStubCompiler::CompileLoadCallback(String* name,
   2823                                                    JSObject* object,
   2824                                                    JSObject* holder,
   2825                                                    AccessorInfo* callback) {
   2826   // ----------- S t a t e -------------
   2827   //  -- eax    : receiver
   2828   //  -- ecx    : name
   2829   //  -- esp[0] : return address
   2830   // -----------------------------------
   2831   Label miss;
   2832 
   2833   MaybeObject* result = GenerateLoadCallback(object, holder, eax, ecx, ebx, edx,
   2834                                              edi, callback, name, &miss);
   2835   if (result->IsFailure()) {
   2836     miss.Unuse();
   2837     return result;
   2838   }
   2839 
   2840   __ bind(&miss);
   2841   GenerateLoadMiss(masm(), Code::LOAD_IC);
   2842 
   2843   // Return the generated code.
   2844   return GetCode(CALLBACKS, name);
   2845 }
   2846 
   2847 
   2848 MaybeObject* LoadStubCompiler::CompileLoadConstant(JSObject* object,
   2849                                                    JSObject* holder,
   2850                                                    Object* value,
   2851                                                    String* name) {
   2852   // ----------- S t a t e -------------
   2853   //  -- eax    : receiver
   2854   //  -- ecx    : name
   2855   //  -- esp[0] : return address
   2856   // -----------------------------------
   2857   Label miss;
   2858 
   2859   GenerateLoadConstant(object, holder, eax, ebx, edx, edi, value, name, &miss);
   2860   __ bind(&miss);
   2861   GenerateLoadMiss(masm(), Code::LOAD_IC);
   2862 
   2863   // Return the generated code.
   2864   return GetCode(CONSTANT_FUNCTION, name);
   2865 }
   2866 
   2867 
   2868 MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
   2869                                                       JSObject* holder,
   2870                                                       String* name) {
   2871   // ----------- S t a t e -------------
   2872   //  -- eax    : receiver
   2873   //  -- ecx    : name
   2874   //  -- esp[0] : return address
   2875   // -----------------------------------
   2876   Label miss;
   2877 
   2878   LookupResult lookup;
   2879   LookupPostInterceptor(holder, name, &lookup);
   2880 
   2881   // TODO(368): Compile in the whole chain: all the interceptors in
   2882   // prototypes and ultimate answer.
   2883   GenerateLoadInterceptor(receiver,
   2884                           holder,
   2885                           &lookup,
   2886                           eax,
   2887                           ecx,
   2888                           edx,
   2889                           ebx,
   2890                           edi,
   2891                           name,
   2892                           &miss);
   2893 
   2894   __ bind(&miss);
   2895   GenerateLoadMiss(masm(), Code::LOAD_IC);
   2896 
   2897   // Return the generated code.
   2898   return GetCode(INTERCEPTOR, name);
   2899 }
   2900 
   2901 
   2902 MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
   2903                                                  GlobalObject* holder,
   2904                                                  JSGlobalPropertyCell* cell,
   2905                                                  String* name,
   2906                                                  bool is_dont_delete) {
   2907   // ----------- S t a t e -------------
   2908   //  -- eax    : receiver
   2909   //  -- ecx    : name
   2910   //  -- esp[0] : return address
   2911   // -----------------------------------
   2912   Label miss;
   2913 
   2914   // If the object is the holder then we know that it's a global
   2915   // object which can only happen for contextual loads. In this case,
   2916   // the receiver cannot be a smi.
   2917   if (object != holder) {
   2918     __ test(eax, Immediate(kSmiTagMask));
   2919     __ j(zero, &miss, not_taken);
   2920   }
   2921 
   2922   // Check that the maps haven't changed.
   2923   CheckPrototypes(object, eax, holder, ebx, edx, edi, name, &miss);
   2924 
   2925   // Get the value from the cell.
   2926   if (Serializer::enabled()) {
   2927     __ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell)));
   2928     __ mov(ebx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset));
   2929   } else {
   2930     __ mov(ebx, Operand::Cell(Handle<JSGlobalPropertyCell>(cell)));
   2931   }
   2932 
   2933   // Check for deleted property if property can actually be deleted.
   2934   if (!is_dont_delete) {
   2935     __ cmp(ebx, factory()->the_hole_value());
   2936     __ j(equal, &miss, not_taken);
   2937   } else if (FLAG_debug_code) {
   2938     __ cmp(ebx, factory()->the_hole_value());
   2939     __ Check(not_equal, "DontDelete cells can't contain the hole");
   2940   }
   2941 
   2942   Counters* counters = isolate()->counters();
   2943   __ IncrementCounter(counters->named_load_global_stub(), 1);
   2944   __ mov(eax, ebx);
   2945   __ ret(0);
   2946 
   2947   __ bind(&miss);
   2948   __ IncrementCounter(counters->named_load_global_stub_miss(), 1);
   2949   GenerateLoadMiss(masm(), Code::LOAD_IC);
   2950 
   2951   // Return the generated code.
   2952   return GetCode(NORMAL, name);
   2953 }
   2954 
   2955 
   2956 MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name,
   2957                                                      JSObject* receiver,
   2958                                                      JSObject* holder,
   2959                                                      int index) {
   2960   // ----------- S t a t e -------------
   2961   //  -- eax    : key
   2962   //  -- edx    : receiver
   2963   //  -- esp[0] : return address
   2964   // -----------------------------------
   2965   Label miss;
   2966 
   2967   Counters* counters = isolate()->counters();
   2968   __ IncrementCounter(counters->keyed_load_field(), 1);
   2969 
   2970   // Check that the name has not changed.
   2971   __ cmp(Operand(eax), Immediate(Handle<String>(name)));
   2972   __ j(not_equal, &miss, not_taken);
   2973 
   2974   GenerateLoadField(receiver, holder, edx, ebx, ecx, edi, index, name, &miss);
   2975 
   2976   __ bind(&miss);
   2977   __ DecrementCounter(counters->keyed_load_field(), 1);
   2978   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
   2979 
   2980   // Return the generated code.
   2981   return GetCode(FIELD, name);
   2982 }
   2983 
   2984 
   2985 MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback(
   2986     String* name,
   2987     JSObject* receiver,
   2988     JSObject* holder,
   2989     AccessorInfo* callback) {
   2990   // ----------- S t a t e -------------
   2991   //  -- eax    : key
   2992   //  -- edx    : receiver
   2993   //  -- esp[0] : return address
   2994   // -----------------------------------
   2995   Label miss;
   2996 
   2997   Counters* counters = isolate()->counters();
   2998   __ IncrementCounter(counters->keyed_load_callback(), 1);
   2999 
   3000   // Check that the name has not changed.
   3001   __ cmp(Operand(eax), Immediate(Handle<String>(name)));
   3002   __ j(not_equal, &miss, not_taken);
   3003 
   3004   MaybeObject* result = GenerateLoadCallback(receiver, holder, edx, eax, ebx,
   3005                                              ecx, edi, callback, name, &miss);
   3006   if (result->IsFailure()) {
   3007     miss.Unuse();
   3008     return result;
   3009   }
   3010 
   3011   __ bind(&miss);
   3012 
   3013   __ DecrementCounter(counters->keyed_load_callback(), 1);
   3014   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
   3015 
   3016   // Return the generated code.
   3017   return GetCode(CALLBACKS, name);
   3018 }
   3019 
   3020 
   3021 MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
   3022                                                         JSObject* receiver,
   3023                                                         JSObject* holder,
   3024                                                         Object* value) {
   3025   // ----------- S t a t e -------------
   3026   //  -- eax    : key
   3027   //  -- edx    : receiver
   3028   //  -- esp[0] : return address
   3029   // -----------------------------------
   3030   Label miss;
   3031 
   3032   Counters* counters = isolate()->counters();
   3033   __ IncrementCounter(counters->keyed_load_constant_function(), 1);
   3034 
   3035   // Check that the name has not changed.
   3036   __ cmp(Operand(eax), Immediate(Handle<String>(name)));
   3037   __ j(not_equal, &miss, not_taken);
   3038 
   3039   GenerateLoadConstant(receiver, holder, edx, ebx, ecx, edi,
   3040                        value, name, &miss);
   3041   __ bind(&miss);
   3042   __ DecrementCounter(counters->keyed_load_constant_function(), 1);
   3043   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
   3044 
   3045   // Return the generated code.
   3046   return GetCode(CONSTANT_FUNCTION, name);
   3047 }
   3048 
   3049 
   3050 MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
   3051                                                            JSObject* holder,
   3052                                                            String* name) {
   3053   // ----------- S t a t e -------------
   3054   //  -- eax    : key
   3055   //  -- edx    : receiver
   3056   //  -- esp[0] : return address
   3057   // -----------------------------------
   3058   Label miss;
   3059 
   3060   Counters* counters = isolate()->counters();
   3061   __ IncrementCounter(counters->keyed_load_interceptor(), 1);
   3062 
   3063   // Check that the name has not changed.
   3064   __ cmp(Operand(eax), Immediate(Handle<String>(name)));
   3065   __ j(not_equal, &miss, not_taken);
   3066 
   3067   LookupResult lookup;
   3068   LookupPostInterceptor(holder, name, &lookup);
   3069   GenerateLoadInterceptor(receiver,
   3070                           holder,
   3071                           &lookup,
   3072                           edx,
   3073                           eax,
   3074                           ecx,
   3075                           ebx,
   3076                           edi,
   3077                           name,
   3078                           &miss);
   3079   __ bind(&miss);
   3080   __ DecrementCounter(counters->keyed_load_interceptor(), 1);
   3081   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
   3082 
   3083   // Return the generated code.
   3084   return GetCode(INTERCEPTOR, name);
   3085 }
   3086 
   3087 
   3088 MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
   3089   // ----------- S t a t e -------------
   3090   //  -- eax    : key
   3091   //  -- edx    : receiver
   3092   //  -- esp[0] : return address
   3093   // -----------------------------------
   3094   Label miss;
   3095 
   3096   Counters* counters = isolate()->counters();
   3097   __ IncrementCounter(counters->keyed_load_array_length(), 1);
   3098 
   3099   // Check that the name has not changed.
   3100   __ cmp(Operand(eax), Immediate(Handle<String>(name)));
   3101   __ j(not_equal, &miss, not_taken);
   3102 
   3103   GenerateLoadArrayLength(masm(), edx, ecx, &miss);
   3104   __ bind(&miss);
   3105   __ DecrementCounter(counters->keyed_load_array_length(), 1);
   3106   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
   3107 
   3108   // Return the generated code.
   3109   return GetCode(CALLBACKS, name);
   3110 }
   3111 
   3112 
   3113 MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
   3114   // ----------- S t a t e -------------
   3115   //  -- eax    : key
   3116   //  -- edx    : receiver
   3117   //  -- esp[0] : return address
   3118   // -----------------------------------
   3119   Label miss;
   3120 
   3121   Counters* counters = isolate()->counters();
   3122   __ IncrementCounter(counters->keyed_load_string_length(), 1);
   3123 
   3124   // Check that the name has not changed.
   3125   __ cmp(Operand(eax), Immediate(Handle<String>(name)));
   3126   __ j(not_equal, &miss, not_taken);
   3127 
   3128   GenerateLoadStringLength(masm(), edx, ecx, ebx, &miss, true);
   3129   __ bind(&miss);
   3130   __ DecrementCounter(counters->keyed_load_string_length(), 1);
   3131   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
   3132 
   3133   // Return the generated code.
   3134   return GetCode(CALLBACKS, name);
   3135 }
   3136 
   3137 
   3138 MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
   3139   // ----------- S t a t e -------------
   3140   //  -- eax    : key
   3141   //  -- edx    : receiver
   3142   //  -- esp[0] : return address
   3143   // -----------------------------------
   3144   Label miss;
   3145 
   3146   Counters* counters = isolate()->counters();
   3147   __ IncrementCounter(counters->keyed_load_function_prototype(), 1);
   3148 
   3149   // Check that the name has not changed.
   3150   __ cmp(Operand(eax), Immediate(Handle<String>(name)));
   3151   __ j(not_equal, &miss, not_taken);
   3152 
   3153   GenerateLoadFunctionPrototype(masm(), edx, ecx, ebx, &miss);
   3154   __ bind(&miss);
   3155   __ DecrementCounter(counters->keyed_load_function_prototype(), 1);
   3156   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
   3157 
   3158   // Return the generated code.
   3159   return GetCode(CALLBACKS, name);
   3160 }
   3161 
   3162 
   3163 MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) {
   3164   // ----------- S t a t e -------------
   3165   //  -- eax    : key
   3166   //  -- edx    : receiver
   3167   //  -- esp[0] : return address
   3168   // -----------------------------------
   3169   Label miss;
   3170 
   3171   // Check that the receiver isn't a smi.
   3172   __ test(edx, Immediate(kSmiTagMask));
   3173   __ j(zero, &miss, not_taken);
   3174 
   3175   // Check that the map matches.
   3176   __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
   3177          Immediate(Handle<Map>(receiver->map())));
   3178   __ j(not_equal, &miss, not_taken);
   3179 
   3180   // Check that the key is a smi.
   3181   __ test(eax, Immediate(kSmiTagMask));
   3182   __ j(not_zero, &miss, not_taken);
   3183 
   3184   // Get the elements array.
   3185   __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
   3186   __ AssertFastElements(ecx);
   3187 
   3188   // Check that the key is within bounds.
   3189   __ cmp(eax, FieldOperand(ecx, FixedArray::kLengthOffset));
   3190   __ j(above_equal, &miss, not_taken);
   3191 
   3192   // Load the result and make sure it's not the hole.
   3193   __ mov(ebx, Operand(ecx, eax, times_2,
   3194                       FixedArray::kHeaderSize - kHeapObjectTag));
   3195   __ cmp(ebx, factory()->the_hole_value());
   3196   __ j(equal, &miss, not_taken);
   3197   __ mov(eax, ebx);
   3198   __ ret(0);
   3199 
   3200   __ bind(&miss);
   3201   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
   3202 
   3203   // Return the generated code.
   3204   return GetCode(NORMAL, NULL);
   3205 }
   3206 
   3207 
   3208 // Specialized stub for constructing objects from functions which only have only
   3209 // simple assignments of the form this.x = ...; in their body.
   3210 MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
   3211   // ----------- S t a t e -------------
   3212   //  -- eax : argc
   3213   //  -- edi : constructor
   3214   //  -- esp[0] : return address
   3215   //  -- esp[4] : last argument
   3216   // -----------------------------------
   3217   Label generic_stub_call;
   3218 #ifdef ENABLE_DEBUGGER_SUPPORT
   3219   // Check to see whether there are any break points in the function code. If
   3220   // there are jump to the generic constructor stub which calls the actual
   3221   // code for the function thereby hitting the break points.
   3222   __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
   3223   __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kDebugInfoOffset));
   3224   __ cmp(ebx, factory()->undefined_value());
   3225   __ j(not_equal, &generic_stub_call, not_taken);
   3226 #endif
   3227 
   3228   // Load the initial map and verify that it is in fact a map.
   3229   __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
   3230   // Will both indicate a NULL and a Smi.
   3231   __ test(ebx, Immediate(kSmiTagMask));
   3232   __ j(zero, &generic_stub_call);
   3233   __ CmpObjectType(ebx, MAP_TYPE, ecx);
   3234   __ j(not_equal, &generic_stub_call);
   3235 
   3236 #ifdef DEBUG
   3237   // Cannot construct functions this way.
   3238   // edi: constructor
   3239   // ebx: initial map
   3240   __ CmpInstanceType(ebx, JS_FUNCTION_TYPE);
   3241   __ Assert(not_equal, "Function constructed by construct stub.");
   3242 #endif
   3243 
   3244   // Now allocate the JSObject on the heap by moving the new space allocation
   3245   // top forward.
   3246   // edi: constructor
   3247   // ebx: initial map
   3248   __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset));
   3249   __ shl(ecx, kPointerSizeLog2);
   3250   __ AllocateInNewSpace(ecx,
   3251                         edx,
   3252                         ecx,
   3253                         no_reg,
   3254                         &generic_stub_call,
   3255                         NO_ALLOCATION_FLAGS);
   3256 
   3257   // Allocated the JSObject, now initialize the fields and add the heap tag.
   3258   // ebx: initial map
   3259   // edx: JSObject (untagged)
   3260   __ mov(Operand(edx, JSObject::kMapOffset), ebx);
   3261   __ mov(ebx, factory()->empty_fixed_array());
   3262   __ mov(Operand(edx, JSObject::kPropertiesOffset), ebx);
   3263   __ mov(Operand(edx, JSObject::kElementsOffset), ebx);
   3264 
   3265   // Push the allocated object to the stack. This is the object that will be
   3266   // returned (after it is tagged).
   3267   __ push(edx);
   3268 
   3269   // eax: argc
   3270   // edx: JSObject (untagged)
   3271   // Load the address of the first in-object property into edx.
   3272   __ lea(edx, Operand(edx, JSObject::kHeaderSize));
   3273   // Calculate the location of the first argument. The stack contains the
   3274   // allocated object and the return address on top of the argc arguments.
   3275   __ lea(ecx, Operand(esp, eax, times_4, 1 * kPointerSize));
   3276 
   3277   // Use edi for holding undefined which is used in several places below.
   3278   __ mov(edi, factory()->undefined_value());
   3279 
   3280   // eax: argc
   3281   // ecx: first argument
   3282   // edx: first in-object property of the JSObject
   3283   // edi: undefined
   3284   // Fill the initialized properties with a constant value or a passed argument
   3285   // depending on the this.x = ...; assignment in the function.
   3286   SharedFunctionInfo* shared = function->shared();
   3287   for (int i = 0; i < shared->this_property_assignments_count(); i++) {
   3288     if (shared->IsThisPropertyAssignmentArgument(i)) {
   3289       // Check if the argument assigned to the property is actually passed.
   3290       // If argument is not passed the property is set to undefined,
   3291       // otherwise find it on the stack.
   3292       int arg_number = shared->GetThisPropertyAssignmentArgument(i);
   3293       __ mov(ebx, edi);
   3294       __ cmp(eax, arg_number);
   3295       if (CpuFeatures::IsSupported(CMOV)) {
   3296         CpuFeatures::Scope use_cmov(CMOV);
   3297         __ cmov(above, ebx, Operand(ecx, arg_number * -kPointerSize));
   3298       } else {
   3299         Label not_passed;
   3300         __ j(below_equal, &not_passed);
   3301         __ mov(ebx, Operand(ecx, arg_number * -kPointerSize));
   3302         __ bind(&not_passed);
   3303       }
   3304       // Store value in the property.
   3305       __ mov(Operand(edx, i * kPointerSize), ebx);
   3306     } else {
   3307       // Set the property to the constant value.
   3308       Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
   3309       __ mov(Operand(edx, i * kPointerSize), Immediate(constant));
   3310     }
   3311   }
   3312 
   3313   // Fill the unused in-object property fields with undefined.
   3314   ASSERT(function->has_initial_map());
   3315   for (int i = shared->this_property_assignments_count();
   3316        i < function->initial_map()->inobject_properties();
   3317        i++) {
   3318     __ mov(Operand(edx, i * kPointerSize), edi);
   3319   }
   3320 
   3321   // Move argc to ebx and retrieve and tag the JSObject to return.
   3322   __ mov(ebx, eax);
   3323   __ pop(eax);
   3324   __ or_(Operand(eax), Immediate(kHeapObjectTag));
   3325 
   3326   // Remove caller arguments and receiver from the stack and return.
   3327   __ pop(ecx);
   3328   __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize));
   3329   __ push(ecx);
   3330   Counters* counters = isolate()->counters();
   3331   __ IncrementCounter(counters->constructed_objects(), 1);
   3332   __ IncrementCounter(counters->constructed_objects_stub(), 1);
   3333   __ ret(0);
   3334 
   3335   // Jump to the generic stub in case the specialized code cannot handle the
   3336   // construction.
   3337   __ bind(&generic_stub_call);
   3338   Handle<Code> generic_construct_stub =
   3339       isolate()->builtins()->JSConstructStubGeneric();
   3340   __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET);
   3341 
   3342   // Return the generated code.
   3343   return GetCode();
   3344 }
   3345 
   3346 
   3347 MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
   3348     JSObject*receiver, ExternalArrayType array_type, Code::Flags flags) {
   3349   // ----------- S t a t e -------------
   3350   //  -- eax    : key
   3351   //  -- edx    : receiver
   3352   //  -- esp[0] : return address
   3353   // -----------------------------------
   3354   Label slow, failed_allocation;
   3355 
   3356   // Check that the object isn't a smi.
   3357   __ test(edx, Immediate(kSmiTagMask));
   3358   __ j(zero, &slow, not_taken);
   3359 
   3360   // Check that the key is a smi.
   3361   __ test(eax, Immediate(kSmiTagMask));
   3362   __ j(not_zero, &slow, not_taken);
   3363 
   3364   // Check that the map matches.
   3365   __ CheckMap(edx, Handle<Map>(receiver->map()), &slow, false);
   3366   __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
   3367 
   3368   // eax: key, known to be a smi.
   3369   // edx: receiver, known to be a JSObject.
   3370   // ebx: elements object, known to be an external array.
   3371   // Check that the index is in range.
   3372   __ mov(ecx, eax);
   3373   __ SmiUntag(ecx);  // Untag the index.
   3374   __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset));
   3375   // Unsigned comparison catches both negative and too-large values.
   3376   __ j(above_equal, &slow);
   3377   __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset));
   3378   // ebx: base pointer of external storage
   3379   switch (array_type) {
   3380     case kExternalByteArray:
   3381       __ movsx_b(eax, Operand(ebx, ecx, times_1, 0));
   3382       break;
   3383     case kExternalUnsignedByteArray:
   3384     case kExternalPixelArray:
   3385       __ movzx_b(eax, Operand(ebx, ecx, times_1, 0));
   3386       break;
   3387     case kExternalShortArray:
   3388       __ movsx_w(eax, Operand(ebx, ecx, times_2, 0));
   3389       break;
   3390     case kExternalUnsignedShortArray:
   3391       __ movzx_w(eax, Operand(ebx, ecx, times_2, 0));
   3392       break;
   3393     case kExternalIntArray:
   3394     case kExternalUnsignedIntArray:
   3395       __ mov(ecx, Operand(ebx, ecx, times_4, 0));
   3396       break;
   3397     case kExternalFloatArray:
   3398       __ fld_s(Operand(ebx, ecx, times_4, 0));
   3399       break;
   3400     default:
   3401       UNREACHABLE();
   3402       break;
   3403   }
   3404 
   3405   // For integer array types:
   3406   // ecx: value
   3407   // For floating-point array type:
   3408   // FP(0): value
   3409 
   3410   if (array_type == kExternalIntArray ||
   3411       array_type == kExternalUnsignedIntArray) {
   3412     // For the Int and UnsignedInt array types, we need to see whether
   3413     // the value can be represented in a Smi. If not, we need to convert
   3414     // it to a HeapNumber.
   3415     Label box_int;
   3416     if (array_type == kExternalIntArray) {
   3417       __ cmp(ecx, 0xC0000000);
   3418       __ j(sign, &box_int);
   3419     } else {
   3420       ASSERT_EQ(array_type, kExternalUnsignedIntArray);
   3421       // The test is different for unsigned int values. Since we need
   3422       // the value to be in the range of a positive smi, we can't
   3423       // handle either of the top two bits being set in the value.
   3424       __ test(ecx, Immediate(0xC0000000));
   3425       __ j(not_zero, &box_int);
   3426     }
   3427 
   3428     __ mov(eax, ecx);
   3429     __ SmiTag(eax);
   3430     __ ret(0);
   3431 
   3432     __ bind(&box_int);
   3433 
   3434     // Allocate a HeapNumber for the int and perform int-to-double
   3435     // conversion.
   3436     if (array_type == kExternalIntArray) {
   3437       __ push(ecx);
   3438       __ fild_s(Operand(esp, 0));
   3439       __ pop(ecx);
   3440     } else {
   3441       ASSERT(array_type == kExternalUnsignedIntArray);
   3442       // Need to zero-extend the value.
   3443       // There's no fild variant for unsigned values, so zero-extend
   3444       // to a 64-bit int manually.
   3445       __ push(Immediate(0));
   3446       __ push(ecx);
   3447       __ fild_d(Operand(esp, 0));
   3448       __ pop(ecx);
   3449       __ pop(ecx);
   3450     }
   3451     // FP(0): value
   3452     __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation);
   3453     // Set the value.
   3454     __ mov(eax, ecx);
   3455     __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
   3456     __ ret(0);
   3457   } else if (array_type == kExternalFloatArray) {
   3458     // For the floating-point array type, we need to always allocate a
   3459     // HeapNumber.
   3460     __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation);
   3461     // Set the value.
   3462     __ mov(eax, ecx);
   3463     __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
   3464     __ ret(0);
   3465   } else {
   3466     __ SmiTag(eax);
   3467     __ ret(0);
   3468   }
   3469 
   3470   // If we fail allocation of the HeapNumber, we still have a value on
   3471   // top of the FPU stack. Remove it.
   3472   __ bind(&failed_allocation);
   3473   __ ffree();
   3474   __ fincstp();
   3475   // Fall through to slow case.
   3476 
   3477   // Slow case: Jump to runtime.
   3478   __ bind(&slow);
   3479   Counters* counters = isolate()->counters();
   3480   __ IncrementCounter(counters->keyed_load_external_array_slow(), 1);
   3481   // ----------- S t a t e -------------
   3482   //  -- eax    : key
   3483   //  -- edx    : receiver
   3484   //  -- esp[0] : return address
   3485   // -----------------------------------
   3486 
   3487   __ pop(ebx);
   3488   __ push(edx);  // receiver
   3489   __ push(eax);  // name
   3490   __ push(ebx);  // return address
   3491 
   3492   // Perform tail call to the entry.
   3493   __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
   3494 
   3495   // Return the generated code.
   3496   return GetCode(flags);
   3497 }
   3498 
   3499 
   3500 MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
   3501     JSObject* receiver, ExternalArrayType array_type, Code::Flags flags) {
   3502   // ----------- S t a t e -------------
   3503   //  -- eax    : value
   3504   //  -- ecx    : key
   3505   //  -- edx    : receiver
   3506   //  -- esp[0] : return address
   3507   // -----------------------------------
   3508   Label slow, check_heap_number;
   3509 
   3510   // Check that the object isn't a smi.
   3511   __ test(edx, Immediate(kSmiTagMask));
   3512   __ j(zero, &slow);
   3513 
   3514   // Check that the map matches.
   3515   __ CheckMap(edx, Handle<Map>(receiver->map()), &slow, false);
   3516 
   3517   // Check that the key is a smi.
   3518   __ test(ecx, Immediate(kSmiTagMask));
   3519   __ j(not_zero, &slow);
   3520 
   3521   // Check that the index is in range.
   3522   __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
   3523   __ mov(ebx, ecx);
   3524   __ SmiUntag(ebx);
   3525   __ cmp(ebx, FieldOperand(edi, ExternalArray::kLengthOffset));
   3526   // Unsigned comparison catches both negative and too-large values.
   3527   __ j(above_equal, &slow);
   3528 
   3529   // Handle both smis and HeapNumbers in the fast path. Go to the
   3530   // runtime for all other kinds of values.
   3531   // eax: value
   3532   // edx: receiver
   3533   // ecx: key
   3534   // edi: elements array
   3535   // ebx: untagged index
   3536   __ test(eax, Immediate(kSmiTagMask));
   3537   if (array_type == kExternalPixelArray)
   3538     __ j(not_equal, &slow);
   3539   else
   3540     __ j(not_equal, &check_heap_number);
   3541 
   3542   // smi case
   3543   __ mov(ecx, eax);  // Preserve the value in eax.  Key is no longer needed.
   3544   __ SmiUntag(ecx);
   3545   __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
   3546   // ecx: base pointer of external storage
   3547   switch (array_type) {
   3548     case kExternalPixelArray:
   3549       {  // Clamp the value to [0..255].
   3550         NearLabel done;
   3551         __ test(ecx, Immediate(0xFFFFFF00));
   3552         __ j(zero, &done);
   3553         __ setcc(negative, ecx);  // 1 if negative, 0 if positive.
   3554         __ dec_b(ecx);  // 0 if negative, 255 if positive.
   3555         __ bind(&done);
   3556       }
   3557       __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
   3558       break;
   3559     case kExternalByteArray:
   3560     case kExternalUnsignedByteArray:
   3561       __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
   3562       break;
   3563     case kExternalShortArray:
   3564     case kExternalUnsignedShortArray:
   3565       __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
   3566       break;
   3567     case kExternalIntArray:
   3568     case kExternalUnsignedIntArray:
   3569       __ mov(Operand(edi, ebx, times_4, 0), ecx);
   3570       break;
   3571     case kExternalFloatArray:
   3572       // Need to perform int-to-float conversion.
   3573       __ push(ecx);
   3574       __ fild_s(Operand(esp, 0));
   3575       __ pop(ecx);
   3576       __ fstp_s(Operand(edi, ebx, times_4, 0));
   3577       break;
   3578     default:
   3579       UNREACHABLE();
   3580       break;
   3581   }
   3582   __ ret(0);  // Return the original value.
   3583 
   3584   // TODO(danno): handle heap number -> pixel array conversion
   3585   if (array_type != kExternalPixelArray) {
   3586     __ bind(&check_heap_number);
   3587     // eax: value
   3588     // edx: receiver
   3589     // ecx: key
   3590     // edi: elements array
   3591     // ebx: untagged index
   3592     __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
   3593            Immediate(factory()->heap_number_map()));
   3594     __ j(not_equal, &slow);
   3595 
   3596     // The WebGL specification leaves the behavior of storing NaN and
   3597     // +/-Infinity into integer arrays basically undefined. For more
   3598     // reproducible behavior, convert these to zero.
   3599     __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
   3600     // ebx: untagged index
   3601     // edi: base pointer of external storage
   3602     if (array_type == kExternalFloatArray) {
   3603       __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
   3604       __ fstp_s(Operand(edi, ebx, times_4, 0));
   3605       __ ret(0);
   3606     } else {
   3607       // Perform float-to-int conversion with truncation (round-to-zero)
   3608       // behavior.
   3609 
   3610       // For the moment we make the slow call to the runtime on
   3611       // processors that don't support SSE2. The code in IntegerConvert
   3612       // (code-stubs-ia32.cc) is roughly what is needed here though the
   3613       // conversion failure case does not need to be handled.
   3614       if (CpuFeatures::IsSupported(SSE2)) {
   3615         if (array_type != kExternalIntArray &&
   3616             array_type != kExternalUnsignedIntArray) {
   3617           ASSERT(CpuFeatures::IsSupported(SSE2));
   3618           CpuFeatures::Scope scope(SSE2);
   3619           __ cvttsd2si(ecx, FieldOperand(eax, HeapNumber::kValueOffset));
   3620           // ecx: untagged integer value
   3621           switch (array_type) {
   3622             case kExternalPixelArray:
   3623               {  // Clamp the value to [0..255].
   3624                 NearLabel done;
   3625                 __ test(ecx, Immediate(0xFFFFFF00));
   3626                 __ j(zero, &done);
   3627                 __ setcc(negative, ecx);  // 1 if negative, 0 if positive.
   3628                 __ dec_b(ecx);  // 0 if negative, 255 if positive.
   3629                 __ bind(&done);
   3630               }
   3631               __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
   3632               break;
   3633             case kExternalByteArray:
   3634             case kExternalUnsignedByteArray:
   3635               __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
   3636               break;
   3637             case kExternalShortArray:
   3638             case kExternalUnsignedShortArray:
   3639               __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
   3640               break;
   3641             default:
   3642               UNREACHABLE();
   3643               break;
   3644           }
   3645         } else {
   3646           if (CpuFeatures::IsSupported(SSE3)) {
   3647             CpuFeatures::Scope scope(SSE3);
   3648             // fisttp stores values as signed integers. To represent the
   3649             // entire range of int and unsigned int arrays, store as a
   3650             // 64-bit int and discard the high 32 bits.
   3651             // If the value is NaN or +/-infinity, the result is 0x80000000,
   3652             // which is automatically zero when taken mod 2^n, n < 32.
   3653             __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
   3654             __ sub(Operand(esp), Immediate(2 * kPointerSize));
   3655             __ fisttp_d(Operand(esp, 0));
   3656             __ pop(ecx);
   3657             __ add(Operand(esp), Immediate(kPointerSize));
   3658           } else {
   3659             ASSERT(CpuFeatures::IsSupported(SSE2));
   3660             CpuFeatures::Scope scope(SSE2);
   3661             // We can easily implement the correct rounding behavior for the
   3662             // range [0, 2^31-1]. For the time being, to keep this code simple,
   3663             // make the slow runtime call for values outside this range.
   3664             // Note: we could do better for signed int arrays.
   3665             __ movd(xmm0, FieldOperand(eax, HeapNumber::kValueOffset));
   3666             // We will need the key if we have to make the slow runtime call.
   3667             __ push(ecx);
   3668             __ LoadPowerOf2(xmm1, ecx, 31);
   3669             __ pop(ecx);
   3670             __ ucomisd(xmm1, xmm0);
   3671             __ j(above_equal, &slow);
   3672             __ cvttsd2si(ecx, Operand(xmm0));
   3673           }
   3674           // ecx: untagged integer value
   3675           __ mov(Operand(edi, ebx, times_4, 0), ecx);
   3676         }
   3677         __ ret(0);  // Return original value.
   3678       }
   3679     }
   3680   }
   3681 
   3682   // Slow case: call runtime.
   3683   __ bind(&slow);
   3684   // ----------- S t a t e -------------
   3685   //  -- eax    : value
   3686   //  -- ecx    : key
   3687   //  -- edx    : receiver
   3688   //  -- esp[0] : return address
   3689   // -----------------------------------
   3690 
   3691   __ pop(ebx);
   3692   __ push(edx);
   3693   __ push(ecx);
   3694   __ push(eax);
   3695   __ push(Immediate(Smi::FromInt(NONE)));   // PropertyAttributes
   3696   __ push(Immediate(Smi::FromInt(
   3697       Code::ExtractExtraICStateFromFlags(flags) & kStrictMode)));
   3698   __ push(ebx);   // return address
   3699 
   3700   // Do tail-call to runtime routine.
   3701   __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
   3702 
   3703   return GetCode(flags);
   3704 }
   3705 
   3706 
   3707 #undef __
   3708 
   3709 } }  // namespace v8::internal
   3710 
   3711 #endif  // V8_TARGET_ARCH_IA32
   3712