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