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