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