builtins-x64.cc revision 402d937239b0e2fd11bf2f4fe972ad78aa9fd481
1// Copyright 2009 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#include "codegen-inl.h"
30#include "macro-assembler.h"
31
32namespace v8 {
33namespace internal {
34
35#define __ ACCESS_MASM(masm)
36
37
38void Builtins::Generate_Adaptor(MacroAssembler* masm,
39                                CFunctionId id,
40                                BuiltinExtraArguments extra_args) {
41  // ----------- S t a t e -------------
42  //  -- rax                : number of arguments excluding receiver
43  //  -- rdi                : called function (only guaranteed when
44  //                          extra_args requires it)
45  //  -- rsi                : context
46  //  -- rsp[0]             : return address
47  //  -- rsp[8]             : last argument
48  //  -- ...
49  //  -- rsp[8 * argc]      : first argument (argc == rax)
50  //  -- rsp[8 * (argc +1)] : receiver
51  // -----------------------------------
52
53  // Insert extra arguments.
54  int num_extra_args = 0;
55  if (extra_args == NEEDS_CALLED_FUNCTION) {
56    num_extra_args = 1;
57    __ pop(kScratchRegister);  // Save return address.
58    __ push(rdi);
59    __ push(kScratchRegister);  // Restore return address.
60  } else {
61    ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
62  }
63
64  // JumpToRuntime expects rax to contain the number of arguments
65  // including the receiver and the extra arguments.
66  __ addq(rax, Immediate(num_extra_args + 1));
67  __ JumpToRuntime(ExternalReference(id), 1);
68}
69
70
71static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
72  __ push(rbp);
73  __ movq(rbp, rsp);
74
75  // Store the arguments adaptor context sentinel.
76  __ Push(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
77
78  // Push the function on the stack.
79  __ push(rdi);
80
81  // Preserve the number of arguments on the stack. Must preserve both
82  // rax and rbx because these registers are used when copying the
83  // arguments and the receiver.
84  __ Integer32ToSmi(rcx, rax);
85  __ push(rcx);
86}
87
88
89static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
90  // Retrieve the number of arguments from the stack. Number is a Smi.
91  __ movq(rbx, Operand(rbp, ArgumentsAdaptorFrameConstants::kLengthOffset));
92
93  // Leave the frame.
94  __ movq(rsp, rbp);
95  __ pop(rbp);
96
97  // Remove caller arguments from the stack.
98  __ pop(rcx);
99  SmiIndex index = masm->SmiToIndex(rbx, rbx, kPointerSizeLog2);
100  __ lea(rsp, Operand(rsp, index.reg, index.scale, 1 * kPointerSize));
101  __ push(rcx);
102}
103
104
105void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
106  // ----------- S t a t e -------------
107  //  -- rax : actual number of arguments
108  //  -- rbx : expected number of arguments
109  //  -- rdx : code entry to call
110  // -----------------------------------
111
112  Label invoke, dont_adapt_arguments;
113  __ IncrementCounter(&Counters::arguments_adaptors, 1);
114
115  Label enough, too_few;
116  __ cmpq(rax, rbx);
117  __ j(less, &too_few);
118  __ cmpq(rbx, Immediate(SharedFunctionInfo::kDontAdaptArgumentsSentinel));
119  __ j(equal, &dont_adapt_arguments);
120
121  {  // Enough parameters: Actual >= expected.
122    __ bind(&enough);
123    EnterArgumentsAdaptorFrame(masm);
124
125    // Copy receiver and all expected arguments.
126    const int offset = StandardFrameConstants::kCallerSPOffset;
127    __ lea(rax, Operand(rbp, rax, times_pointer_size, offset));
128    __ movq(rcx, Immediate(-1));  // account for receiver
129
130    Label copy;
131    __ bind(&copy);
132    __ incq(rcx);
133    __ push(Operand(rax, 0));
134    __ subq(rax, Immediate(kPointerSize));
135    __ cmpq(rcx, rbx);
136    __ j(less, &copy);
137    __ jmp(&invoke);
138  }
139
140  {  // Too few parameters: Actual < expected.
141    __ bind(&too_few);
142    EnterArgumentsAdaptorFrame(masm);
143
144    // Copy receiver and all actual arguments.
145    const int offset = StandardFrameConstants::kCallerSPOffset;
146    __ lea(rdi, Operand(rbp, rax, times_pointer_size, offset));
147    __ movq(rcx, Immediate(-1));  // account for receiver
148
149    Label copy;
150    __ bind(&copy);
151    __ incq(rcx);
152    __ push(Operand(rdi, 0));
153    __ subq(rdi, Immediate(kPointerSize));
154    __ cmpq(rcx, rax);
155    __ j(less, &copy);
156
157    // Fill remaining expected arguments with undefined values.
158    Label fill;
159    __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
160    __ bind(&fill);
161    __ incq(rcx);
162    __ push(kScratchRegister);
163    __ cmpq(rcx, rbx);
164    __ j(less, &fill);
165
166    // Restore function pointer.
167    __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
168  }
169
170  // Call the entry point.
171  __ bind(&invoke);
172  __ call(rdx);
173
174  // Leave frame and return.
175  LeaveArgumentsAdaptorFrame(masm);
176  __ ret(0);
177
178  // -------------------------------------------
179  // Dont adapt arguments.
180  // -------------------------------------------
181  __ bind(&dont_adapt_arguments);
182  __ jmp(rdx);
183}
184
185
186void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
187  // Stack Layout:
188  // rsp[0]:   Return address
189  // rsp[1]:   Argument n
190  // rsp[2]:   Argument n-1
191  //  ...
192  // rsp[n]:   Argument 1
193  // rsp[n+1]: Receiver (function to call)
194  //
195  // rax contains the number of arguments, n, not counting the receiver.
196  //
197  // 1. Make sure we have at least one argument.
198  { Label done;
199    __ testq(rax, rax);
200    __ j(not_zero, &done);
201    __ pop(rbx);
202    __ Push(Factory::undefined_value());
203    __ push(rbx);
204    __ incq(rax);
205    __ bind(&done);
206  }
207
208  // 2. Get the function to call (passed as receiver) from the stack, check
209  //    if it is a function.
210  Label non_function;
211  // The function to call is at position n+1 on the stack.
212  __ movq(rdi, Operand(rsp, rax, times_pointer_size, 1 * kPointerSize));
213  __ JumpIfSmi(rdi, &non_function);
214  __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
215  __ j(not_equal, &non_function);
216
217  // 3a. Patch the first argument if necessary when calling a function.
218  Label shift_arguments;
219  { Label convert_to_object, use_global_receiver, patch_receiver;
220    // Change context eagerly in case we need the global receiver.
221    __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
222
223    __ movq(rbx, Operand(rsp, rax, times_pointer_size, 0));
224    __ JumpIfSmi(rbx, &convert_to_object);
225
226    __ CompareRoot(rbx, Heap::kNullValueRootIndex);
227    __ j(equal, &use_global_receiver);
228    __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
229    __ j(equal, &use_global_receiver);
230
231    __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, rcx);
232    __ j(below, &convert_to_object);
233    __ CmpInstanceType(rcx, LAST_JS_OBJECT_TYPE);
234    __ j(below_equal, &shift_arguments);
235
236    __ bind(&convert_to_object);
237    __ EnterInternalFrame();  // In order to preserve argument count.
238    __ Integer32ToSmi(rax, rax);
239    __ push(rax);
240
241    __ push(rbx);
242    __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
243    __ movq(rbx, rax);
244
245    __ pop(rax);
246    __ SmiToInteger32(rax, rax);
247    __ LeaveInternalFrame();
248    // Restore the function to rdi.
249    __ movq(rdi, Operand(rsp, rax, times_pointer_size, 1 * kPointerSize));
250    __ jmp(&patch_receiver);
251
252    // Use the global receiver object from the called function as the
253    // receiver.
254    __ bind(&use_global_receiver);
255    const int kGlobalIndex =
256        Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
257    __ movq(rbx, FieldOperand(rsi, kGlobalIndex));
258    __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalContextOffset));
259    __ movq(rbx, FieldOperand(rbx, kGlobalIndex));
260    __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
261
262    __ bind(&patch_receiver);
263    __ movq(Operand(rsp, rax, times_pointer_size, 0), rbx);
264
265    __ jmp(&shift_arguments);
266  }
267
268
269  // 3b. Patch the first argument when calling a non-function.  The
270  //     CALL_NON_FUNCTION builtin expects the non-function callee as
271  //     receiver, so overwrite the first argument which will ultimately
272  //     become the receiver.
273  __ bind(&non_function);
274  __ movq(Operand(rsp, rax, times_pointer_size, 0), rdi);
275  __ xor_(rdi, rdi);
276
277  // 4. Shift arguments and return address one slot down on the stack
278  //    (overwriting the original receiver).  Adjust argument count to make
279  //    the original first argument the new receiver.
280  __ bind(&shift_arguments);
281  { Label loop;
282    __ movq(rcx, rax);
283    __ bind(&loop);
284    __ movq(rbx, Operand(rsp, rcx, times_pointer_size, 0));
285    __ movq(Operand(rsp, rcx, times_pointer_size, 1 * kPointerSize), rbx);
286    __ decq(rcx);
287    __ j(not_sign, &loop);  // While non-negative (to copy return address).
288    __ pop(rbx);  // Discard copy of return address.
289    __ decq(rax);  // One fewer argument (first argument is new receiver).
290  }
291
292  // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin.
293  { Label function;
294    __ testq(rdi, rdi);
295    __ j(not_zero, &function);
296    __ xor_(rbx, rbx);
297    __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
298    __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
299            RelocInfo::CODE_TARGET);
300    __ bind(&function);
301  }
302
303  // 5b. Get the code to call from the function and check that the number of
304  //     expected arguments matches what we're providing.  If so, jump
305  //     (tail-call) to the code in register edx without checking arguments.
306  __ movq(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
307  __ movsxlq(rbx,
308         FieldOperand(rdx, SharedFunctionInfo::kFormalParameterCountOffset));
309  __ movq(rdx, FieldOperand(rdx, SharedFunctionInfo::kCodeOffset));
310  __ lea(rdx, FieldOperand(rdx, Code::kHeaderSize));
311  __ cmpq(rax, rbx);
312  __ j(not_equal,
313       Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
314       RelocInfo::CODE_TARGET);
315
316  ParameterCount expected(0);
317  __ InvokeCode(rdx, expected, expected, JUMP_FUNCTION);
318}
319
320
321void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
322  // Stack at entry:
323  //    rsp: return address
324  //  rsp+8: arguments
325  // rsp+16: receiver ("this")
326  // rsp+24: function
327  __ EnterInternalFrame();
328  // Stack frame:
329  //    rbp: Old base pointer
330  // rbp[1]: return address
331  // rbp[2]: function arguments
332  // rbp[3]: receiver
333  // rbp[4]: function
334  static const int kArgumentsOffset = 2 * kPointerSize;
335  static const int kReceiverOffset = 3 * kPointerSize;
336  static const int kFunctionOffset = 4 * kPointerSize;
337  __ push(Operand(rbp, kFunctionOffset));
338  __ push(Operand(rbp, kArgumentsOffset));
339  __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
340
341  // Check the stack for overflow. We are not trying need to catch
342  // interruptions (e.g. debug break and preemption) here, so the "real stack
343  // limit" is checked.
344  Label okay;
345  __ LoadRoot(kScratchRegister, Heap::kRealStackLimitRootIndex);
346  __ movq(rcx, rsp);
347  // Make rcx the space we have left. The stack might already be overflowed
348  // here which will cause rcx to become negative.
349  __ subq(rcx, kScratchRegister);
350  // Make rdx the space we need for the array when it is unrolled onto the
351  // stack.
352  __ PositiveSmiTimesPowerOfTwoToInteger64(rdx, rax, kPointerSizeLog2);
353  // Check if the arguments will overflow the stack.
354  __ cmpq(rcx, rdx);
355  __ j(greater, &okay);  // Signed comparison.
356
357  // Out of stack space.
358  __ push(Operand(rbp, kFunctionOffset));
359  __ push(rax);
360  __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION);
361  __ bind(&okay);
362  // End of stack check.
363
364  // Push current index and limit.
365  const int kLimitOffset =
366      StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
367  const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
368  __ push(rax);  // limit
369  __ push(Immediate(0));  // index
370
371  // Change context eagerly to get the right global object if
372  // necessary.
373  __ movq(rdi, Operand(rbp, kFunctionOffset));
374  __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
375
376  // Compute the receiver.
377  Label call_to_object, use_global_receiver, push_receiver;
378  __ movq(rbx, Operand(rbp, kReceiverOffset));
379  __ JumpIfSmi(rbx, &call_to_object);
380  __ CompareRoot(rbx, Heap::kNullValueRootIndex);
381  __ j(equal, &use_global_receiver);
382  __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
383  __ j(equal, &use_global_receiver);
384
385  // If given receiver is already a JavaScript object then there's no
386  // reason for converting it.
387  __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, rcx);
388  __ j(below, &call_to_object);
389  __ CmpInstanceType(rcx, LAST_JS_OBJECT_TYPE);
390  __ j(below_equal, &push_receiver);
391
392  // Convert the receiver to an object.
393  __ bind(&call_to_object);
394  __ push(rbx);
395  __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
396  __ movq(rbx, rax);
397  __ jmp(&push_receiver);
398
399  // Use the current global receiver object as the receiver.
400  __ bind(&use_global_receiver);
401  const int kGlobalOffset =
402      Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
403  __ movq(rbx, FieldOperand(rsi, kGlobalOffset));
404  __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalContextOffset));
405  __ movq(rbx, FieldOperand(rbx, kGlobalOffset));
406  __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
407
408  // Push the receiver.
409  __ bind(&push_receiver);
410  __ push(rbx);
411
412  // Copy all arguments from the array to the stack.
413  Label entry, loop;
414  __ movq(rax, Operand(rbp, kIndexOffset));
415  __ jmp(&entry);
416  __ bind(&loop);
417  __ movq(rcx, Operand(rbp, kArgumentsOffset));  // load arguments
418  __ push(rcx);
419  __ push(rax);
420
421  // Use inline caching to speed up access to arguments.
422  Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
423  __ Call(ic, RelocInfo::CODE_TARGET);
424  // It is important that we do not have a test instruction after the
425  // call.  A test instruction after the call is used to indicate that
426  // we have generated an inline version of the keyed load.  In this
427  // case, we know that we are not generating a test instruction next.
428
429  // Remove IC arguments from the stack and push the nth argument.
430  __ addq(rsp, Immediate(2 * kPointerSize));
431  __ push(rax);
432
433  // Update the index on the stack and in register rax.
434  __ movq(rax, Operand(rbp, kIndexOffset));
435  __ SmiAddConstant(rax, rax, Smi::FromInt(1));
436  __ movq(Operand(rbp, kIndexOffset), rax);
437
438  __ bind(&entry);
439  __ cmpq(rax, Operand(rbp, kLimitOffset));
440  __ j(not_equal, &loop);
441
442  // Invoke the function.
443  ParameterCount actual(rax);
444  __ SmiToInteger32(rax, rax);
445  __ movq(rdi, Operand(rbp, kFunctionOffset));
446  __ InvokeFunction(rdi, actual, CALL_FUNCTION);
447
448  __ LeaveInternalFrame();
449  __ ret(3 * kPointerSize);  // remove function, receiver, and arguments
450}
451
452
453// Load the built-in Array function from the current context.
454static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) {
455  // Load the global context.
456  __ movq(result, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
457  __ movq(result, FieldOperand(result, GlobalObject::kGlobalContextOffset));
458  // Load the Array function from the global context.
459  __ movq(result,
460          Operand(result, Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
461}
462
463
464// Number of empty elements to allocate for an empty array.
465static const int kPreallocatedArrayElements = 4;
466
467
468// Allocate an empty JSArray. The allocated array is put into the result
469// register. If the parameter initial_capacity is larger than zero an elements
470// backing store is allocated with this size and filled with the hole values.
471// Otherwise the elements backing store is set to the empty FixedArray.
472static void AllocateEmptyJSArray(MacroAssembler* masm,
473                                 Register array_function,
474                                 Register result,
475                                 Register scratch1,
476                                 Register scratch2,
477                                 Register scratch3,
478                                 int initial_capacity,
479                                 Label* gc_required) {
480  ASSERT(initial_capacity >= 0);
481
482  // Load the initial map from the array function.
483  __ movq(scratch1, FieldOperand(array_function,
484                                 JSFunction::kPrototypeOrInitialMapOffset));
485
486  // Allocate the JSArray object together with space for a fixed array with the
487  // requested elements.
488  int size = JSArray::kSize;
489  if (initial_capacity > 0) {
490    size += FixedArray::SizeFor(initial_capacity);
491  }
492  __ AllocateInNewSpace(size,
493                        result,
494                        scratch2,
495                        scratch3,
496                        gc_required,
497                        TAG_OBJECT);
498
499  // Allocated the JSArray. Now initialize the fields except for the elements
500  // array.
501  // result: JSObject
502  // scratch1: initial map
503  // scratch2: start of next object
504  __ movq(FieldOperand(result, JSObject::kMapOffset), scratch1);
505  __ Move(FieldOperand(result, JSArray::kPropertiesOffset),
506          Factory::empty_fixed_array());
507  // Field JSArray::kElementsOffset is initialized later.
508  __ Move(FieldOperand(result, JSArray::kLengthOffset), Smi::FromInt(0));
509
510  // If no storage is requested for the elements array just set the empty
511  // fixed array.
512  if (initial_capacity == 0) {
513    __ Move(FieldOperand(result, JSArray::kElementsOffset),
514            Factory::empty_fixed_array());
515    return;
516  }
517
518  // Calculate the location of the elements array and set elements array member
519  // of the JSArray.
520  // result: JSObject
521  // scratch2: start of next object
522  __ lea(scratch1, Operand(result, JSArray::kSize));
523  __ movq(FieldOperand(result, JSArray::kElementsOffset), scratch1);
524
525  // Initialize the FixedArray and fill it with holes. FixedArray length is not
526  // stored as a smi.
527  // result: JSObject
528  // scratch1: elements array
529  // scratch2: start of next object
530  __ Move(FieldOperand(scratch1, JSObject::kMapOffset),
531          Factory::fixed_array_map());
532  __ movq(FieldOperand(scratch1, Array::kLengthOffset),
533          Immediate(initial_capacity));
534
535  // Fill the FixedArray with the hole value. Inline the code if short.
536  // Reconsider loop unfolding if kPreallocatedArrayElements gets changed.
537  static const int kLoopUnfoldLimit = 4;
538  ASSERT(kPreallocatedArrayElements <= kLoopUnfoldLimit);
539  __ Move(scratch3, Factory::the_hole_value());
540  if (initial_capacity <= kLoopUnfoldLimit) {
541    // Use a scratch register here to have only one reloc info when unfolding
542    // the loop.
543    for (int i = 0; i < initial_capacity; i++) {
544      __ movq(FieldOperand(scratch1,
545                           FixedArray::kHeaderSize + i * kPointerSize),
546              scratch3);
547    }
548  } else {
549    Label loop, entry;
550    __ jmp(&entry);
551    __ bind(&loop);
552    __ movq(Operand(scratch1, 0), scratch3);
553    __ addq(scratch1, Immediate(kPointerSize));
554    __ bind(&entry);
555    __ cmpq(scratch1, scratch2);
556    __ j(below, &loop);
557  }
558}
559
560
561// Allocate a JSArray with the number of elements stored in a register. The
562// register array_function holds the built-in Array function and the register
563// array_size holds the size of the array as a smi. The allocated array is put
564// into the result register and beginning and end of the FixedArray elements
565// storage is put into registers elements_array and elements_array_end  (see
566// below for when that is not the case). If the parameter fill_with_holes is
567// true the allocated elements backing store is filled with the hole values
568// otherwise it is left uninitialized. When the backing store is filled the
569// register elements_array is scratched.
570static void AllocateJSArray(MacroAssembler* masm,
571                            Register array_function,  // Array function.
572                            Register array_size,  // As a smi.
573                            Register result,
574                            Register elements_array,
575                            Register elements_array_end,
576                            Register scratch,
577                            bool fill_with_hole,
578                            Label* gc_required) {
579  Label not_empty, allocated;
580
581  // Load the initial map from the array function.
582  __ movq(elements_array,
583          FieldOperand(array_function,
584                       JSFunction::kPrototypeOrInitialMapOffset));
585
586  // Check whether an empty sized array is requested.
587  __ SmiToInteger64(array_size, array_size);
588  __ testq(array_size, array_size);
589  __ j(not_zero, &not_empty);
590
591  // If an empty array is requested allocate a small elements array anyway. This
592  // keeps the code below free of special casing for the empty array.
593  int size = JSArray::kSize + FixedArray::SizeFor(kPreallocatedArrayElements);
594  __ AllocateInNewSpace(size,
595                        result,
596                        elements_array_end,
597                        scratch,
598                        gc_required,
599                        TAG_OBJECT);
600  __ jmp(&allocated);
601
602  // Allocate the JSArray object together with space for a FixedArray with the
603  // requested elements.
604  __ bind(&not_empty);
605  ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
606  __ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize,
607                        times_pointer_size,
608                        array_size,
609                        result,
610                        elements_array_end,
611                        scratch,
612                        gc_required,
613                        TAG_OBJECT);
614
615  // Allocated the JSArray. Now initialize the fields except for the elements
616  // array.
617  // result: JSObject
618  // elements_array: initial map
619  // elements_array_end: start of next object
620  // array_size: size of array
621  __ bind(&allocated);
622  __ movq(FieldOperand(result, JSObject::kMapOffset), elements_array);
623  __ Move(elements_array, Factory::empty_fixed_array());
624  __ movq(FieldOperand(result, JSArray::kPropertiesOffset), elements_array);
625  // Field JSArray::kElementsOffset is initialized later.
626  __ Integer32ToSmi(scratch, array_size);
627  __ movq(FieldOperand(result, JSArray::kLengthOffset), scratch);
628
629  // Calculate the location of the elements array and set elements array member
630  // of the JSArray.
631  // result: JSObject
632  // elements_array_end: start of next object
633  // array_size: size of array
634  __ lea(elements_array, Operand(result, JSArray::kSize));
635  __ movq(FieldOperand(result, JSArray::kElementsOffset), elements_array);
636
637  // Initialize the fixed array. FixedArray length is not stored as a smi.
638  // result: JSObject
639  // elements_array: elements array
640  // elements_array_end: start of next object
641  // array_size: size of array
642  ASSERT(kSmiTag == 0);
643  __ Move(FieldOperand(elements_array, JSObject::kMapOffset),
644          Factory::fixed_array_map());
645  Label not_empty_2, fill_array;
646  __ testq(array_size, array_size);
647  __ j(not_zero, &not_empty_2);
648  // Length of the FixedArray is the number of pre-allocated elements even
649  // though the actual JSArray has length 0.
650  __ movq(FieldOperand(elements_array, Array::kLengthOffset),
651          Immediate(kPreallocatedArrayElements));
652  __ jmp(&fill_array);
653  __ bind(&not_empty_2);
654  // For non-empty JSArrays the length of the FixedArray and the JSArray is the
655  // same.
656  __ movq(FieldOperand(elements_array, Array::kLengthOffset), array_size);
657
658  // Fill the allocated FixedArray with the hole value if requested.
659  // result: JSObject
660  // elements_array: elements array
661  // elements_array_end: start of next object
662  __ bind(&fill_array);
663  if (fill_with_hole) {
664    Label loop, entry;
665    __ Move(scratch, Factory::the_hole_value());
666    __ lea(elements_array, Operand(elements_array,
667                                   FixedArray::kHeaderSize - kHeapObjectTag));
668    __ jmp(&entry);
669    __ bind(&loop);
670    __ movq(Operand(elements_array, 0), scratch);
671    __ addq(elements_array, Immediate(kPointerSize));
672    __ bind(&entry);
673    __ cmpq(elements_array, elements_array_end);
674    __ j(below, &loop);
675  }
676}
677
678
679// Create a new array for the built-in Array function. This function allocates
680// the JSArray object and the FixedArray elements array and initializes these.
681// If the Array cannot be constructed in native code the runtime is called. This
682// function assumes the following state:
683//   rdi: constructor (built-in Array function)
684//   rax: argc
685//   rsp[0]: return address
686//   rsp[8]: last argument
687// This function is used for both construct and normal calls of Array. The only
688// difference between handling a construct call and a normal call is that for a
689// construct call the constructor function in rdi needs to be preserved for
690// entering the generic code. In both cases argc in rax needs to be preserved.
691// Both registers are preserved by this code so no need to differentiate between
692// a construct call and a normal call.
693static void ArrayNativeCode(MacroAssembler* masm,
694                            Label *call_generic_code) {
695  Label argc_one_or_more, argc_two_or_more;
696
697  // Check for array construction with zero arguments.
698  __ testq(rax, rax);
699  __ j(not_zero, &argc_one_or_more);
700
701  // Handle construction of an empty array.
702  AllocateEmptyJSArray(masm,
703                       rdi,
704                       rbx,
705                       rcx,
706                       rdx,
707                       r8,
708                       kPreallocatedArrayElements,
709                       call_generic_code);
710  __ IncrementCounter(&Counters::array_function_native, 1);
711  __ movq(rax, rbx);
712  __ ret(kPointerSize);
713
714  // Check for one argument. Bail out if argument is not smi or if it is
715  // negative.
716  __ bind(&argc_one_or_more);
717  __ cmpq(rax, Immediate(1));
718  __ j(not_equal, &argc_two_or_more);
719  __ movq(rdx, Operand(rsp, kPointerSize));  // Get the argument from the stack.
720  __ JumpIfNotPositiveSmi(rdx, call_generic_code);
721
722  // Handle construction of an empty array of a certain size. Bail out if size
723  // is to large to actually allocate an elements array.
724  __ SmiCompare(rdx, Smi::FromInt(JSObject::kInitialMaxFastElementArray));
725  __ j(greater_equal, call_generic_code);
726
727  // rax: argc
728  // rdx: array_size (smi)
729  // rdi: constructor
730  // esp[0]: return address
731  // esp[8]: argument
732  AllocateJSArray(masm,
733                  rdi,
734                  rdx,
735                  rbx,
736                  rcx,
737                  r8,
738                  r9,
739                  true,
740                  call_generic_code);
741  __ IncrementCounter(&Counters::array_function_native, 1);
742  __ movq(rax, rbx);
743  __ ret(2 * kPointerSize);
744
745  // Handle construction of an array from a list of arguments.
746  __ bind(&argc_two_or_more);
747  __ movq(rdx, rax);
748  __ Integer32ToSmi(rdx, rdx);  // Convet argc to a smi.
749  // rax: argc
750  // rdx: array_size (smi)
751  // rdi: constructor
752  // esp[0] : return address
753  // esp[8] : last argument
754  AllocateJSArray(masm,
755                  rdi,
756                  rdx,
757                  rbx,
758                  rcx,
759                  r8,
760                  r9,
761                  false,
762                  call_generic_code);
763  __ IncrementCounter(&Counters::array_function_native, 1);
764
765  // rax: argc
766  // rbx: JSArray
767  // rcx: elements_array
768  // r8: elements_array_end (untagged)
769  // esp[0]: return address
770  // esp[8]: last argument
771
772  // Location of the last argument
773  __ lea(r9, Operand(rsp, kPointerSize));
774
775  // Location of the first array element (Parameter fill_with_holes to
776  // AllocateJSArrayis false, so the FixedArray is returned in rcx).
777  __ lea(rdx, Operand(rcx, FixedArray::kHeaderSize - kHeapObjectTag));
778
779  // rax: argc
780  // rbx: JSArray
781  // rdx: location of the first array element
782  // r9: location of the last argument
783  // esp[0]: return address
784  // esp[8]: last argument
785  Label loop, entry;
786  __ movq(rcx, rax);
787  __ jmp(&entry);
788  __ bind(&loop);
789  __ movq(kScratchRegister, Operand(r9, rcx, times_pointer_size, 0));
790  __ movq(Operand(rdx, 0), kScratchRegister);
791  __ addq(rdx, Immediate(kPointerSize));
792  __ bind(&entry);
793  __ decq(rcx);
794  __ j(greater_equal, &loop);
795
796  // Remove caller arguments from the stack and return.
797  // rax: argc
798  // rbx: JSArray
799  // esp[0]: return address
800  // esp[8]: last argument
801  __ pop(rcx);
802  __ lea(rsp, Operand(rsp, rax, times_pointer_size, 1 * kPointerSize));
803  __ push(rcx);
804  __ movq(rax, rbx);
805  __ ret(0);
806}
807
808
809void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
810  // ----------- S t a t e -------------
811  //  -- rax : argc
812  //  -- rsp[0] : return address
813  //  -- rsp[8] : last argument
814  // -----------------------------------
815  Label generic_array_code;
816
817  // Get the Array function.
818  GenerateLoadArrayFunction(masm, rdi);
819
820  if (FLAG_debug_code) {
821    // Initial map for the builtin Array function shoud be a map.
822    __ movq(rbx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
823    // Will both indicate a NULL and a Smi.
824    ASSERT(kSmiTag == 0);
825    Condition not_smi = NegateCondition(masm->CheckSmi(rbx));
826    __ Check(not_smi, "Unexpected initial map for Array function");
827    __ CmpObjectType(rbx, MAP_TYPE, rcx);
828    __ Check(equal, "Unexpected initial map for Array function");
829  }
830
831  // Run the native code for the Array function called as a normal function.
832  ArrayNativeCode(masm, &generic_array_code);
833
834  // Jump to the generic array code in case the specialized code cannot handle
835  // the construction.
836  __ bind(&generic_array_code);
837  Code* code = Builtins::builtin(Builtins::ArrayCodeGeneric);
838  Handle<Code> array_code(code);
839  __ Jump(array_code, RelocInfo::CODE_TARGET);
840}
841
842
843void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
844  // ----------- S t a t e -------------
845  //  -- rax : argc
846  //  -- rdi : constructor
847  //  -- rsp[0] : return address
848  //  -- rsp[8] : last argument
849  // -----------------------------------
850  Label generic_constructor;
851
852  if (FLAG_debug_code) {
853    // The array construct code is only set for the builtin Array function which
854    // does always have a map.
855    GenerateLoadArrayFunction(masm, rbx);
856    __ cmpq(rdi, rbx);
857    __ Check(equal, "Unexpected Array function");
858    // Initial map for the builtin Array function should be a map.
859    __ movq(rbx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
860    // Will both indicate a NULL and a Smi.
861    ASSERT(kSmiTag == 0);
862    Condition not_smi = NegateCondition(masm->CheckSmi(rbx));
863    __ Check(not_smi, "Unexpected initial map for Array function");
864    __ CmpObjectType(rbx, MAP_TYPE, rcx);
865    __ Check(equal, "Unexpected initial map for Array function");
866  }
867
868  // Run the native code for the Array function called as constructor.
869  ArrayNativeCode(masm, &generic_constructor);
870
871  // Jump to the generic construct code in case the specialized code cannot
872  // handle the construction.
873  __ bind(&generic_constructor);
874  Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
875  Handle<Code> generic_construct_stub(code);
876  __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
877}
878
879
880void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
881  // ----------- S t a t e -------------
882  //  -- rax: number of arguments
883  //  -- rdi: constructor function
884  // -----------------------------------
885
886  Label non_function_call;
887  // Check that function is not a smi.
888  __ JumpIfSmi(rdi, &non_function_call);
889  // Check that function is a JSFunction.
890  __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
891  __ j(not_equal, &non_function_call);
892
893  // Jump to the function-specific construct stub.
894  __ movq(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
895  __ movq(rbx, FieldOperand(rbx, SharedFunctionInfo::kConstructStubOffset));
896  __ lea(rbx, FieldOperand(rbx, Code::kHeaderSize));
897  __ jmp(rbx);
898
899  // edi: called object
900  // eax: number of arguments
901  __ bind(&non_function_call);
902  // CALL_NON_FUNCTION expects the non-function constructor as receiver
903  // (instead of the original receiver from the call site).  The receiver is
904  // stack element argc+1.
905  __ movq(Operand(rsp, rax, times_pointer_size, kPointerSize), rdi);
906  // Set expected number of arguments to zero (not changing rax).
907  __ movq(rbx, Immediate(0));
908  __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
909  __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
910          RelocInfo::CODE_TARGET);
911}
912
913
914static void Generate_JSConstructStubHelper(MacroAssembler* masm,
915                                           bool is_api_function) {
916    // Enter a construct frame.
917  __ EnterConstructFrame();
918
919  // Store a smi-tagged arguments count on the stack.
920  __ Integer32ToSmi(rax, rax);
921  __ push(rax);
922
923  // Push the function to invoke on the stack.
924  __ push(rdi);
925
926  // Try to allocate the object without transitioning into C code. If any of the
927  // preconditions is not met, the code bails out to the runtime call.
928  Label rt_call, allocated;
929  if (FLAG_inline_new) {
930    Label undo_allocation;
931
932#ifdef ENABLE_DEBUGGER_SUPPORT
933    ExternalReference debug_step_in_fp =
934        ExternalReference::debug_step_in_fp_address();
935    __ movq(kScratchRegister, debug_step_in_fp);
936    __ cmpq(Operand(kScratchRegister, 0), Immediate(0));
937    __ j(not_equal, &rt_call);
938#endif
939
940    // Verified that the constructor is a JSFunction.
941    // Load the initial map and verify that it is in fact a map.
942    // rdi: constructor
943    __ movq(rax, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
944    // Will both indicate a NULL and a Smi
945    ASSERT(kSmiTag == 0);
946    __ JumpIfSmi(rax, &rt_call);
947    // rdi: constructor
948    // rax: initial map (if proven valid below)
949    __ CmpObjectType(rax, MAP_TYPE, rbx);
950    __ j(not_equal, &rt_call);
951
952    // Check that the constructor is not constructing a JSFunction (see comments
953    // in Runtime_NewObject in runtime.cc). In which case the initial map's
954    // instance type would be JS_FUNCTION_TYPE.
955    // rdi: constructor
956    // rax: initial map
957    __ CmpInstanceType(rax, JS_FUNCTION_TYPE);
958    __ j(equal, &rt_call);
959
960    // Now allocate the JSObject on the heap.
961    __ movzxbq(rdi, FieldOperand(rax, Map::kInstanceSizeOffset));
962    __ shl(rdi, Immediate(kPointerSizeLog2));
963    // rdi: size of new object
964    __ AllocateInNewSpace(rdi,
965                          rbx,
966                          rdi,
967                          no_reg,
968                          &rt_call,
969                          NO_ALLOCATION_FLAGS);
970    // Allocated the JSObject, now initialize the fields.
971    // rax: initial map
972    // rbx: JSObject (not HeapObject tagged - the actual address).
973    // rdi: start of next object
974    __ movq(Operand(rbx, JSObject::kMapOffset), rax);
975    __ LoadRoot(rcx, Heap::kEmptyFixedArrayRootIndex);
976    __ movq(Operand(rbx, JSObject::kPropertiesOffset), rcx);
977    __ movq(Operand(rbx, JSObject::kElementsOffset), rcx);
978    // Set extra fields in the newly allocated object.
979    // rax: initial map
980    // rbx: JSObject
981    // rdi: start of next object
982    { Label loop, entry;
983      __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
984      __ lea(rcx, Operand(rbx, JSObject::kHeaderSize));
985      __ jmp(&entry);
986      __ bind(&loop);
987      __ movq(Operand(rcx, 0), rdx);
988      __ addq(rcx, Immediate(kPointerSize));
989      __ bind(&entry);
990      __ cmpq(rcx, rdi);
991      __ j(less, &loop);
992    }
993
994    // Add the object tag to make the JSObject real, so that we can continue and
995    // jump into the continuation code at any time from now on. Any failures
996    // need to undo the allocation, so that the heap is in a consistent state
997    // and verifiable.
998    // rax: initial map
999    // rbx: JSObject
1000    // rdi: start of next object
1001    __ or_(rbx, Immediate(kHeapObjectTag));
1002
1003    // Check if a non-empty properties array is needed.
1004    // Allocate and initialize a FixedArray if it is.
1005    // rax: initial map
1006    // rbx: JSObject
1007    // rdi: start of next object
1008    // Calculate total properties described map.
1009    __ movzxbq(rdx, FieldOperand(rax, Map::kUnusedPropertyFieldsOffset));
1010    __ movzxbq(rcx, FieldOperand(rax, Map::kPreAllocatedPropertyFieldsOffset));
1011    __ addq(rdx, rcx);
1012    // Calculate unused properties past the end of the in-object properties.
1013    __ movzxbq(rcx, FieldOperand(rax, Map::kInObjectPropertiesOffset));
1014    __ subq(rdx, rcx);
1015    // Done if no extra properties are to be allocated.
1016    __ j(zero, &allocated);
1017    __ Assert(positive, "Property allocation count failed.");
1018
1019    // Scale the number of elements by pointer size and add the header for
1020    // FixedArrays to the start of the next object calculation from above.
1021    // rbx: JSObject
1022    // rdi: start of next object (will be start of FixedArray)
1023    // rdx: number of elements in properties array
1024    __ AllocateInNewSpace(FixedArray::kHeaderSize,
1025                          times_pointer_size,
1026                          rdx,
1027                          rdi,
1028                          rax,
1029                          no_reg,
1030                          &undo_allocation,
1031                          RESULT_CONTAINS_TOP);
1032
1033    // Initialize the FixedArray.
1034    // rbx: JSObject
1035    // rdi: FixedArray
1036    // rdx: number of elements
1037    // rax: start of next object
1038    __ LoadRoot(rcx, Heap::kFixedArrayMapRootIndex);
1039    __ movq(Operand(rdi, JSObject::kMapOffset), rcx);  // setup the map
1040    __ movl(Operand(rdi, FixedArray::kLengthOffset), rdx);  // and length
1041
1042    // Initialize the fields to undefined.
1043    // rbx: JSObject
1044    // rdi: FixedArray
1045    // rax: start of next object
1046    // rdx: number of elements
1047    { Label loop, entry;
1048      __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
1049      __ lea(rcx, Operand(rdi, FixedArray::kHeaderSize));
1050      __ jmp(&entry);
1051      __ bind(&loop);
1052      __ movq(Operand(rcx, 0), rdx);
1053      __ addq(rcx, Immediate(kPointerSize));
1054      __ bind(&entry);
1055      __ cmpq(rcx, rax);
1056      __ j(below, &loop);
1057    }
1058
1059    // Store the initialized FixedArray into the properties field of
1060    // the JSObject
1061    // rbx: JSObject
1062    // rdi: FixedArray
1063    __ or_(rdi, Immediate(kHeapObjectTag));  // add the heap tag
1064    __ movq(FieldOperand(rbx, JSObject::kPropertiesOffset), rdi);
1065
1066
1067    // Continue with JSObject being successfully allocated
1068    // rbx: JSObject
1069    __ jmp(&allocated);
1070
1071    // Undo the setting of the new top so that the heap is verifiable. For
1072    // example, the map's unused properties potentially do not match the
1073    // allocated objects unused properties.
1074    // rbx: JSObject (previous new top)
1075    __ bind(&undo_allocation);
1076    __ UndoAllocationInNewSpace(rbx);
1077  }
1078
1079  // Allocate the new receiver object using the runtime call.
1080  // rdi: function (constructor)
1081  __ bind(&rt_call);
1082  // Must restore rdi (constructor) before calling runtime.
1083  __ movq(rdi, Operand(rsp, 0));
1084  __ push(rdi);
1085  __ CallRuntime(Runtime::kNewObject, 1);
1086  __ movq(rbx, rax);  // store result in rbx
1087
1088  // New object allocated.
1089  // rbx: newly allocated object
1090  __ bind(&allocated);
1091  // Retrieve the function from the stack.
1092  __ pop(rdi);
1093
1094  // Retrieve smi-tagged arguments count from the stack.
1095  __ movq(rax, Operand(rsp, 0));
1096  __ SmiToInteger32(rax, rax);
1097
1098  // Push the allocated receiver to the stack. We need two copies
1099  // because we may have to return the original one and the calling
1100  // conventions dictate that the called function pops the receiver.
1101  __ push(rbx);
1102  __ push(rbx);
1103
1104  // Setup pointer to last argument.
1105  __ lea(rbx, Operand(rbp, StandardFrameConstants::kCallerSPOffset));
1106
1107  // Copy arguments and receiver to the expression stack.
1108  Label loop, entry;
1109  __ movq(rcx, rax);
1110  __ jmp(&entry);
1111  __ bind(&loop);
1112  __ push(Operand(rbx, rcx, times_pointer_size, 0));
1113  __ bind(&entry);
1114  __ decq(rcx);
1115  __ j(greater_equal, &loop);
1116
1117  // Call the function.
1118  if (is_api_function) {
1119    __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
1120    Handle<Code> code = Handle<Code>(
1121        Builtins::builtin(Builtins::HandleApiCallConstruct));
1122    ParameterCount expected(0);
1123    __ InvokeCode(code, expected, expected,
1124                  RelocInfo::CODE_TARGET, CALL_FUNCTION);
1125  } else {
1126    ParameterCount actual(rax);
1127    __ InvokeFunction(rdi, actual, CALL_FUNCTION);
1128  }
1129
1130  // Restore context from the frame.
1131  __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
1132
1133  // If the result is an object (in the ECMA sense), we should get rid
1134  // of the receiver and use the result; see ECMA-262 section 13.2.2-7
1135  // on page 74.
1136  Label use_receiver, exit;
1137  // If the result is a smi, it is *not* an object in the ECMA sense.
1138  __ JumpIfSmi(rax, &use_receiver);
1139
1140  // If the type of the result (stored in its map) is less than
1141  // FIRST_JS_OBJECT_TYPE, it is not an object in the ECMA sense.
1142  __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx);
1143  __ j(above_equal, &exit);
1144
1145  // Throw away the result of the constructor invocation and use the
1146  // on-stack receiver as the result.
1147  __ bind(&use_receiver);
1148  __ movq(rax, Operand(rsp, 0));
1149
1150  // Restore the arguments count and leave the construct frame.
1151  __ bind(&exit);
1152  __ movq(rbx, Operand(rsp, kPointerSize));  // get arguments count
1153  __ LeaveConstructFrame();
1154
1155  // Remove caller arguments from the stack and return.
1156  __ pop(rcx);
1157  SmiIndex index = masm->SmiToIndex(rbx, rbx, kPointerSizeLog2);
1158  __ lea(rsp, Operand(rsp, index.reg, index.scale, 1 * kPointerSize));
1159  __ push(rcx);
1160  __ IncrementCounter(&Counters::constructed_objects, 1);
1161  __ ret(0);
1162}
1163
1164
1165void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
1166  Generate_JSConstructStubHelper(masm, false);
1167}
1168
1169
1170void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
1171  Generate_JSConstructStubHelper(masm, true);
1172}
1173
1174
1175static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
1176                                             bool is_construct) {
1177  // Expects five C++ function parameters.
1178  // - Address entry (ignored)
1179  // - JSFunction* function (
1180  // - Object* receiver
1181  // - int argc
1182  // - Object*** argv
1183  // (see Handle::Invoke in execution.cc).
1184
1185  // Platform specific argument handling. After this, the stack contains
1186  // an internal frame and the pushed function and receiver, and
1187  // register rax and rbx holds the argument count and argument array,
1188  // while rdi holds the function pointer and rsi the context.
1189#ifdef _WIN64
1190  // MSVC parameters in:
1191  // rcx : entry (ignored)
1192  // rdx : function
1193  // r8 : receiver
1194  // r9 : argc
1195  // [rsp+0x20] : argv
1196
1197  // Clear the context before we push it when entering the JS frame.
1198  __ xor_(rsi, rsi);
1199  __ EnterInternalFrame();
1200
1201  // Load the function context into rsi.
1202  __ movq(rsi, FieldOperand(rdx, JSFunction::kContextOffset));
1203
1204  // Push the function and the receiver onto the stack.
1205  __ push(rdx);
1206  __ push(r8);
1207
1208  // Load the number of arguments and setup pointer to the arguments.
1209  __ movq(rax, r9);
1210  // Load the previous frame pointer to access C argument on stack
1211  __ movq(kScratchRegister, Operand(rbp, 0));
1212  __ movq(rbx, Operand(kScratchRegister, EntryFrameConstants::kArgvOffset));
1213  // Load the function pointer into rdi.
1214  __ movq(rdi, rdx);
1215#else  // !defined(_WIN64)
1216  // GCC parameters in:
1217  // rdi : entry (ignored)
1218  // rsi : function
1219  // rdx : receiver
1220  // rcx : argc
1221  // r8  : argv
1222
1223  __ movq(rdi, rsi);
1224  // rdi : function
1225
1226  // Clear the context before we push it when entering the JS frame.
1227  __ xor_(rsi, rsi);
1228  // Enter an internal frame.
1229  __ EnterInternalFrame();
1230
1231  // Push the function and receiver and setup the context.
1232  __ push(rdi);
1233  __ push(rdx);
1234  __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
1235
1236  // Load the number of arguments and setup pointer to the arguments.
1237  __ movq(rax, rcx);
1238  __ movq(rbx, r8);
1239#endif  // _WIN64
1240
1241  // Set up the roots register.
1242  ExternalReference roots_address = ExternalReference::roots_address();
1243  __ movq(r13, roots_address);
1244
1245  // Current stack contents:
1246  // [rsp + 2 * kPointerSize ... ]: Internal frame
1247  // [rsp + kPointerSize]         : function
1248  // [rsp]                        : receiver
1249  // Current register contents:
1250  // rax : argc
1251  // rbx : argv
1252  // rsi : context
1253  // rdi : function
1254
1255  // Copy arguments to the stack in a loop.
1256  // Register rbx points to array of pointers to handle locations.
1257  // Push the values of these handles.
1258  Label loop, entry;
1259  __ xor_(rcx, rcx);  // Set loop variable to 0.
1260  __ jmp(&entry);
1261  __ bind(&loop);
1262  __ movq(kScratchRegister, Operand(rbx, rcx, times_pointer_size, 0));
1263  __ push(Operand(kScratchRegister, 0));  // dereference handle
1264  __ addq(rcx, Immediate(1));
1265  __ bind(&entry);
1266  __ cmpq(rcx, rax);
1267  __ j(not_equal, &loop);
1268
1269  // Invoke the code.
1270  if (is_construct) {
1271    // Expects rdi to hold function pointer.
1272    __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
1273            RelocInfo::CODE_TARGET);
1274  } else {
1275    ParameterCount actual(rax);
1276    // Function must be in rdi.
1277    __ InvokeFunction(rdi, actual, CALL_FUNCTION);
1278  }
1279
1280  // Exit the JS frame. Notice that this also removes the empty
1281  // context and the function left on the stack by the code
1282  // invocation.
1283  __ LeaveInternalFrame();
1284  // TODO(X64): Is argument correct? Is there a receiver to remove?
1285  __ ret(1 * kPointerSize);  // remove receiver
1286}
1287
1288
1289void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
1290  Generate_JSEntryTrampolineHelper(masm, false);
1291}
1292
1293
1294void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
1295  Generate_JSEntryTrampolineHelper(masm, true);
1296}
1297
1298} }  // namespace v8::internal
1299