1b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Copyright 2012 the V8 project authors. All rights reserved.
2b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// found in the LICENSE file.
4b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
5b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#if V8_TARGET_ARCH_X87
6b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
7b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/code-factory.h"
8b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/codegen.h"
9b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/deoptimizer.h"
10014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/full-codegen/full-codegen.h"
11014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/x87/frames-x87.h"
12b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
13b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochnamespace v8 {
14b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochnamespace internal {
15b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
16b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#define __ ACCESS_MASM(masm)
17b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
18f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochvoid Builtins::Generate_Adaptor(MacroAssembler* masm, Address address,
19f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                                ExitFrameType exit_frame_type) {
20b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // ----------- S t a t e -------------
21b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- eax                : number of arguments excluding receiver
22014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi                : target
23014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx                : new.target
24b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- esp[0]             : return address
25b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- esp[4]             : last argument
26b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- ...
27014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[4 * argc]      : first argument
28b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- esp[4 * (argc +1)] : receiver
29b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // -----------------------------------
30014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ AssertFunction(edi);
31014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
32014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Make sure we operate in the context of the called function (for example
33014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ConstructStubs implemented in C++ will be run in the context of the caller
34014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // instead of the callee, due to the way that [[Construct]] is defined for
35014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ordinary functions).
36014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
37b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
38f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // JumpToExternalReference expects eax to contain the number of arguments
39f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // including the receiver and the extra arguments.
40f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  const int num_extra_args = 3;
41f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ add(eax, Immediate(num_extra_args + 1));
42f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
43b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Insert extra arguments.
4413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ PopReturnAddressTo(ecx);
45f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ SmiTag(eax);
46f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ Push(eax);
47f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ SmiUntag(eax);
4813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ Push(edi);
4913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ Push(edx);
5013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ PushReturnAddressFrom(ecx);
51b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
52f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ JumpToExternalReference(ExternalReference(address, masm->isolate()),
53f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                             exit_frame_type == BUILTIN_EXIT);
54b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
55b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
56109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochstatic void GenerateTailCallToReturnedCode(MacroAssembler* masm,
57109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                                           Runtime::FunctionId function_id) {
58014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
59109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  //  -- eax : argument count (preserved for callee)
60014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx : new target (preserved for callee)
61014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi : target function (preserved for callee)
62014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
63109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  {
64109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
65109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Push the number of arguments to the callee.
66109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ SmiTag(eax);
67109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ push(eax);
68109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Push a copy of the target function and the new target.
69109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ push(edi);
70109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ push(edx);
71109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Function is also the parameter to the runtime call.
72109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ push(edi);
73b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
74109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ CallRuntime(function_id, 1);
75109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ mov(ebx, eax);
76b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
77109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Restore target function and new target.
78109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ pop(edx);
79109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ pop(edi);
80109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ pop(eax);
81109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ SmiUntag(eax);
82109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  }
83f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
84109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize));
85109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ jmp(ebx);
86b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
87b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
88109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochstatic void GenerateTailCallToSharedCode(MacroAssembler* masm) {
89109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
90109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kCodeOffset));
91109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize));
92109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ jmp(ebx);
93f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch}
94f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
95b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) {
96b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Checking whether the queued function is ready for install is optional,
97b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // since we come across interrupts and stack checks elsewhere.  However,
98b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // not checking may delay installing ready functions, and always checking
99b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // would be quite expensive.  A good compromise is to first check against
100b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // stack limit as a cue for an interrupt signal.
101b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Label ok;
102b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  ExternalReference stack_limit =
103b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      ExternalReference::address_of_stack_limit(masm->isolate());
104b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ cmp(esp, Operand::StaticVariable(stack_limit));
105b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ j(above_equal, &ok, Label::kNear);
106b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
107109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  GenerateTailCallToReturnedCode(masm, Runtime::kTryInstallOptimizedCode);
108b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
109b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ bind(&ok);
110b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  GenerateTailCallToSharedCode(masm);
111b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
112b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
113c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdochnamespace {
114c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch
115c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdochvoid Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
116c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch                                    bool create_implicit_receiver,
117c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch                                    bool check_derived_construct) {
118b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // ----------- S t a t e -------------
119b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- eax: number of arguments
1203b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  //  -- esi: context
121b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- edi: constructor function
122014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx: new target
123b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // -----------------------------------
124b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
125b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Enter a construct frame.
126b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  {
127b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    FrameScope scope(masm, StackFrame::CONSTRUCT);
128b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
129014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Preserve the incoming parameters on the stack.
130b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ SmiTag(eax);
131c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    __ push(esi);
132b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ push(eax);
133b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
134014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (create_implicit_receiver) {
135109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      // Allocate the new receiver object.
136109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ Push(edi);
137109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ Push(edx);
13862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      __ Call(CodeFactory::FastNewObject(masm->isolate()).code(),
13962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch              RelocInfo::CODE_TARGET);
140109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ mov(ebx, eax);
141109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ Pop(edx);
142109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ Pop(edi);
143f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
144109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      // ----------- S t a t e -------------
145109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      //  -- edi: constructor function
146109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      //  -- ebx: newly allocated object
147109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      //  -- edx: new target
148109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      // -----------------------------------
149014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
150014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Retrieve smi-tagged arguments count from the stack.
151014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ mov(eax, Operand(esp, 0));
152b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
153b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
154014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ SmiUntag(eax);
155b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
156014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (create_implicit_receiver) {
157014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Push the allocated receiver to the stack. We need two copies
158014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // because we may have to return the original one and the calling
159014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // conventions dictate that the called function pops the receiver.
160014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ push(ebx);
161014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ push(ebx);
162b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    } else {
163014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ PushRoot(Heap::kTheHoleValueRootIndex);
164b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
165b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
166b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Set up pointer to last argument.
167b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
168b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
169b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Copy arguments and receiver to the expression stack.
170b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Label loop, entry;
171b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ mov(ecx, eax);
172b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ jmp(&entry);
173b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ bind(&loop);
174b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ push(Operand(ebx, ecx, times_4, 0));
175b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ bind(&entry);
176b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ dec(ecx);
177b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ j(greater_equal, &loop);
178b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
179b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Call the function.
180bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    ParameterCount actual(eax);
181bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ InvokeFunction(edi, edx, actual, CALL_FUNCTION,
182bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch                      CheckDebugStepCallWrapper());
183b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
184b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Store offset of return address for deoptimizer.
185014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (create_implicit_receiver && !is_api_function) {
186b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
187b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
188b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
189b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Restore context from the frame.
1903b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    __ mov(esi, Operand(ebp, ConstructFrameConstants::kContextOffset));
191b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
192014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (create_implicit_receiver) {
193014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // If the result is an object (in the ECMA sense), we should get rid
194014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // of the receiver and use the result; see ECMA-262 section 13.2.2-7
195014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // on page 74.
196014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Label use_receiver, exit;
197014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
198014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // If the result is a smi, it is *not* an object in the ECMA sense.
199c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      __ JumpIfSmi(eax, &use_receiver, Label::kNear);
200014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
201014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // If the type of the result (stored in its map) is less than
202014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense.
203014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ecx);
204c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      __ j(above_equal, &exit, Label::kNear);
205014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
206014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Throw away the result of the constructor invocation and use the
207014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // on-stack receiver as the result.
208014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ bind(&use_receiver);
209014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ mov(eax, Operand(esp, 0));
210014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
211014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Restore the arguments count and leave the construct frame. The
212014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // arguments count is stored below the receiver.
213014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ bind(&exit);
214014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ mov(ebx, Operand(esp, 1 * kPointerSize));
215014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    } else {
216014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ mov(ebx, Operand(esp, 0));
217014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
218b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
219b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Leave construct frame.
220b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
221b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
222109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // ES6 9.2.2. Step 13+
223109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Check that the result is not a Smi, indicating that the constructor result
224109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // from a derived class is neither undefined nor an Object.
225109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  if (check_derived_construct) {
226109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    Label dont_throw;
227109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ JumpIfNotSmi(eax, &dont_throw);
228109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    {
229109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      FrameScope scope(masm, StackFrame::INTERNAL);
230109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject);
231109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    }
232109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ bind(&dont_throw);
233109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  }
234109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
235b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Remove caller arguments from the stack and return.
236b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
237b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ pop(ecx);
238b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize));  // 1 ~ receiver
239b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ push(ecx);
240014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (create_implicit_receiver) {
241014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);
242014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
243b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ ret(0);
244b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
245b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
246c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch}  // namespace
247c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch
248b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
249109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Generate_JSConstructStubHelper(masm, false, true, false);
250b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
251b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
252b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
253109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Generate_JSConstructStubHelper(masm, true, false, false);
254014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
255014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
256014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) {
257109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Generate_JSConstructStubHelper(masm, false, false, false);
258109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch}
259109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
260109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochvoid Builtins::Generate_JSBuiltinsConstructStubForDerived(
261109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    MacroAssembler* masm) {
262109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Generate_JSConstructStubHelper(masm, false, false, true);
263014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
264014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
265014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_ConstructedNonConstructable(MacroAssembler* masm) {
266014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  FrameScope scope(masm, StackFrame::INTERNAL);
267014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ push(edi);
268014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CallRuntime(Runtime::kThrowConstructedNonConstructable);
269014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
270014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
271014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochenum IsTagged { kEaxIsSmiTagged, kEaxIsUntaggedInt };
272014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
273014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// Clobbers ecx, edx, edi; preserves all other registers.
274014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochstatic void Generate_CheckStackOverflow(MacroAssembler* masm,
275014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                        IsTagged eax_is_tagged) {
276014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // eax   : the number of items to be pushed to the stack
277014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //
278014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Check the stack for overflow. We are not trying to catch
279014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // interruptions (e.g. debug break and preemption) here, so the "real stack
280014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // limit" is checked.
281014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label okay;
282014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  ExternalReference real_stack_limit =
283014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      ExternalReference::address_of_real_stack_limit(masm->isolate());
284014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(edi, Operand::StaticVariable(real_stack_limit));
285014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Make ecx the space we have left. The stack might already be overflowed
286014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // here which will cause ecx to become negative.
287014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, esp);
288014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ sub(ecx, edi);
289014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Make edx the space we need for the array when it is unrolled onto the
290014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // stack.
291014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(edx, eax);
292014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  int smi_tag = eax_is_tagged == kEaxIsSmiTagged ? kSmiTagSize : 0;
293014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ shl(edx, kPointerSizeLog2 - smi_tag);
294014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Check if the arguments will overflow the stack.
295014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ cmp(ecx, edx);
296014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(greater, &okay);  // Signed comparison.
297014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
298014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Out of stack space.
299014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CallRuntime(Runtime::kThrowStackOverflow);
300014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
301014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&okay);
302b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
303b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
304b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochstatic void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
305b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                             bool is_construct) {
306b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  ProfileEntryHookStub::MaybeCallEntryHook(masm);
307b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
308b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  {
309b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
310b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
311014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Setup the context (we need to use the caller context from the isolate).
312014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    ExternalReference context_address(Isolate::kContextAddress,
313014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                      masm->isolate());
314014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(esi, Operand::StaticVariable(context_address));
315014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
316b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Load the previous frame pointer (ebx) to access C arguments
317b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ mov(ebx, Operand(ebp, 0));
318b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
319b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Push the function and the receiver onto the stack.
320014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ push(Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
321b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
322b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
323b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Load the number of arguments and setup pointer to the arguments.
324b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset));
325b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset));
326b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
327014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Check if we have enough stack space to push all arguments.
328014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Expects argument count in eax. Clobbers ecx, edx, edi.
329014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Generate_CheckStackOverflow(masm, kEaxIsUntaggedInt);
330014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
331b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Copy arguments to the stack in a loop.
332b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Label loop, entry;
333b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ Move(ecx, Immediate(0));
334014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ jmp(&entry, Label::kNear);
335b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ bind(&loop);
336b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ mov(edx, Operand(ebx, ecx, times_4, 0));  // push parameter from argv
337f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ push(Operand(edx, 0));                    // dereference handle
338b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ inc(ecx);
339b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ bind(&entry);
340b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ cmp(ecx, eax);
341b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ j(not_equal, &loop);
342b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
343014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Load the previous frame pointer (ebx) to access C arguments
344014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ebx, Operand(ebp, 0));
345014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
346014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Get the new.target and function from the frame.
347014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(edx, Operand(ebx, EntryFrameConstants::kNewTargetArgOffset));
348014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(edi, Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
349b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
350b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Invoke the code.
351014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Handle<Code> builtin = is_construct
352014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                               ? masm->isolate()->builtins()->Construct()
353014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                               : masm->isolate()->builtins()->Call();
354014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Call(builtin, RelocInfo::CODE_TARGET);
355b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
356b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Exit the internal frame. Notice that this also removes the empty.
357b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // context and the function left on the stack by the code
358b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // invocation.
359b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
360b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ ret(kPointerSize);  // Remove receiver.
361b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
362b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
363b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
364b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Generate_JSEntryTrampolineHelper(masm, false);
365b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
366b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
367b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
368b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Generate_JSEntryTrampolineHelper(masm, true);
369b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
370b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
371bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch// static
372bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdochvoid Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
373bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // ----------- S t a t e -------------
374bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- eax    : the value to pass to the generator
375bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- ebx    : the JSGeneratorObject to resume
376bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- edx    : the resume mode (tagged)
377bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- esp[0] : return address
378bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // -----------------------------------
379bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ AssertGeneratorObject(ebx);
380bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
381bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Store input value into generator object.
38213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ mov(FieldOperand(ebx, JSGeneratorObject::kInputOrDebugPosOffset), eax);
38313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ RecordWriteField(ebx, JSGeneratorObject::kInputOrDebugPosOffset, eax, ecx,
384bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch                      kDontSaveFPRegs);
385bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
386bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Store resume mode into generator object.
387bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(FieldOperand(ebx, JSGeneratorObject::kResumeModeOffset), edx);
388bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
389bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Load suspended function and context.
390bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(edi, FieldOperand(ebx, JSGeneratorObject::kFunctionOffset));
39162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
392bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
393bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Flood function if we are stepping.
39413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  Label prepare_step_in_if_stepping, prepare_step_in_suspended_generator;
39513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  Label stepping_prepared;
39662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  ExternalReference debug_hook =
39762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      ExternalReference::debug_hook_on_function_call_address(masm->isolate());
39862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ cmpb(Operand::StaticVariable(debug_hook), Immediate(0));
39962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ j(not_equal, &prepare_step_in_if_stepping);
40013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
40113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  // Flood function if we need to continue stepping in the suspended generator.
40213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  ExternalReference debug_suspended_generator =
40313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      ExternalReference::debug_suspended_generator_address(masm->isolate());
40413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ cmp(ebx, Operand::StaticVariable(debug_suspended_generator));
40513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ j(equal, &prepare_step_in_suspended_generator);
40613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ bind(&stepping_prepared);
407bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
408bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Pop return address.
409bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ PopReturnAddressTo(eax);
410bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
411bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Push receiver.
412bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ Push(FieldOperand(ebx, JSGeneratorObject::kReceiverOffset));
413bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
414bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // ----------- S t a t e -------------
415bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- eax    : return address
416bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- ebx    : the JSGeneratorObject to resume
417bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- edx    : the resume mode (tagged)
418bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- edi    : generator function
419bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- esi    : generator context
420bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- esp[0] : generator receiver
421bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // -----------------------------------
422bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
423bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Push holes for arguments to generator function. Since the parser forced
424bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // context allocation for any variables in generators, the actual argument
425bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // values have already been copied into the context and these dummy values
426bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // will never be used.
427bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
428bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(ecx,
429bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch         FieldOperand(ecx, SharedFunctionInfo::kFormalParameterCountOffset));
430bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  {
431bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    Label done_loop, loop;
432bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ bind(&loop);
433bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ sub(ecx, Immediate(Smi::FromInt(1)));
434bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ j(carry, &done_loop, Label::kNear);
435bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ PushRoot(Heap::kTheHoleValueRootIndex);
436bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ jmp(&loop);
437bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ bind(&done_loop);
438bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  }
439bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
44062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // Underlying function needs to have bytecode available.
44162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  if (FLAG_debug_code) {
44262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
44362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kFunctionDataOffset));
44462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ CmpObjectType(ecx, BYTECODE_ARRAY_TYPE, ecx);
44562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ Assert(equal, kMissingBytecodeArray);
44662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  }
447bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
44862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // Resume (Ignition/TurboFan) generator object.
449bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  {
450bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ PushReturnAddressFrom(eax);
451bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
452bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ mov(eax,
45362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch           FieldOperand(eax, SharedFunctionInfo::kFormalParameterCountOffset));
454bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    // We abuse new.target both to indicate that this is a resume call and to
455bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    // pass in the generator object.  In ordinary calls, new.target is always
456bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    // undefined because generator functions are non-constructable.
457bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ mov(edx, ebx);
458bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ jmp(FieldOperand(edi, JSFunction::kCodeEntryOffset));
459bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  }
460bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
46113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ bind(&prepare_step_in_if_stepping);
46213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  {
46313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
46413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ Push(ebx);
46513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ Push(edx);
46613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ Push(edi);
46762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ CallRuntime(Runtime::kDebugOnFunctionCall);
46813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ Pop(edx);
46913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ Pop(ebx);
47013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ mov(edi, FieldOperand(ebx, JSGeneratorObject::kFunctionOffset));
47113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  }
47213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ jmp(&stepping_prepared);
47313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
47413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ bind(&prepare_step_in_suspended_generator);
47513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  {
47613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
47713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ Push(ebx);
47813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ Push(edx);
47913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ CallRuntime(Runtime::kDebugPrepareStepInSuspendedGenerator);
48013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ Pop(edx);
48113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ Pop(ebx);
48213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ mov(edi, FieldOperand(ebx, JSGeneratorObject::kFunctionOffset));
48313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  }
48413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ jmp(&stepping_prepared);
48513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch}
48613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
48713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochstatic void LeaveInterpreterFrame(MacroAssembler* masm, Register scratch1,
48813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch                                  Register scratch2) {
48913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  Register args_count = scratch1;
49013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  Register return_pc = scratch2;
49113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
49213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  // Get the arguments + reciever count.
49313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ mov(args_count,
49413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch         Operand(ebp, InterpreterFrameConstants::kBytecodeArrayFromFp));
49513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ mov(args_count,
49613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch         FieldOperand(args_count, BytecodeArray::kParameterSizeOffset));
49713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
49813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  // Leave the frame (also dropping the register file).
49913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ leave();
50013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
50113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  // Drop receiver + arguments.
50213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ pop(return_pc);
50313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ add(esp, args_count);
50413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ push(return_pc);
505bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch}
506b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
507014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// Generate code for entering a JS function with the interpreter.
508014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// On entry to the function the receiver and arguments have been pushed on the
509014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// stack left to right.  The actual argument count matches the formal parameter
510014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// count expected by the function.
511014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch//
512014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// The live registers are:
513014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch//   o edi: the JS function object being called
514014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch//   o edx: the new target
515014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch//   o esi: our context
516014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch//   o ebp: the caller's frame pointer
517014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch//   o esp: stack pointer (pointing to return address)
518014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch//
519109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// The function builds an interpreter frame.  See InterpreterFrameConstants in
520109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// frames.h for its layout.
521014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
522bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  ProfileEntryHookStub::MaybeCallEntryHook(masm);
523bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
524014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Open a frame scope to indicate that there is a frame on the stack.  The
525014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // MANUAL indicates that the scope shouldn't actually generate code to set up
526014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // the frame (that is done below).
527014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  FrameScope frame_scope(masm, StackFrame::MANUAL);
528014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ push(ebp);  // Caller's frame pointer.
529014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ebp, esp);
530014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ push(esi);  // Callee's context.
531014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ push(edi);  // Callee's JS function.
532014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ push(edx);  // Callee's new target.
533014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
534bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Get the bytecode array from the function object (or from the DebugInfo if
535bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // it is present) and load it into kInterpreterBytecodeArrayRegister.
536014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
537109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Label load_debug_bytecode_array, bytecode_array_loaded;
53862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ JumpIfNotSmi(FieldOperand(eax, SharedFunctionInfo::kDebugInfoOffset),
53962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                  &load_debug_bytecode_array);
540014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(kInterpreterBytecodeArrayRegister,
541014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch         FieldOperand(eax, SharedFunctionInfo::kFunctionDataOffset));
542109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ bind(&bytecode_array_loaded);
543014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
544f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // Check whether we should continue to use the interpreter.
545f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  Label switch_to_different_code_kind;
546f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ Move(ecx, masm->CodeObject());  // Self-reference to this code.
547f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ cmp(ecx, FieldOperand(eax, SharedFunctionInfo::kCodeOffset));
548f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ j(not_equal, &switch_to_different_code_kind);
549f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
550f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Increment invocation count for the function.
55162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ EmitLoadFeedbackVector(ecx);
55262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ add(
55362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      FieldOperand(ecx, FeedbackVector::kInvocationCountIndex * kPointerSize +
55462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                            FeedbackVector::kHeaderSize),
55562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      Immediate(Smi::FromInt(1)));
556f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
557bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Check function data field is actually a BytecodeArray object.
558014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (FLAG_debug_code) {
559014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ AssertNotSmi(kInterpreterBytecodeArrayRegister);
560014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CmpObjectType(kInterpreterBytecodeArrayRegister, BYTECODE_ARRAY_TYPE,
561014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                     eax);
562014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
563014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
564014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
56562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // Reset code age.
56662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ mov_b(FieldOperand(kInterpreterBytecodeArrayRegister,
56762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                        BytecodeArray::kBytecodeAgeOffset),
56862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch           Immediate(BytecodeArray::kNoAgeBytecodeAge));
56962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
570109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Push bytecode array.
571109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ push(kInterpreterBytecodeArrayRegister);
572bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Push Smi tagged initial bytecode array offset.
573bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ push(Immediate(Smi::FromInt(BytecodeArray::kHeaderSize - kHeapObjectTag)));
574109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
575014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Allocate the local and temporary register file on the stack.
576014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
577014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Load frame size from the BytecodeArray object.
578014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ebx, FieldOperand(kInterpreterBytecodeArrayRegister,
579014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                             BytecodeArray::kFrameSizeOffset));
580014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
581014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Do a stack check to ensure we don't go over the limit.
582014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label ok;
583014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ecx, esp);
584014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ sub(ecx, ebx);
585014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    ExternalReference stack_limit =
586014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        ExternalReference::address_of_real_stack_limit(masm->isolate());
587014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(ecx, Operand::StaticVariable(stack_limit));
588014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(above_equal, &ok);
589014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CallRuntime(Runtime::kThrowStackOverflow);
590014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&ok);
591014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
592014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // If ok, push undefined as the initial value for all register file entries.
593014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label loop_header;
594014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label loop_check;
595014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(eax, Immediate(masm->isolate()->factory()->undefined_value()));
596014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ jmp(&loop_check);
597014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&loop_header);
598014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // TODO(rmcilroy): Consider doing more than one push per loop iteration.
599014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ push(eax);
600014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Continue loop if not done.
601014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&loop_check);
602014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ sub(ebx, Immediate(kPointerSize));
603014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(greater_equal, &loop_header);
604014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
605014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
606bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Load accumulator, bytecode offset and dispatch table into registers.
607014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
608014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(kInterpreterBytecodeOffsetRegister,
609014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch         Immediate(BytecodeArray::kHeaderSize - kHeapObjectTag));
610bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(kInterpreterDispatchTableRegister,
611bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch         Immediate(ExternalReference::interpreter_dispatch_table_address(
612bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch             masm->isolate())));
613014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
614014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Dispatch to the first bytecode handler for the function.
615bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ movzx_b(ebx, Operand(kInterpreterBytecodeArrayRegister,
616014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                          kInterpreterBytecodeOffsetRegister, times_1, 0));
617bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(ebx, Operand(kInterpreterDispatchTableRegister, ebx,
618bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch                      times_pointer_size, 0));
619014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ call(ebx);
620bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  masm->isolate()->heap()->SetInterpreterEntryReturnPCOffset(masm->pc_offset());
621109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
622bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // The return value is in eax.
62313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  LeaveInterpreterFrame(masm, ebx, ecx);
624014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ ret(0);
625014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
626bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Load debug copy of the bytecode array.
627bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ bind(&load_debug_bytecode_array);
628bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Register debug_info = kInterpreterBytecodeArrayRegister;
629bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(debug_info, FieldOperand(eax, SharedFunctionInfo::kDebugInfoOffset));
630bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(kInterpreterBytecodeArrayRegister,
631f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch         FieldOperand(debug_info, DebugInfo::kDebugBytecodeArrayIndex));
632bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ jmp(&bytecode_array_loaded);
633bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
634f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // If the shared code is no longer this entry trampoline, then the underlying
635f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // function has been switched to a different kind of code and we heal the
636f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // closure by switching the code entry field over to the new code as well.
637f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ bind(&switch_to_different_code_kind);
638bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ pop(edx);  // Callee's new target.
639bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ pop(edi);  // Callee's JS function.
640bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ pop(esi);  // Callee's context.
641bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ leave();   // Leave the frame so we can tail call.
642bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
643bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kCodeOffset));
644bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
645bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(FieldOperand(edi, JSFunction::kCodeEntryOffset), ecx);
646bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ RecordWriteCodeEntryField(edi, ecx, ebx);
647bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ jmp(ecx);
648bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch}
649014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
650f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdochstatic void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args,
651f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch                                        Register scratch1, Register scratch2,
652f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch                                        Label* stack_overflow,
653f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch                                        bool include_receiver = false) {
654f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Check the stack for overflow. We are not trying to catch
655f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // interruptions (e.g. debug break and preemption) here, so the "real stack
656f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // limit" is checked.
657f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  ExternalReference real_stack_limit =
658f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch      ExternalReference::address_of_real_stack_limit(masm->isolate());
659f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ mov(scratch1, Operand::StaticVariable(real_stack_limit));
660f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Make scratch2 the space we have left. The stack might already be overflowed
661f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // here which will cause scratch2 to become negative.
662f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ mov(scratch2, esp);
663f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ sub(scratch2, scratch1);
664f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Make scratch1 the space we need for the array when it is unrolled onto the
665f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // stack.
666f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ mov(scratch1, num_args);
667f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  if (include_receiver) {
668f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ add(scratch1, Immediate(1));
669f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  }
670f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ shl(scratch1, kPointerSizeLog2);
671f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Check if the arguments will overflow the stack.
672f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ cmp(scratch2, scratch1);
673f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ j(less_equal, stack_overflow);  // Signed comparison.
674f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch}
675f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
676014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochstatic void Generate_InterpreterPushArgs(MacroAssembler* masm,
677f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch                                         Register array_limit,
678f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch                                         Register start_address) {
679014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
680f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  //  -- start_address : Pointer to the last argument in the args array.
681014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- array_limit : Pointer to one before the first argument in the
682014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //                   args array.
683014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
684014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label loop_header, loop_check;
685014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ jmp(&loop_check);
686014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&loop_header);
687f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ Push(Operand(start_address, 0));
688f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ sub(start_address, Immediate(kPointerSize));
689014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&loop_check);
690f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ cmp(start_address, array_limit);
691014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(greater, &loop_header, Label::kNear);
692014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
693014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
694014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
695109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochvoid Builtins::Generate_InterpreterPushArgsAndCallImpl(
696f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    MacroAssembler* masm, TailCallMode tail_call_mode,
69762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    InterpreterPushArgsMode mode) {
698014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
699014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax : the number of arguments (not including the receiver)
700014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- ebx : the address of the first argument to be pushed. Subsequent
701014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //           arguments should be consecutive above this, in the same order as
702014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //           they are to be pushed onto the stack.
703014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi : the target to call (can be any Object).
704014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
705f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  Label stack_overflow;
706f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Compute the expected number of arguments.
707f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ mov(ecx, eax);
708f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ add(ecx, Immediate(1));  // Add one for receiver.
709f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
710f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Add a stack check before pushing the arguments. We need an extra register
711f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // to perform a stack check. So push it onto the stack temporarily. This
712f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // might cause stack overflow, but it will be detected by the check.
713f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ Push(edi);
714f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  Generate_StackOverflowCheck(masm, ecx, edx, edi, &stack_overflow);
715f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ Pop(edi);
716014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
717014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Pop return address to allow tail-call after pushing arguments.
718014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Pop(edx);
719014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
720014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Find the address of the last argument.
721014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ shl(ecx, kPointerSizeLog2);
722014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ neg(ecx);
723014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ add(ecx, ebx);
724f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  Generate_InterpreterPushArgs(masm, ecx, ebx);
725014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
726014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Call the target.
727014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Push(edx);  // Re-push return address.
728014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
72962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  if (mode == InterpreterPushArgsMode::kJSFunction) {
730f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny,
731f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                                                      tail_call_mode),
732f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch            RelocInfo::CODE_TARGET);
73362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  } else if (mode == InterpreterPushArgsMode::kWithFinalSpread) {
73462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ Jump(masm->isolate()->builtins()->CallWithSpread(),
73562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch            RelocInfo::CODE_TARGET);
736f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  } else {
737f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
738f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                                              tail_call_mode),
739f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch            RelocInfo::CODE_TARGET);
740f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
741f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
742f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ bind(&stack_overflow);
743f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  {
744f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // Pop the temporary registers, so that return address is on top of stack.
745f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ Pop(edi);
746f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
747f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ TailCallRuntime(Runtime::kThrowStackOverflow);
748f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
749f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // This should be unreachable.
750f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ int3();
751f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  }
752f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch}
753f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
754f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdochnamespace {
755f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
756f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch// This function modified start_addr, and only reads the contents of num_args
757f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch// register. scratch1 and scratch2 are used as temporary registers. Their
758f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch// original values are restored after the use.
759f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdochvoid Generate_InterpreterPushArgsAndReturnAddress(
760f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    MacroAssembler* masm, Register num_args, Register start_addr,
761f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    Register scratch1, Register scratch2, bool receiver_in_args,
762f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    int num_slots_above_ret_addr, Label* stack_overflow) {
763f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // We have to move return address and the temporary registers above it
764f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // before we can copy arguments onto the stack. To achieve this:
765f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Step 1: Increment the stack pointer by num_args + 1 (for receiver).
766f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Step 2: Move the return address and values above it to the top of stack.
767f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Step 3: Copy the arguments into the correct locations.
768f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  //  current stack    =====>    required stack layout
769f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // |             |            | scratch1      | (2) <-- esp(1)
770f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // |             |            | ....          | (2)
771f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // |             |            | scratch-n     | (2)
772f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // |             |            | return addr   | (2)
773f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // |             |            | arg N         | (3)
774f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // | scratch1    | <-- esp    | ....          |
775f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // | ....        |            | arg 0         |
776f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // | scratch-n   |            | arg 0         |
777f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // | return addr |            | receiver slot |
778f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
779f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Check for stack overflow before we increment the stack pointer.
780f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  Generate_StackOverflowCheck(masm, num_args, scratch1, scratch2,
781f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch                              stack_overflow, true);
782f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
783f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch// Step 1 - Update the stack pointer. scratch1 already contains the required
784f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch// increment to the stack. i.e. num_args + 1 stack slots. This is computed in
785f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch// the Generate_StackOverflowCheck.
786f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
787f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch#ifdef _MSC_VER
788f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // TODO(mythria): Move it to macro assembler.
789f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // In windows, we cannot increment the stack size by more than one page
790f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // (mimimum page size is 4KB) without accessing at least one byte on the
791f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // page. Check this:
792f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // https://msdn.microsoft.com/en-us/library/aa227153(v=vs.60).aspx.
793f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  const int page_size = 4 * 1024;
794f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  Label check_offset, update_stack_pointer;
795f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ bind(&check_offset);
796f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ cmp(scratch1, page_size);
797f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ j(less, &update_stack_pointer);
798f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ sub(esp, Immediate(page_size));
799f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Just to touch the page, before we increment further.
800f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ mov(Operand(esp, 0), Immediate(0));
801f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ sub(scratch1, Immediate(page_size));
802f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ jmp(&check_offset);
803f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ bind(&update_stack_pointer);
804f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch#endif
805f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
806f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ sub(esp, scratch1);
807f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
808f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Step 2 move return_address and slots above it to the correct locations.
809f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Move from top to bottom, otherwise we may overwrite when num_args = 0 or 1,
810f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // basically when the source and destination overlap. We at least need one
811f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // extra slot for receiver, so no extra checks are required to avoid copy.
812f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  for (int i = 0; i < num_slots_above_ret_addr + 1; i++) {
813f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ mov(scratch1,
814f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch           Operand(esp, num_args, times_pointer_size, (i + 1) * kPointerSize));
815f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ mov(Operand(esp, i * kPointerSize), scratch1);
816f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  }
817f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
818f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Step 3 copy arguments to correct locations.
819f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  if (receiver_in_args) {
820f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ mov(scratch1, num_args);
821f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ add(scratch1, Immediate(1));
822f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  } else {
823f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // Slot meant for receiver contains return address. Reset it so that
824f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // we will not incorrectly interpret return address as an object.
825f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ mov(Operand(esp, num_args, times_pointer_size,
826f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch                   (num_slots_above_ret_addr + 1) * kPointerSize),
827f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch           Immediate(0));
828f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ mov(scratch1, num_args);
829f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  }
830f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
831f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  Label loop_header, loop_check;
832f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ jmp(&loop_check);
833f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ bind(&loop_header);
834f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ mov(scratch2, Operand(start_addr, 0));
835f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ mov(Operand(esp, scratch1, times_pointer_size,
836f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch                 num_slots_above_ret_addr * kPointerSize),
837f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch         scratch2);
838f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ sub(start_addr, Immediate(kPointerSize));
839f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ sub(scratch1, Immediate(1));
840f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ bind(&loop_check);
841f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ cmp(scratch1, Immediate(0));
842f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ j(greater, &loop_header, Label::kNear);
843f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}
844014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
845f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch}  // end anonymous namespace
846f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
847014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
848f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdochvoid Builtins::Generate_InterpreterPushArgsAndConstructImpl(
84962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    MacroAssembler* masm, InterpreterPushArgsMode mode) {
850014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
851014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax : the number of arguments (not including the receiver)
852014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx : the new target
853014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi : the constructor
854f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  //  -- ebx : allocation site feedback (if available or undefined)
855f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  //  -- ecx : the address of the first argument to be pushed. Subsequent
856014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //           arguments should be consecutive above this, in the same order as
857014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //           they are to be pushed onto the stack.
858014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
859f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  Label stack_overflow;
860f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // We need two scratch registers. Push edi and edx onto stack.
861f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ Push(edi);
862f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ Push(edx);
863014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
864f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Push arguments and move return address to the top of stack.
865f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // The eax register is readonly. The ecx register will be modified. The edx
866f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // and edi registers will be modified but restored to their original values.
867f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  Generate_InterpreterPushArgsAndReturnAddress(masm, eax, ecx, edx, edi, false,
868f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch                                               2, &stack_overflow);
869014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
870f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Restore edi and edx
871f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ Pop(edx);
872f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ Pop(edi);
873f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
874f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ AssertUndefinedOrAllocationSite(ebx);
87562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  if (mode == InterpreterPushArgsMode::kJSFunction) {
876f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // Tail call to the function-specific construct stub (still in the caller
877f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // context at this point).
878f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ AssertFunction(edi);
879f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
880f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
881f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset));
882f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
883f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ jmp(ecx);
88462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  } else if (mode == InterpreterPushArgsMode::kWithFinalSpread) {
88562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // Call the constructor with unmodified eax, edi, edx values.
88662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ Jump(masm->isolate()->builtins()->ConstructWithSpread(),
88762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch            RelocInfo::CODE_TARGET);
888f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  } else {
88962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    DCHECK_EQ(InterpreterPushArgsMode::kOther, mode);
890f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // Call the constructor with unmodified eax, edi, edx values.
891f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
892f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  }
893f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
894f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ bind(&stack_overflow);
895f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  {
896f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // Pop the temporary registers, so that return address is on top of stack.
897f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ Pop(edx);
898f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ Pop(edi);
899f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
900f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ TailCallRuntime(Runtime::kThrowStackOverflow);
901f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
902f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // This should be unreachable.
903f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ int3();
904f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  }
905f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch}
906f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
907f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch// static
908f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdochvoid Builtins::Generate_InterpreterPushArgsAndConstructArray(
909f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    MacroAssembler* masm) {
910f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // ----------- S t a t e -------------
911f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  //  -- eax : the number of arguments (not including the receiver)
912f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  //  -- edx : the target to call checked to be Array function.
913f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  //  -- ebx : the allocation site feedback
914f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  //  -- ecx : the address of the first argument to be pushed. Subsequent
915f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  //           arguments should be consecutive above this, in the same order as
916f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  //           they are to be pushed onto the stack.
917f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // -----------------------------------
918f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  Label stack_overflow;
919f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // We need two scratch registers. Register edi is available, push edx onto
920f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // stack.
921f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ Push(edx);
922f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
923f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Push arguments and move return address to the top of stack.
924f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // The eax register is readonly. The ecx register will be modified. The edx
925f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // and edi registers will be modified but restored to their original values.
926f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  Generate_InterpreterPushArgsAndReturnAddress(masm, eax, ecx, edx, edi, true,
927f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch                                               1, &stack_overflow);
928014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
929f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Restore edx.
930f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ Pop(edx);
931014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
932f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Array constructor expects constructor in edi. It is same as edx here.
933f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ Move(edi, edx);
934014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
935f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  ArrayConstructorStub stub(masm->isolate());
936f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ TailCallStub(&stub);
937014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
938f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ bind(&stack_overflow);
939f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  {
940f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // Pop the temporary registers, so that return address is on top of stack.
941f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ Pop(edx);
942f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
943f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ TailCallRuntime(Runtime::kThrowStackOverflow);
944f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
945f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // This should be unreachable.
946f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ int3();
947f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  }
948014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
949014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
950c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdochstatic void Generate_InterpreterEnterBytecode(MacroAssembler* masm) {
951bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Set the return address to the correct point in the interpreter entry
952bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // trampoline.
953bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Smi* interpreter_entry_return_pc_offset(
954bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch      masm->isolate()->heap()->interpreter_entry_return_pc_offset());
955c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  DCHECK_NE(interpreter_entry_return_pc_offset, Smi::kZero);
956bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ LoadHeapObject(ebx,
957bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch                    masm->isolate()->builtins()->InterpreterEntryTrampoline());
958bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ add(ebx, Immediate(interpreter_entry_return_pc_offset->value() +
959bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch                        Code::kHeaderSize - kHeapObjectTag));
960bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ push(ebx);
961014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
962bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Initialize the dispatch table register.
963bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(kInterpreterDispatchTableRegister,
964bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch         Immediate(ExternalReference::interpreter_dispatch_table_address(
965bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch             masm->isolate())));
966014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
967014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Get the bytecode array pointer from the frame.
968014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(kInterpreterBytecodeArrayRegister,
969bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch         Operand(ebp, InterpreterFrameConstants::kBytecodeArrayFromFp));
970014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
971014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (FLAG_debug_code) {
972014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Check function data field is actually a BytecodeArray object.
973014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ AssertNotSmi(kInterpreterBytecodeArrayRegister);
974014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CmpObjectType(kInterpreterBytecodeArrayRegister, BYTECODE_ARRAY_TYPE,
975014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                     ebx);
976014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
977014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
978014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
979014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Get the target bytecode offset from the frame.
980bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(kInterpreterBytecodeOffsetRegister,
981bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch         Operand(ebp, InterpreterFrameConstants::kBytecodeOffsetFromFp));
982014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ SmiUntag(kInterpreterBytecodeOffsetRegister);
983014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
984014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Dispatch to the target bytecode.
985bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ movzx_b(ebx, Operand(kInterpreterBytecodeArrayRegister,
986014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                          kInterpreterBytecodeOffsetRegister, times_1, 0));
987bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(ebx, Operand(kInterpreterDispatchTableRegister, ebx,
988bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch                      times_pointer_size, 0));
989014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ jmp(ebx);
990014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
991014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
992c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdochvoid Builtins::Generate_InterpreterEnterBytecodeAdvance(MacroAssembler* masm) {
993c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // Advance the current bytecode offset stored within the given interpreter
994c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // stack frame. This simulates what all bytecode handlers do upon completion
995c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // of the underlying operation.
996c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ mov(ebx, Operand(ebp, InterpreterFrameConstants::kBytecodeArrayFromFp));
997c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ mov(edx, Operand(ebp, InterpreterFrameConstants::kBytecodeOffsetFromFp));
998c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
999c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  {
1000c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
1001c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    __ Push(kInterpreterAccumulatorRegister);
1002c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    __ Push(ebx);  // First argument is the bytecode array.
1003c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    __ Push(edx);  // Second argument is the bytecode offset.
1004c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    __ CallRuntime(Runtime::kInterpreterAdvanceBytecodeOffset);
1005c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    __ Move(edx, eax);  // Result is the new bytecode offset.
1006c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    __ Pop(kInterpreterAccumulatorRegister);
1007c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  }
1008c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ mov(Operand(ebp, InterpreterFrameConstants::kBytecodeOffsetFromFp), edx);
1009c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch
1010c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  Generate_InterpreterEnterBytecode(masm);
1011c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch}
1012c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch
1013c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdochvoid Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
1014c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  Generate_InterpreterEnterBytecode(masm);
1015c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch}
1016c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch
1017014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_CompileLazy(MacroAssembler* masm) {
1018bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // ----------- S t a t e -------------
1019bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- eax : argument count (preserved for callee)
1020bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- edx : new target (preserved for callee)
1021bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- edi : target function (preserved for callee)
1022bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // -----------------------------------
1023bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // First lookup code, maybe we don't need to compile!
1024bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Label gotta_call_runtime, gotta_call_runtime_no_stack;
1025bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Label try_shared;
1026bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Label loop_top, loop_bottom;
1027bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1028bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Register closure = edi;
1029bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Register new_target = edx;
1030bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Register argument_count = eax;
1031bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
103262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // Do we have a valid feedback vector?
103362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ mov(ebx, FieldOperand(closure, JSFunction::kFeedbackVectorOffset));
103462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ mov(ebx, FieldOperand(ebx, Cell::kValueOffset));
103562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ cmp(ebx, masm->isolate()->factory()->undefined_value());
103662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ j(equal, &gotta_call_runtime_no_stack);
103762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
1038bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ push(argument_count);
1039bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ push(new_target);
1040bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ push(closure);
1041bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1042bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Register map = argument_count;
1043bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Register index = ebx;
1044bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(map, FieldOperand(closure, JSFunction::kSharedFunctionInfoOffset));
1045bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(map, FieldOperand(map, SharedFunctionInfo::kOptimizedCodeMapOffset));
1046bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(index, FieldOperand(map, FixedArray::kLengthOffset));
1047bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ cmp(index, Immediate(Smi::FromInt(2)));
104862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ j(less, &try_shared);
1049bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1050bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // edx : native context
1051bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // ebx : length / index
1052bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // eax : optimized code map
1053bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // stack[0] : new target
1054bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // stack[4] : closure
1055bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Register native_context = edx;
1056bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(native_context, NativeContextOperand());
1057bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1058bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ bind(&loop_top);
1059bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Register temp = edi;
1060bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1061bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Does the native context match?
1062bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(temp, FieldOperand(map, index, times_half_pointer_size,
1063bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch                            SharedFunctionInfo::kOffsetToPreviousContext));
1064bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(temp, FieldOperand(temp, WeakCell::kValueOffset));
1065bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ cmp(temp, native_context);
1066bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ j(not_equal, &loop_bottom);
1067bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Code available?
1068bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Register entry = ecx;
1069bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(entry, FieldOperand(map, index, times_half_pointer_size,
1070bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch                             SharedFunctionInfo::kOffsetToPreviousCachedCode));
1071bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(entry, FieldOperand(entry, WeakCell::kValueOffset));
1072c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ JumpIfSmi(entry, &try_shared);
1073bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
107462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // Found code. Get it into the closure and return.
1075bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ pop(closure);
1076bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Store code entry in the closure.
1077bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ lea(entry, FieldOperand(entry, Code::kHeaderSize));
1078bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(FieldOperand(closure, JSFunction::kCodeEntryOffset), entry);
1079bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ RecordWriteCodeEntryField(closure, entry, eax);
1080bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1081bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Link the closure into the optimized function list.
1082bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // ecx : code entry
1083bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // edx : native context
1084bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // edi : closure
1085bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(ebx,
1086bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch         ContextOperand(native_context, Context::OPTIMIZED_FUNCTIONS_LIST));
1087bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(FieldOperand(closure, JSFunction::kNextFunctionLinkOffset), ebx);
1088bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ RecordWriteField(closure, JSFunction::kNextFunctionLinkOffset, ebx, eax,
1089bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch                      kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
1090bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  const int function_list_offset =
1091bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch      Context::SlotOffset(Context::OPTIMIZED_FUNCTIONS_LIST);
1092bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(ContextOperand(native_context, Context::OPTIMIZED_FUNCTIONS_LIST),
1093bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch         closure);
1094bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Save closure before the write barrier.
1095bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(ebx, closure);
1096bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ RecordWriteContextSlot(native_context, function_list_offset, closure, eax,
1097bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch                            kDontSaveFPRegs);
1098bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(closure, ebx);
1099bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ pop(new_target);
1100bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ pop(argument_count);
1101bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ jmp(entry);
1102bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1103bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ bind(&loop_bottom);
1104bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ sub(index, Immediate(Smi::FromInt(SharedFunctionInfo::kEntryLength)));
1105bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ cmp(index, Immediate(Smi::FromInt(1)));
1106bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ j(greater, &loop_top);
1107bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
110862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // We found no code.
1109bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ jmp(&gotta_call_runtime);
1110bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1111bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ bind(&try_shared);
1112c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ pop(closure);
1113bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ pop(new_target);
1114bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ pop(argument_count);
1115bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(entry, FieldOperand(closure, JSFunction::kSharedFunctionInfoOffset));
1116c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // Is the shared function marked for tier up?
1117c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ test_b(FieldOperand(entry, SharedFunctionInfo::kMarkedForTierUpByteOffset),
1118c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch            Immediate(1 << SharedFunctionInfo::kMarkedForTierUpBitWithinByte));
1119c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ j(not_zero, &gotta_call_runtime_no_stack);
112062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
112162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // If SFI points to anything other than CompileLazy, install that.
1122bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(entry, FieldOperand(entry, SharedFunctionInfo::kCodeOffset));
112362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ Move(ebx, masm->CodeObject());
112462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ cmp(entry, ebx);
1125bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ j(equal, &gotta_call_runtime_no_stack);
112662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
112762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // Install the SFI's code entry.
1128bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ lea(entry, FieldOperand(entry, Code::kHeaderSize));
1129bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(FieldOperand(closure, JSFunction::kCodeEntryOffset), entry);
1130bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ RecordWriteCodeEntryField(closure, entry, ebx);
1131bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ jmp(entry);
1132bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1133bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ bind(&gotta_call_runtime);
1134bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ pop(closure);
1135bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ pop(new_target);
1136bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ pop(argument_count);
1137bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ bind(&gotta_call_runtime_no_stack);
1138bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1139109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy);
1140b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1141b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1142bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdochvoid Builtins::Generate_CompileBaseline(MacroAssembler* masm) {
1143bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  GenerateTailCallToReturnedCode(masm, Runtime::kCompileBaseline);
1144bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch}
1145b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1146b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
1147109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  GenerateTailCallToReturnedCode(masm,
1148109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                                 Runtime::kCompileOptimized_NotConcurrent);
1149b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1150b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1151b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) {
1152109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  GenerateTailCallToReturnedCode(masm, Runtime::kCompileOptimized_Concurrent);
1153b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1154b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1155f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochvoid Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
1156f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // ----------- S t a t e -------------
1157f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  //  -- eax : argument count (preserved for callee)
1158f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  //  -- edx : new target (preserved for callee)
1159f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  //  -- edi : target function (preserved for callee)
1160f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // -----------------------------------
1161f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  Label failed;
1162f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  {
1163f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
1164f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // Preserve argument count for later compare.
1165f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ mov(ecx, eax);
1166f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // Push the number of arguments to the callee.
1167f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ SmiTag(eax);
1168f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ push(eax);
1169f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // Push a copy of the target function and the new target.
1170f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ push(edi);
1171f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ push(edx);
1172f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
1173f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // The function.
1174f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ push(edi);
1175f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // Copy arguments from caller (stdlib, foreign, heap).
1176f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    Label args_done;
1177f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    for (int j = 0; j < 4; ++j) {
1178f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      Label over;
1179f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      if (j < 3) {
1180f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        __ cmp(ecx, Immediate(j));
1181f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        __ j(not_equal, &over, Label::kNear);
1182f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      }
1183f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      for (int i = j - 1; i >= 0; --i) {
1184f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        __ Push(Operand(
1185f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch            ebp, StandardFrameConstants::kCallerSPOffset + i * kPointerSize));
1186f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      }
1187f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      for (int i = 0; i < 3 - j; ++i) {
1188f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        __ PushRoot(Heap::kUndefinedValueRootIndex);
1189f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      }
1190f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      if (j < 3) {
1191f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        __ jmp(&args_done, Label::kNear);
1192f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        __ bind(&over);
1193f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      }
1194f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    }
1195f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ bind(&args_done);
1196f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
1197f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // Call runtime, on success unwind frame, and parent frame.
1198f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ CallRuntime(Runtime::kInstantiateAsmJs, 4);
1199f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // A smi 0 is returned on failure, an object on success.
1200f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ JumpIfSmi(eax, &failed, Label::kNear);
1201f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
1202f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ Drop(2);
1203f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ Pop(ecx);
1204f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ SmiUntag(ecx);
1205f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    scope.GenerateLeaveFrame();
1206f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
1207f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ PopReturnAddressTo(ebx);
1208f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ inc(ecx);
1209f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ lea(esp, Operand(esp, ecx, times_pointer_size, 0));
1210f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ PushReturnAddressFrom(ebx);
1211f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ ret(0);
1212f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
1213f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ bind(&failed);
1214f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // Restore target function and new target.
1215f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ pop(edx);
1216f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ pop(edi);
1217f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ pop(eax);
1218f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ SmiUntag(eax);
1219f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
1220f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // On failure, tail call back to regular js.
1221f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy);
1222f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}
1223b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1224b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochstatic void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
1225b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // For now, we are relying on the fact that make_code_young doesn't do any
1226b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // garbage collection which allows us to save/restore the registers without
1227b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // worrying about which of them contain pointers. We also don't build an
1228b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // internal frame to make the code faster, since we shouldn't have to do stack
1229b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // crawls in MakeCodeYoung. This seems a bit fragile.
1230b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1231b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Re-execute the code that was patched back to the young age when
1232b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // the stub returns.
1233b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ sub(Operand(esp, 0), Immediate(5));
1234b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ pushad();
1235b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(eax, Operand(esp, 8 * kPointerSize));
1236b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  {
1237b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    FrameScope scope(masm, StackFrame::MANUAL);
1238b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ PrepareCallCFunction(2, ebx);
1239b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ mov(Operand(esp, 1 * kPointerSize),
1240b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch           Immediate(ExternalReference::isolate_address(masm->isolate())));
1241b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ mov(Operand(esp, 0), eax);
1242b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ CallCFunction(
1243b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        ExternalReference::get_make_code_young_function(masm->isolate()), 2);
1244b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1245b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ popad();
1246b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ ret(0);
1247b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1248b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
124962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C)                              \
125062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  void Builtins::Generate_Make##C##CodeYoungAgain(MacroAssembler* masm) { \
125162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    GenerateMakeCodeYoungAgainCommon(masm);                               \
1252f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
1253b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochCODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
1254b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
1255b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1256b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
1257b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact
1258b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // that make_code_young doesn't do any garbage collection which allows us to
1259b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // save/restore the registers without worrying about which of them contain
1260b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // pointers.
1261b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ pushad();
1262b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(eax, Operand(esp, 8 * kPointerSize));
1263b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ sub(eax, Immediate(Assembler::kCallInstructionLength));
1264b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  {  // NOLINT
1265b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    FrameScope scope(masm, StackFrame::MANUAL);
1266b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ PrepareCallCFunction(2, ebx);
1267b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ mov(Operand(esp, 1 * kPointerSize),
1268b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch           Immediate(ExternalReference::isolate_address(masm->isolate())));
1269b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ mov(Operand(esp, 0), eax);
1270b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ CallCFunction(
1271b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        ExternalReference::get_mark_code_as_executed_function(masm->isolate()),
1272b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        2);
1273b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1274b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ popad();
1275b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1276b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Perform prologue operations usually performed by the young code stub.
1277b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ pop(eax);   // Pop return address into scratch register.
1278b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ push(ebp);  // Caller's frame pointer.
1279b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(ebp, esp);
1280b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ push(esi);  // Callee's context.
1281b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ push(edi);  // Callee's JS Function.
1282b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ push(eax);  // Push return address after frame prologue.
1283b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1284b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Jump to point after the code-age stub.
1285b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ ret(0);
1286b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1287b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1288b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
1289b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  GenerateMakeCodeYoungAgainCommon(masm);
1290b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1291b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1292014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_MarkCodeAsToBeExecutedOnce(MacroAssembler* masm) {
1293014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Generate_MarkCodeAsExecutedOnce(masm);
1294014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
1295014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1296b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochstatic void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
1297b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                             SaveFPRegsMode save_doubles) {
1298b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Enter an internal frame.
1299b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  {
1300b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
1301b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1302b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Preserve registers across notification, this is important for compiled
1303b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // stubs that tail call the runtime on deopts passing their parameters in
1304b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // registers.
1305b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ pushad();
1306014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CallRuntime(Runtime::kNotifyStubFailure, save_doubles);
1307b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ popad();
1308b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Tear down internal frame.
1309b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1310b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1311b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ pop(MemOperand(esp, 0));  // Ignore state offset
1312b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ ret(0);  // Return to IC Miss stub, continuation still on stack.
1313b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1314b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1315b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
1316b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
1317b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1318b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1319b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
1320b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
1321b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1322b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1323b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochstatic void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
1324b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                             Deoptimizer::BailoutType type) {
1325b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  {
1326b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
1327b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1328b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Pass deoptimization type to the runtime system.
1329b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ push(Immediate(Smi::FromInt(static_cast<int>(type))));
1330014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CallRuntime(Runtime::kNotifyDeoptimized);
1331b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1332b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Tear down internal frame.
1333b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1334b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1335b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Get the full codegen state from the stack and untag it.
1336b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(ecx, Operand(esp, 1 * kPointerSize));
1337b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ SmiUntag(ecx);
1338b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1339b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Switch on the state.
1340b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Label not_no_registers, not_tos_eax;
1341bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ cmp(ecx, static_cast<int>(Deoptimizer::BailoutState::NO_REGISTERS));
1342b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ j(not_equal, &not_no_registers, Label::kNear);
1343b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ ret(1 * kPointerSize);  // Remove state.
1344b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1345b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ bind(&not_no_registers);
1346bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  DCHECK_EQ(kInterpreterAccumulatorRegister.code(), eax.code());
1347b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(eax, Operand(esp, 2 * kPointerSize));
1348bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ cmp(ecx, static_cast<int>(Deoptimizer::BailoutState::TOS_REGISTER));
1349b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ j(not_equal, &not_tos_eax, Label::kNear);
1350b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ ret(2 * kPointerSize);  // Remove state, eax.
1351b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1352b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ bind(&not_tos_eax);
1353b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ Abort(kNoCasesLeft);
1354b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1355b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1356b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
1357b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
1358b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1359b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1360b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
1361b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
1362b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1363b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1364b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
1365b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
1366b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1367b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1368014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
1369014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
1370014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
1371014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax     : argc
1372014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[0]  : return address
1373014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[4]  : argArray
1374014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[8]  : thisArg
1375014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[12] : receiver
1376014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
1377014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1378014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 1. Load receiver into edi, argArray into eax (if present), remove all
1379014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // arguments from the stack (including the receiver), and push thisArg (if
1380014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // present) instead.
1381014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1382014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label no_arg_array, no_this_arg;
1383014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
1384014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ebx, edx);
1385014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize));
1386014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ test(eax, eax);
1387014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(zero, &no_this_arg, Label::kNear);
1388014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    {
1389014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ mov(edx, Operand(esp, eax, times_pointer_size, 0));
1390014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ cmp(eax, Immediate(1));
1391014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ j(equal, &no_arg_array, Label::kNear);
1392014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ mov(ebx, Operand(esp, eax, times_pointer_size, -kPointerSize));
1393014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ bind(&no_arg_array);
1394b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
1395014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&no_this_arg);
1396014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PopReturnAddressTo(ecx);
1397014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1398014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Push(edx);
1399014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PushReturnAddressFrom(ecx);
1400014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Move(eax, ebx);
1401014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
1402014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1403014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
1404014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax    : argArray
1405014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi    : receiver
1406014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[0] : return address
1407014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[4] : thisArg
1408014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
1409b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1410014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 2. Make sure the receiver is actually callable.
1411014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label receiver_not_callable;
1412014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ JumpIfSmi(edi, &receiver_not_callable, Label::kNear);
1413014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
14143b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
14153b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch            Immediate(1 << Map::kIsCallable));
1416014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(zero, &receiver_not_callable, Label::kNear);
1417b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1418014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 3. Tail call with no arguments if argArray is null or undefined.
1419014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label no_arguments;
1420014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ JumpIfRoot(eax, Heap::kNullValueRootIndex, &no_arguments, Label::kNear);
1421014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ JumpIfRoot(eax, Heap::kUndefinedValueRootIndex, &no_arguments,
1422014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                Label::kNear);
1423b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1424014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 4a. Apply the receiver to the given argArray (passing undefined for
1425014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // new.target).
1426014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
1427014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1428b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1429014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 4b. The argArray is either null or undefined, so we tail call without any
1430014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // arguments to the receiver.
1431014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&no_arguments);
1432014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1433014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Set(eax, 0);
1434014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1435b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1436b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1437014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 4c. The receiver is not callable, throw an appropriate TypeError.
1438014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&receiver_not_callable);
1439014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1440014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(Operand(esp, kPointerSize), edi);
1441014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ TailCallRuntime(Runtime::kThrowApplyNonFunction);
1442014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
1443014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
1444014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1445014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
1446014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) {
1447014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Stack Layout:
1448014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // esp[0]           : Return address
1449014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // esp[8]           : Argument n
1450014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // esp[16]          : Argument n-1
1451014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  ...
1452014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // esp[8 * n]       : Argument 1
1453014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // esp[8 * (n + 1)] : Receiver (callable to call)
1454014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //
1455014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // eax contains the number of arguments, n, not counting the receiver.
1456014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //
1457014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 1. Make sure we have at least one argument.
1458014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1459014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label done;
1460014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ test(eax, eax);
1461014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(not_zero, &done, Label::kNear);
1462014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PopReturnAddressTo(ebx);
1463014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PushRoot(Heap::kUndefinedValueRootIndex);
1464014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PushReturnAddressFrom(ebx);
1465014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ inc(eax);
1466014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&done);
1467014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
1468b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1469014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 2. Get the callable to call (passed as receiver) from the stack.
1470014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize));
1471b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1472014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 3. Shift arguments and return address one slot down on the stack
1473b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //    (overwriting the original receiver).  Adjust argument count to make
1474b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //    the original first argument the new receiver.
1475014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1476014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label loop;
1477b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ mov(ecx, eax);
1478b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ bind(&loop);
1479014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ebx, Operand(esp, ecx, times_pointer_size, 0));
1480014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(Operand(esp, ecx, times_pointer_size, kPointerSize), ebx);
1481b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ dec(ecx);
1482b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ j(not_sign, &loop);  // While non-negative (to copy return address).
1483014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ pop(ebx);            // Discard copy of return address.
1484b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ dec(eax);  // One fewer argument (first argument is new receiver).
1485b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1486b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1487014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 4. Call the callable.
1488014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1489b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1490b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1491014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_ReflectApply(MacroAssembler* masm) {
1492014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
1493014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax     : argc
1494014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[0]  : return address
1495014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[4]  : argumentsList
1496014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[8]  : thisArgument
1497014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[12] : target
1498014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[16] : receiver
1499014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
1500b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1501014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 1. Load target into edi (if present), argumentsList into eax (if present),
1502014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // remove all arguments from the stack (including the receiver), and push
1503014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // thisArgument (if present) instead.
1504014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1505014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label done;
1506014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ LoadRoot(edi, Heap::kUndefinedValueRootIndex);
1507014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(edx, edi);
1508014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ebx, edi);
1509014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(eax, Immediate(1));
1510014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(below, &done, Label::kNear);
1511014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(edi, Operand(esp, eax, times_pointer_size, -0 * kPointerSize));
1512014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(equal, &done, Label::kNear);
1513014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(edx, Operand(esp, eax, times_pointer_size, -1 * kPointerSize));
1514014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(eax, Immediate(3));
1515014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(below, &done, Label::kNear);
1516014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ebx, Operand(esp, eax, times_pointer_size, -2 * kPointerSize));
1517014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&done);
1518014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PopReturnAddressTo(ecx);
1519014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1520014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Push(edx);
1521014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PushReturnAddressFrom(ecx);
1522014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Move(eax, ebx);
1523014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
1524b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1525014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
1526014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax    : argumentsList
1527014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi    : target
1528014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[0] : return address
1529014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[4] : thisArgument
1530014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
1531b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1532014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 2. Make sure the target is actually callable.
1533014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label target_not_callable;
1534014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ JumpIfSmi(edi, &target_not_callable, Label::kNear);
1535014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
15363b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
15373b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch            Immediate(1 << Map::kIsCallable));
1538014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(zero, &target_not_callable, Label::kNear);
1539b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1540014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 3a. Apply the target to the given argumentsList (passing undefined for
1541014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // new.target).
1542014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
1543014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1544b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1545014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 3b. The target is not callable, throw an appropriate TypeError.
1546014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&target_not_callable);
1547014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1548014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(Operand(esp, kPointerSize), edi);
1549014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ TailCallRuntime(Runtime::kThrowApplyNonFunction);
1550014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
1551014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
1552b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1553014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
1554014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
1555014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax     : argc
1556014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[0]  : return address
1557014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[4]  : new.target (optional)
1558014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[8]  : argumentsList
1559014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[12] : target
1560014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[16] : receiver
1561014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
1562b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1563014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 1. Load target into edi (if present), argumentsList into eax (if present),
1564014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // new.target into edx (if present, otherwise use target), remove all
1565014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // arguments from the stack (including the receiver), and push thisArgument
1566014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // (if present) instead.
1567014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1568014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label done;
1569014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ LoadRoot(edi, Heap::kUndefinedValueRootIndex);
1570014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(edx, edi);
1571014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ebx, edi);
1572014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(eax, Immediate(1));
1573014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(below, &done, Label::kNear);
1574014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(edi, Operand(esp, eax, times_pointer_size, -0 * kPointerSize));
1575014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(edx, edi);
1576014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(equal, &done, Label::kNear);
1577014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ebx, Operand(esp, eax, times_pointer_size, -1 * kPointerSize));
1578014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(eax, Immediate(3));
1579014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(below, &done, Label::kNear);
1580014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(edx, Operand(esp, eax, times_pointer_size, -2 * kPointerSize));
1581014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&done);
1582014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PopReturnAddressTo(ecx);
1583014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1584014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PushRoot(Heap::kUndefinedValueRootIndex);
1585014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PushReturnAddressFrom(ecx);
1586014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Move(eax, ebx);
1587014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
1588b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1589014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
1590014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax    : argumentsList
1591014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx    : new.target
1592014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi    : target
1593014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[0] : return address
1594014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[4] : receiver (undefined)
1595014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
1596b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1597014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 2. Make sure the target is actually a constructor.
1598014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label target_not_constructor;
1599014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ JumpIfSmi(edi, &target_not_constructor, Label::kNear);
1600014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
16013b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
16023b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch            Immediate(1 << Map::kIsConstructor));
1603014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(zero, &target_not_constructor, Label::kNear);
1604014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1605014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 3. Make sure the target is actually a constructor.
1606014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label new_target_not_constructor;
1607014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ JumpIfSmi(edx, &new_target_not_constructor, Label::kNear);
1608014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
16093b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
16103b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch            Immediate(1 << Map::kIsConstructor));
1611014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(zero, &new_target_not_constructor, Label::kNear);
1612014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1613014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 4a. Construct the target with the given new.target and argumentsList.
1614014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1615014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1616014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 4b. The target is not a constructor, throw an appropriate TypeError.
1617014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&target_not_constructor);
1618014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1619014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(Operand(esp, kPointerSize), edi);
162062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ TailCallRuntime(Runtime::kThrowNotConstructor);
1621014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
1622b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1623014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 4c. The new.target is not a constructor, throw an appropriate TypeError.
1624014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&new_target_not_constructor);
1625014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1626014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(Operand(esp, kPointerSize), edx);
162762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ TailCallRuntime(Runtime::kThrowNotConstructor);
1628b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1629b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1630b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1631b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
1632b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // ----------- S t a t e -------------
1633b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- eax : argc
1634b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- esp[0] : return address
1635b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- esp[4] : last argument
1636b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // -----------------------------------
1637b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Label generic_array_code;
1638b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1639b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Get the InternalArray function.
1640b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi);
1641b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1642b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (FLAG_debug_code) {
1643b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Initial map for the builtin InternalArray function should be a map.
1644b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1645b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Will both indicate a NULL and a Smi.
1646b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ test(ebx, Immediate(kSmiTagMask));
1647b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ Assert(not_zero, kUnexpectedInitialMapForInternalArrayFunction);
1648b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ CmpObjectType(ebx, MAP_TYPE, ecx);
1649b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ Assert(equal, kUnexpectedInitialMapForInternalArrayFunction);
1650b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1651b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1652b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Run the native code for the InternalArray function called as a normal
1653b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // function.
1654b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // tail call a stub
1655b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  InternalArrayConstructorStub stub(masm->isolate());
1656b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ TailCallStub(&stub);
1657b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1658b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1659b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Builtins::Generate_ArrayCode(MacroAssembler* masm) {
1660b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // ----------- S t a t e -------------
1661b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- eax : argc
1662b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- esp[0] : return address
1663b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- esp[4] : last argument
1664b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // -----------------------------------
1665b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Label generic_array_code;
1666b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1667b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Get the Array function.
1668b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi);
1669014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(edx, edi);
1670b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1671b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (FLAG_debug_code) {
1672b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Initial map for the builtin Array function should be a map.
1673b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1674b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Will both indicate a NULL and a Smi.
1675b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ test(ebx, Immediate(kSmiTagMask));
1676b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction);
1677b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ CmpObjectType(ebx, MAP_TYPE, ecx);
1678b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ Assert(equal, kUnexpectedInitialMapForArrayFunction);
1679b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1680b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1681b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Run the native code for the Array function called as a normal function.
1682b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // tail call a stub
1683b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(ebx, masm->isolate()->factory()->undefined_value());
1684b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  ArrayConstructorStub stub(masm->isolate());
1685b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ TailCallStub(&stub);
1686b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1687b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1688014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
1689109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochvoid Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
1690109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // ----------- S t a t e -------------
1691109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  //  -- eax                 : number of arguments
169213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  //  -- edi                 : function
169313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  //  -- esi                 : context
1694109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  //  -- esp[0]              : return address
1695109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  //  -- esp[(argc - n) * 8] : arg[n] (zero-based)
1696109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  //  -- esp[(argc + 1) * 8] : receiver
1697109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // -----------------------------------
1698109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Condition const cc = (kind == MathMaxMinKind::kMin) ? below : above;
1699109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Heap::RootListIndex const root_index =
1700109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      (kind == MathMaxMinKind::kMin) ? Heap::kInfinityValueRootIndex
1701109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                                     : Heap::kMinusInfinityValueRootIndex;
1702109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  const int reg_sel = (kind == MathMaxMinKind::kMin) ? 1 : 0;
1703109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1704109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Load the accumulator with the default return value (either -Infinity or
1705109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // +Infinity), with the tagged value in edx and the double value in stx_0.
1706109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ LoadRoot(edx, root_index);
1707109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ fld_d(FieldOperand(edx, HeapNumber::kValueOffset));
1708109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ Move(ecx, eax);
1709109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1710109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Label done_loop, loop;
1711109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ bind(&loop);
1712109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  {
1713109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Check if all parameters done.
1714109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ test(ecx, ecx);
1715109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ j(zero, &done_loop);
1716109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1717109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Load the next parameter tagged value into ebx.
1718109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ mov(ebx, Operand(esp, ecx, times_pointer_size, 0));
1719109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1720109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Load the double value of the parameter into stx_1, maybe converting the
172113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    // parameter to a number first using the ToNumber builtin if necessary.
1722109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    Label convert, convert_smi, convert_number, done_convert;
1723109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ bind(&convert);
1724109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ JumpIfSmi(ebx, &convert_smi);
1725109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ JumpIfRoot(FieldOperand(ebx, HeapObject::kMapOffset),
1726109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                  Heap::kHeapNumberMapRootIndex, &convert_number);
1727109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    {
172813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      // Parameter is not a Number, use the ToNumber builtin to convert it.
172913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      FrameScope scope(masm, StackFrame::MANUAL);
1730109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ SmiTag(eax);
1731109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ SmiTag(ecx);
1732f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      __ EnterBuiltinFrame(esi, edi, eax);
1733109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ Push(ecx);
1734109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ Push(edx);
1735109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ mov(eax, ebx);
173613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      __ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
1737109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ mov(ebx, eax);
1738109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ Pop(edx);
1739109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ Pop(ecx);
1740f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      __ LeaveBuiltinFrame(esi, edi, eax);
1741f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      __ SmiUntag(ecx);
1742f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      __ SmiUntag(eax);
1743109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      {
1744109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        // Restore the double accumulator value (stX_0).
1745109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        Label restore_smi, done_restore;
1746109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        __ JumpIfSmi(edx, &restore_smi, Label::kNear);
1747109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        __ fld_d(FieldOperand(edx, HeapNumber::kValueOffset));
1748109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        __ jmp(&done_restore, Label::kNear);
1749109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        __ bind(&restore_smi);
1750109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        __ SmiUntag(edx);
1751109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        __ push(edx);
1752109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        __ fild_s(Operand(esp, 0));
1753109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        __ pop(edx);
1754109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        __ SmiTag(edx);
1755109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        __ bind(&done_restore);
1756109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      }
1757109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    }
1758109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ jmp(&convert);
1759109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ bind(&convert_number);
1760109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Load another value into stx_1
1761109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ fld_d(FieldOperand(ebx, HeapNumber::kValueOffset));
1762109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ fxch();
1763109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ jmp(&done_convert, Label::kNear);
1764109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ bind(&convert_smi);
1765109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ SmiUntag(ebx);
1766109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ push(ebx);
1767109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ fild_s(Operand(esp, 0));
1768109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ pop(ebx);
1769109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ fxch();
1770109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ SmiTag(ebx);
1771109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ bind(&done_convert);
1772109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1773109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Perform the actual comparison with the accumulator value on the left hand
1774109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // side (stx_0) and the next parameter value on the right hand side (stx_1).
1775109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    Label compare_equal, compare_nan, compare_swap, done_compare;
1776109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1777109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Duplicates the 2 float data for FCmp
1778109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ fld(1);
1779109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ fld(1);
1780109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ FCmp();
1781109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ j(parity_even, &compare_nan, Label::kNear);
1782109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ j(cc, &done_compare, Label::kNear);
1783109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ j(equal, &compare_equal, Label::kNear);
1784109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1785109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Result is on the right hand side(stx_0).
1786109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ bind(&compare_swap);
1787109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ fxch();
1788109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ mov(edx, ebx);
1789109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ jmp(&done_compare, Label::kNear);
1790109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1791109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // At least one side is NaN, which means that the result will be NaN too.
1792109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ bind(&compare_nan);
1793109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Set the result on the right hand side (stx_0) to nan
1794109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ fstp(0);
1795109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ LoadRoot(edx, Heap::kNanValueRootIndex);
1796109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ fld_d(FieldOperand(edx, HeapNumber::kValueOffset));
1797109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ jmp(&done_compare, Label::kNear);
1798109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1799109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Left and right hand side are equal, check for -0 vs. +0.
1800109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ bind(&compare_equal);
1801109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Check the sign of the value in reg_sel
1802109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ fld(reg_sel);
1803109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ FXamSign();
1804109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ j(not_zero, &compare_swap);
1805109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1806109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ bind(&done_compare);
1807109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // The right result is on the right hand side(stx_0)
1808109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // and can remove the useless stx_1 now.
1809109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ fxch();
1810109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ fstp(0);
1811109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ dec(ecx);
1812109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ jmp(&loop);
1813109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  }
1814109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1815109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ bind(&done_loop);
1816109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ PopReturnAddressTo(ecx);
1817109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1818109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ PushReturnAddressFrom(ecx);
1819109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ mov(eax, edx);
1820109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ Ret();
1821109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch}
1822109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1823109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// static
1824014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
1825b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // ----------- S t a t e -------------
1826b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- eax                 : number of arguments
1827b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- edi                 : constructor function
1828f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  //  -- esi                 : context
1829b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- esp[0]              : return address
1830b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1831b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- esp[(argc + 1) * 4] : receiver
1832b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // -----------------------------------
1833b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1834f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // 1. Load the first argument into ebx.
1835014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label no_arguments;
1836014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1837014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ test(eax, eax);
1838014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(zero, &no_arguments, Label::kNear);
1839014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1840b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1841b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1842014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 2a. Convert the first argument to a number.
1843f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  {
1844f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    FrameScope scope(masm, StackFrame::MANUAL);
1845f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ SmiTag(eax);
1846f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ EnterBuiltinFrame(esi, edi, eax);
1847f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ mov(eax, ebx);
1848f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
1849f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ LeaveBuiltinFrame(esi, edi, ebx);  // Argc popped to ebx.
1850f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ SmiUntag(ebx);
1851f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
1852f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
1853f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  {
1854f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // Drop all arguments including the receiver.
1855f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ PopReturnAddressTo(ecx);
1856f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ lea(esp, Operand(esp, ebx, times_pointer_size, kPointerSize));
1857f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ PushReturnAddressFrom(ecx);
1858f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ Ret();
1859f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
1860014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1861014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 2b. No arguments, return +0 (already in eax).
1862014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&no_arguments);
1863014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ ret(1 * kPointerSize);
1864014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
1865014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1866014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
1867014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
1868b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // ----------- S t a t e -------------
1869014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax                 : number of arguments
1870014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi                 : constructor function
1871014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx                 : new target
1872f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  //  -- esi                 : context
1873014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[0]              : return address
1874014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1875014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[(argc + 1) * 4] : receiver
1876b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // -----------------------------------
1877b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1878014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 1. Make sure we operate in the context of the called function.
1879014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1880b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1881f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // Store argc in r8.
1882f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ mov(ecx, eax);
1883f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ SmiTag(ecx);
1884f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
1885f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // 2. Load the first argument into ebx.
1886014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1887014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label no_arguments, done;
1888014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ test(eax, eax);
1889014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(zero, &no_arguments, Label::kNear);
1890014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1891014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ jmp(&done, Label::kNear);
1892014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&no_arguments);
1893c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    __ Move(ebx, Smi::kZero);
1894014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&done);
1895014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
1896b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1897014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 3. Make sure ebx is a number.
1898014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1899014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label done_convert;
1900014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ JumpIfSmi(ebx, &done_convert);
1901014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CompareRoot(FieldOperand(ebx, HeapObject::kMapOffset),
1902014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                   Heap::kHeapNumberMapRootIndex);
1903014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(equal, &done_convert);
1904014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    {
1905f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      FrameScope scope(masm, StackFrame::MANUAL);
1906f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      __ EnterBuiltinFrame(esi, edi, ecx);
1907014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ Push(edx);
1908014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ Move(eax, ebx);
190913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      __ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
1910014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ Move(ebx, eax);
1911014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ Pop(edx);
1912f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      __ LeaveBuiltinFrame(esi, edi, ecx);
1913014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
1914014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&done_convert);
1915014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
1916b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1917014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 4. Check if new target and constructor differ.
1918f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  Label drop_frame_and_ret, done_alloc, new_object;
1919014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ cmp(edx, edi);
1920014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(not_equal, &new_object);
1921b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1922014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 5. Allocate a JSValue wrapper for the number.
1923f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ AllocateJSValue(eax, edi, ebx, esi, &done_alloc);
1924f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ jmp(&drop_frame_and_ret);
1925f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
1926f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ bind(&done_alloc);
1927f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));  // Restore esi.
1928b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1929014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 6. Fallback to the runtime to create new object.
1930014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&new_object);
1931b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  {
1932f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    FrameScope scope(masm, StackFrame::MANUAL);
1933f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ EnterBuiltinFrame(esi, edi, ecx);
1934014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Push(ebx);  // the first argument
193562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ Call(CodeFactory::FastNewObject(masm->isolate()).code(),
193662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch            RelocInfo::CODE_TARGET);
1937014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Pop(FieldOperand(eax, JSValue::kValueOffset));
1938f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ LeaveBuiltinFrame(esi, edi, ecx);
1939b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1940b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1941f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ bind(&drop_frame_and_ret);
1942f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  {
1943f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // Drop all arguments including the receiver.
1944f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ PopReturnAddressTo(esi);
1945f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ SmiUntag(ecx);
1946f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ lea(esp, Operand(esp, ecx, times_pointer_size, kPointerSize));
1947f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ PushReturnAddressFrom(esi);
1948f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ Ret();
1949f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
1950f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}
1951014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1952014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
1953014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_StringConstructor(MacroAssembler* masm) {
1954014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
1955014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax                 : number of arguments
1956014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi                 : constructor function
1957f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  //  -- esi                 : context
1958014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[0]              : return address
1959014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1960014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[(argc + 1) * 4] : receiver
1961014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
1962014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1963f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // 1. Load the first argument into eax.
1964014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label no_arguments;
1965014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1966f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ mov(ebx, eax);  // Store argc in ebx.
1967014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ test(eax, eax);
1968014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(zero, &no_arguments, Label::kNear);
1969f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ mov(eax, Operand(esp, eax, times_pointer_size, 0));
1970014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
1971014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1972014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 2a. At least one argument, return eax if it's a string, otherwise
1973014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // dispatch to appropriate conversion.
1974f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  Label drop_frame_and_ret, to_string, symbol_descriptive_string;
1975014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1976014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ JumpIfSmi(eax, &to_string, Label::kNear);
1977014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    STATIC_ASSERT(FIRST_NONSTRING_TYPE == SYMBOL_TYPE);
1978014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
1979014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(above, &to_string, Label::kNear);
1980014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(equal, &symbol_descriptive_string, Label::kNear);
1981f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ jmp(&drop_frame_and_ret, Label::kNear);
1982014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
1983014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1984014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 2b. No arguments, return the empty string (and pop the receiver).
1985b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ bind(&no_arguments);
1986014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1987014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ LoadRoot(eax, Heap::kempty_stringRootIndex);
1988014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ ret(1 * kPointerSize);
1989014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
1990014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1991014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 3a. Convert eax to a string.
1992014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&to_string);
1993014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1994f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    FrameScope scope(masm, StackFrame::MANUAL);
1995f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ SmiTag(ebx);
1996f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ EnterBuiltinFrame(esi, edi, ebx);
1997f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ Call(masm->isolate()->builtins()->ToString(), RelocInfo::CODE_TARGET);
1998f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ LeaveBuiltinFrame(esi, edi, ebx);
1999f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ SmiUntag(ebx);
2000014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2001f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ jmp(&drop_frame_and_ret, Label::kNear);
2002014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2003014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 3b. Convert symbol in eax to a string.
2004014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&symbol_descriptive_string);
2005014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2006014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PopReturnAddressTo(ecx);
2007f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ lea(esp, Operand(esp, ebx, times_pointer_size, kPointerSize));
2008014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Push(eax);
2009014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PushReturnAddressFrom(ecx);
2010014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ TailCallRuntime(Runtime::kSymbolDescriptiveString);
2011014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2012014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2013f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ bind(&drop_frame_and_ret);
2014f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  {
2015f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // Drop all arguments including the receiver.
2016f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ PopReturnAddressTo(ecx);
2017f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ lea(esp, Operand(esp, ebx, times_pointer_size, kPointerSize));
2018f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ PushReturnAddressFrom(ecx);
2019f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ Ret();
2020f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
2021f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}
2022014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2023014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
2024014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
2025014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
2026014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax                 : number of arguments
2027014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi                 : constructor function
2028014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx                 : new target
2029f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  //  -- esi                 : context
2030014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[0]              : return address
2031014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
2032014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[(argc + 1) * 4] : receiver
2033014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
2034014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2035014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 1. Make sure we operate in the context of the called function.
2036014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
2037014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2038f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ mov(ebx, eax);
2039f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
2040f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // 2. Load the first argument into eax.
2041014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2042014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label no_arguments, done;
2043f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ test(ebx, ebx);
2044014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(zero, &no_arguments, Label::kNear);
2045f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ mov(eax, Operand(esp, ebx, times_pointer_size, 0));
2046014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ jmp(&done, Label::kNear);
2047014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&no_arguments);
2048f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ LoadRoot(eax, Heap::kempty_stringRootIndex);
2049014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&done);
2050014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2051014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2052f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // 3. Make sure eax is a string.
2053014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2054014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label convert, done_convert;
2055f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ JumpIfSmi(eax, &convert, Label::kNear);
2056f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx);
2057014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(below, &done_convert);
2058014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&convert);
2059014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    {
2060f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      FrameScope scope(masm, StackFrame::MANUAL);
2061f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      __ SmiTag(ebx);
2062f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      __ EnterBuiltinFrame(esi, edi, ebx);
2063014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ Push(edx);
2064f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch      __ Call(masm->isolate()->builtins()->ToString(), RelocInfo::CODE_TARGET);
2065014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ Pop(edx);
2066f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      __ LeaveBuiltinFrame(esi, edi, ebx);
2067f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      __ SmiUntag(ebx);
2068014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
2069014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&done_convert);
2070014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2071014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2072014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 4. Check if new target and constructor differ.
2073f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  Label drop_frame_and_ret, done_alloc, new_object;
2074014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ cmp(edx, edi);
2075014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(not_equal, &new_object);
2076b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2077014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 5. Allocate a JSValue wrapper for the string.
2078f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // AllocateJSValue can't handle src == dst register. Reuse esi and restore it
2079f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // as needed after the call.
2080f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ mov(esi, eax);
2081f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ AllocateJSValue(eax, edi, esi, ecx, &done_alloc);
2082f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ jmp(&drop_frame_and_ret);
2083f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
2084f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ bind(&done_alloc);
2085f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  {
2086f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // Restore eax to the first argument and esi to the context.
2087f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ mov(eax, esi);
2088f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
2089f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
2090014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2091014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 6. Fallback to the runtime to create new object.
2092014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&new_object);
2093b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  {
2094f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    FrameScope scope(masm, StackFrame::MANUAL);
2095f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ SmiTag(ebx);
2096f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ EnterBuiltinFrame(esi, edi, ebx);
2097f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ Push(eax);  // the first argument
209862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ Call(CodeFactory::FastNewObject(masm->isolate()).code(),
209962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch            RelocInfo::CODE_TARGET);
2100014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Pop(FieldOperand(eax, JSValue::kValueOffset));
2101f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ LeaveBuiltinFrame(esi, edi, ebx);
2102f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ SmiUntag(ebx);
2103b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
2104b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2105f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ bind(&drop_frame_and_ret);
2106f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  {
2107f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // Drop all arguments including the receiver.
2108f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ PopReturnAddressTo(ecx);
2109f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ lea(esp, Operand(esp, ebx, times_pointer_size, kPointerSize));
2110f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ PushReturnAddressFrom(ecx);
2111f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ Ret();
2112f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
2113f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}
2114b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2115b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochstatic void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
2116b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ push(ebp);
2117b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(ebp, esp);
2118b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2119b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Store the arguments adaptor context sentinel.
2120b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2121b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2122b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Push the function on the stack.
2123b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ push(edi);
2124b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2125b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Preserve the number of arguments on the stack. Must preserve eax,
2126b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // ebx and ecx because these registers are used when copying the
2127b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // arguments and the receiver.
2128b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  STATIC_ASSERT(kSmiTagSize == 1);
2129b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ lea(edi, Operand(eax, eax, times_1, kSmiTag));
2130b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ push(edi);
2131b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
2132b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2133b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochstatic void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
2134b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Retrieve the number of arguments from the stack.
2135b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
2136b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2137b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Leave the frame.
2138b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ leave();
2139b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2140b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Remove caller arguments from the stack.
2141b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
2142b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ pop(ecx);
2143b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize));  // 1 ~ receiver
2144b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ push(ecx);
2145b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
2146b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2147014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
2148014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_Apply(MacroAssembler* masm) {
2149014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
2150014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax    : argumentsList
2151014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi    : target
2152014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx    : new.target (checked to be constructor or undefined)
2153014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[0] : return address.
2154014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[4] : thisArgument
2155014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
2156014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2157014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Create the list of arguments from the array-like argumentsList.
2158014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
215962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Label create_arguments, create_array, create_holey_array, create_runtime,
216062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch        done_create;
2161014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ JumpIfSmi(eax, &create_runtime);
2162014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2163014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Load the map of argumentsList into ecx.
2164014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
2165014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2166014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Load native context into ebx.
2167014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ebx, NativeContextOperand());
2168014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2169014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Check if argumentsList is an (unmodified) arguments object.
2170014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(ecx, ContextOperand(ebx, Context::SLOPPY_ARGUMENTS_MAP_INDEX));
2171014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(equal, &create_arguments);
2172014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(ecx, ContextOperand(ebx, Context::STRICT_ARGUMENTS_MAP_INDEX));
2173014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(equal, &create_arguments);
2174014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2175014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Check if argumentsList is a fast JSArray.
2176014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CmpInstanceType(ecx, JS_ARRAY_TYPE);
2177014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(equal, &create_array);
2178014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2179014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Ask the runtime to create the list (actually a FixedArray).
2180014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&create_runtime);
2181014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    {
2182014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      FrameScope scope(masm, StackFrame::INTERNAL);
2183014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ Push(edi);
2184014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ Push(edx);
2185014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ Push(eax);
2186014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ CallRuntime(Runtime::kCreateListFromArrayLike);
2187014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ Pop(edx);
2188014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ Pop(edi);
2189014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ mov(ebx, FieldOperand(eax, FixedArray::kLengthOffset));
2190014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ SmiUntag(ebx);
2191014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
2192014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ jmp(&done_create);
2193014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2194014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Try to create the list from an arguments object.
2195014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&create_arguments);
2196109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ mov(ebx, FieldOperand(eax, JSArgumentsObject::kLengthOffset));
2197014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ecx, FieldOperand(eax, JSObject::kElementsOffset));
2198014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
2199014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(not_equal, &create_runtime);
2200014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ SmiUntag(ebx);
2201014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(eax, ecx);
2202014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ jmp(&done_create);
2203014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
220462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // For holey JSArrays we need to check that the array prototype chain
220562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // protector is intact and our prototype is the Array.prototype actually.
220662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ bind(&create_holey_array);
220762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
220862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ mov(ecx, FieldOperand(ecx, Map::kPrototypeOffset));
220962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ cmp(ecx, ContextOperand(ebx, Context::INITIAL_ARRAY_PROTOTYPE_INDEX));
221062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ j(not_equal, &create_runtime);
221162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ LoadRoot(ecx, Heap::kArrayProtectorRootIndex);
221262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ cmp(FieldOperand(ecx, PropertyCell::kValueOffset),
221362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch           Immediate(Smi::FromInt(Isolate::kProtectorValid)));
221462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ j(not_equal, &create_runtime);
221562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ mov(ebx, FieldOperand(eax, JSArray::kLengthOffset));
221662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ SmiUntag(ebx);
221762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ mov(eax, FieldOperand(eax, JSArray::kElementsOffset));
221862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ jmp(&done_create);
221962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
2220014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Try to create the list from a JSArray object.
2221014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&create_array);
2222014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
2223014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ DecodeField<Map::ElementsKindBits>(ecx);
2224014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
2225014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
2226014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    STATIC_ASSERT(FAST_ELEMENTS == 2);
222762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
2228014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(ecx, Immediate(FAST_HOLEY_SMI_ELEMENTS));
222962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ j(equal, &create_holey_array, Label::kNear);
223062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ cmp(ecx, Immediate(FAST_HOLEY_ELEMENTS));
223162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ j(equal, &create_holey_array, Label::kNear);
223262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ j(above, &create_runtime);
2233014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ebx, FieldOperand(eax, JSArray::kLengthOffset));
2234014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ SmiUntag(ebx);
2235014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(eax, FieldOperand(eax, JSArray::kElementsOffset));
2236014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2237014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&done_create);
2238014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2239014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2240014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Check for stack overflow.
2241014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2242014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Check the stack for overflow. We are not trying to catch interruptions
2243014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // (i.e. debug break and preemption) here, so check the "real stack limit".
2244014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label done;
2245014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    ExternalReference real_stack_limit =
2246014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        ExternalReference::address_of_real_stack_limit(masm->isolate());
2247014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ecx, Operand::StaticVariable(real_stack_limit));
2248014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Make ecx the space we have left. The stack might already be overflowed
2249014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // here which will cause ecx to become negative.
2250014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ neg(ecx);
2251014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ add(ecx, esp);
2252014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ sar(ecx, kPointerSizeLog2);
2253014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Check if the arguments will overflow the stack.
2254014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(ecx, ebx);
2255014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(greater, &done, Label::kNear);  // Signed comparison.
2256014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ TailCallRuntime(Runtime::kThrowStackOverflow);
2257014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&done);
2258014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2259014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2260014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
2261014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi    : target
2262014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax    : args (a FixedArray built from argumentsList)
2263014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- ebx    : len (number of elements to push from args)
2264014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx    : new.target (checked to be constructor or undefined)
2265014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[0] : return address.
2266014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[4] : thisArgument
2267014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
2268014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2269014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Push arguments onto the stack (thisArgument is already on the stack).
2270014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
227162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // Save edx/edi to stX0/stX1.
2272014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ push(edx);
227362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ push(edi);
2274014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ fld_s(MemOperand(esp, 0));
227562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ fld_s(MemOperand(esp, 4));
227662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ lea(esp, Operand(esp, 2 * kFloatSize));
2277014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2278014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PopReturnAddressTo(edx);
2279014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Move(ecx, Immediate(0));
228062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Label done, push, loop;
2281014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&loop);
2282014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(ecx, ebx);
2283014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(equal, &done, Label::kNear);
228462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // Turn the hole into undefined as we go.
228562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ mov(edi,
228662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch           FieldOperand(eax, ecx, times_pointer_size, FixedArray::kHeaderSize));
228762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ CompareRoot(edi, Heap::kTheHoleValueRootIndex);
228862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ j(not_equal, &push, Label::kNear);
228962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ LoadRoot(edi, Heap::kUndefinedValueRootIndex);
229062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ bind(&push);
229162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ Push(edi);
2292014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ inc(ecx);
2293014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ jmp(&loop);
2294014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&done);
2295014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PushReturnAddressFrom(edx);
2296014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
229762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // Restore edx/edi from stX0/stX1.
229862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ lea(esp, Operand(esp, -2 * kFloatSize));
2299014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ fstp_s(MemOperand(esp, 0));
230062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ fstp_s(MemOperand(esp, 4));
2301014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ pop(edx);
230262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ pop(edi);
2303014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2304014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Move(eax, ebx);
2305014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2306014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2307014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Dispatch to Call or Construct depending on whether new.target is undefined.
2308014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2309014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CompareRoot(edx, Heap::kUndefinedValueRootIndex);
2310014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(equal, masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
2311014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
2312014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2313014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
2314014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2315109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochnamespace {
2316109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2317109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// Drops top JavaScript frame and an arguments adaptor frame below it (if
2318109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// present) preserving all the arguments prepared for current call.
2319109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// Does nothing if debugger is currently active.
2320109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// ES6 14.6.3. PrepareForTailCall
2321109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch//
2322109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// Stack structure for the function g() tail calling f():
2323109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch//
2324109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// ------- Caller frame: -------
2325109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  ...
2326109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  g()'s arg M
2327109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  ...
2328109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  g()'s arg 1
2329109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  g()'s receiver arg
2330109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  g()'s caller pc
2331109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// ------- g()'s frame: -------
2332109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  g()'s caller fp      <- fp
2333109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  g()'s context
2334109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  function pointer: g
2335109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  -------------------------
2336109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  ...
2337109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  ...
2338109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  f()'s arg N
2339109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  ...
2340109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  f()'s arg 1
2341109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  f()'s receiver arg
2342109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  f()'s caller pc      <- sp
2343109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// ----------------------
2344109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch//
2345109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochvoid PrepareForTailCall(MacroAssembler* masm, Register args_reg,
2346109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                        Register scratch1, Register scratch2,
2347109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                        Register scratch3) {
2348109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
2349109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Comment cmnt(masm, "[ PrepareForTailCall");
2350109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
23513b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  // Prepare for tail call only if ES2015 tail call elimination is enabled.
2352109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Label done;
23533b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  ExternalReference is_tail_call_elimination_enabled =
23543b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch      ExternalReference::is_tail_call_elimination_enabled_address(
23553b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch          masm->isolate());
23563b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ movzx_b(scratch1,
23573b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch             Operand::StaticVariable(is_tail_call_elimination_enabled));
2358109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ cmp(scratch1, Immediate(0));
23593b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ j(equal, &done, Label::kNear);
2360109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2361109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Drop possible interpreter handler/stub frame.
2362109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  {
2363109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    Label no_interpreter_frame;
23643b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    __ cmp(Operand(ebp, CommonFrameConstants::kContextOrFrameTypeOffset),
2365109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch           Immediate(Smi::FromInt(StackFrame::STUB)));
2366109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ j(not_equal, &no_interpreter_frame, Label::kNear);
2367109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ mov(ebp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2368109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ bind(&no_interpreter_frame);
2369109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  }
2370109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2371109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Check if next frame is an arguments adaptor frame.
23723b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  Register caller_args_count_reg = scratch1;
2373109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Label no_arguments_adaptor, formal_parameter_count_loaded;
2374109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ mov(scratch2, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
23753b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ cmp(Operand(scratch2, CommonFrameConstants::kContextOrFrameTypeOffset),
2376109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch         Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2377109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(not_equal, &no_arguments_adaptor, Label::kNear);
2378109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
23793b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  // Drop current frame and load arguments count from arguments adaptor frame.
2380109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ mov(ebp, scratch2);
23813b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ mov(caller_args_count_reg,
23823b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch         Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
23833b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ SmiUntag(caller_args_count_reg);
2384109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ jmp(&formal_parameter_count_loaded, Label::kNear);
2385109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2386109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ bind(&no_arguments_adaptor);
2387109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Load caller's formal parameter count
2388109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ mov(scratch1, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
2389109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ mov(scratch1,
2390109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch         FieldOperand(scratch1, JSFunction::kSharedFunctionInfoOffset));
2391109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ mov(
23923b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch      caller_args_count_reg,
2393109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      FieldOperand(scratch1, SharedFunctionInfo::kFormalParameterCountOffset));
23943b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ SmiUntag(caller_args_count_reg);
2395109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2396109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ bind(&formal_parameter_count_loaded);
2397109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
23983b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  ParameterCount callee_args_count(args_reg);
23993b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
24003b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch                        scratch3, ReturnAddressState::kOnStack, 0);
2401109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ bind(&done);
2402109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch}
2403109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch}  // namespace
2404014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2405014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
2406014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_CallFunction(MacroAssembler* masm,
2407109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                                     ConvertReceiverMode mode,
2408109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                                     TailCallMode tail_call_mode) {
2409014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
2410014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax : the number of arguments (not including the receiver)
2411014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi : the function to call (checked to be a JSFunction)
2412014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
2413014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ AssertFunction(edi);
2414014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2415014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
2416014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Check that the function is not a "classConstructor".
2417014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label class_constructor;
2418014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2419014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ test_b(FieldOperand(edx, SharedFunctionInfo::kFunctionKindByteOffset),
24203b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch            Immediate(SharedFunctionInfo::kClassConstructorBitsWithinByte));
2421014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(not_zero, &class_constructor);
2422014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2423014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Enter the context of the function; ToObject has to run in the function
2424014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // context, and we also need to take the global proxy from the function
2425014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // context in case of conversion.
2426014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  STATIC_ASSERT(SharedFunctionInfo::kNativeByteOffset ==
2427014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                SharedFunctionInfo::kStrictModeByteOffset);
2428014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
2429014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // We need to convert the receiver for non-native sloppy mode functions.
2430014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label done_convert;
2431014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ test_b(FieldOperand(edx, SharedFunctionInfo::kNativeByteOffset),
24323b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch            Immediate((1 << SharedFunctionInfo::kNativeBitWithinByte) |
24333b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch                      (1 << SharedFunctionInfo::kStrictModeBitWithinByte)));
2434014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(not_zero, &done_convert);
2435014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2436014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // ----------- S t a t e -------------
2437014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    //  -- eax : the number of arguments (not including the receiver)
2438014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    //  -- edx : the shared function info.
2439014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    //  -- edi : the function to call (checked to be a JSFunction)
2440014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    //  -- esi : the function context.
2441014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // -----------------------------------
2442014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2443014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (mode == ConvertReceiverMode::kNullOrUndefined) {
2444014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Patch receiver to global proxy.
2445014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ LoadGlobalProxy(ecx);
2446014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    } else {
2447014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Label convert_to_object, convert_receiver;
2448014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ mov(ecx, Operand(esp, eax, times_pointer_size, kPointerSize));
2449014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ JumpIfSmi(ecx, &convert_to_object, Label::kNear);
2450014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
2451014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ CmpObjectType(ecx, FIRST_JS_RECEIVER_TYPE, ebx);
2452014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ j(above_equal, &done_convert);
2453014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      if (mode != ConvertReceiverMode::kNotNullOrUndefined) {
2454014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        Label convert_global_proxy;
2455014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ JumpIfRoot(ecx, Heap::kUndefinedValueRootIndex,
2456014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                      &convert_global_proxy, Label::kNear);
2457014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ JumpIfNotRoot(ecx, Heap::kNullValueRootIndex, &convert_to_object,
2458014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                         Label::kNear);
2459014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ bind(&convert_global_proxy);
2460014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        {
2461014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          // Patch receiver to global proxy.
2462014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          __ LoadGlobalProxy(ecx);
2463014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        }
2464014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ jmp(&convert_receiver);
2465014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      }
2466014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ bind(&convert_to_object);
2467014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      {
2468014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        // Convert receiver using ToObject.
2469014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        // TODO(bmeurer): Inline the allocation here to avoid building the frame
2470014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        // in the fast case? (fall back to AllocateInNewSpace?)
2471014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        FrameScope scope(masm, StackFrame::INTERNAL);
2472014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ SmiTag(eax);
2473014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ Push(eax);
2474014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ Push(edi);
2475014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ mov(eax, ecx);
2476f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        __ Push(esi);
2477c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        __ Call(masm->isolate()->builtins()->ToObject(),
2478c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch                RelocInfo::CODE_TARGET);
2479f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        __ Pop(esi);
2480014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ mov(ecx, eax);
2481014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ Pop(edi);
2482014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ Pop(eax);
2483014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ SmiUntag(eax);
2484014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      }
2485014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2486014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ bind(&convert_receiver);
2487014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
2488014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ecx);
2489014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2490014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&done_convert);
2491014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2492014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
2493014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax : the number of arguments (not including the receiver)
2494014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx : the shared function info.
2495014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi : the function to call (checked to be a JSFunction)
2496014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esi : the function context.
2497014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
2498014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2499109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  if (tail_call_mode == TailCallMode::kAllow) {
2500109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    PrepareForTailCall(masm, eax, ebx, ecx, edx);
2501109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Reload shared function info.
2502109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2503109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  }
2504109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2505014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ebx,
2506014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch         FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
2507014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ SmiUntag(ebx);
2508014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  ParameterCount actual(eax);
2509014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  ParameterCount expected(ebx);
2510014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ InvokeFunctionCode(edi, no_reg, expected, actual, JUMP_FUNCTION,
2511014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                        CheckDebugStepCallWrapper());
2512014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // The function is a "classConstructor", need to raise an exception.
2513014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&class_constructor);
2514014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2515014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    FrameScope frame(masm, StackFrame::INTERNAL);
2516014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ push(edi);
2517014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CallRuntime(Runtime::kThrowConstructorNonCallableError);
2518014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2519014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
2520014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2521014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochnamespace {
2522014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2523014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Generate_PushBoundArguments(MacroAssembler* masm) {
2524014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
2525014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax : the number of arguments (not including the receiver)
2526014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx : new.target (only in case of [[Construct]])
2527014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi : target (checked to be a JSBoundFunction)
2528014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
2529014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2530014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Load [[BoundArguments]] into ecx and length of that into ebx.
2531014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label no_bound_arguments;
2532014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset));
2533014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
2534014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ SmiUntag(ebx);
2535014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ test(ebx, ebx);
2536014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(zero, &no_bound_arguments);
2537014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2538014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // ----------- S t a t e -------------
2539014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    //  -- eax : the number of arguments (not including the receiver)
2540014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    //  -- edx : new.target (only in case of [[Construct]])
2541014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    //  -- edi : target (checked to be a JSBoundFunction)
2542014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    //  -- ecx : the [[BoundArguments]] (implemented as FixedArray)
2543014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    //  -- ebx : the number of [[BoundArguments]]
2544014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // -----------------------------------
2545014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2546014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Reserve stack space for the [[BoundArguments]].
2547014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    {
2548014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Label done;
2549014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ lea(ecx, Operand(ebx, times_pointer_size, 0));
2550014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ sub(esp, ecx);
2551014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Check the stack for overflow. We are not trying to catch interruptions
2552014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // (i.e. debug break and preemption) here, so check the "real stack
2553014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // limit".
2554014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ CompareRoot(esp, ecx, Heap::kRealStackLimitRootIndex);
2555014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ j(greater, &done, Label::kNear);  // Signed comparison.
2556014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Restore the stack pointer.
2557014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ lea(esp, Operand(esp, ebx, times_pointer_size, 0));
2558014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      {
2559014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        FrameScope scope(masm, StackFrame::MANUAL);
2560014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ EnterFrame(StackFrame::INTERNAL);
2561014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ CallRuntime(Runtime::kThrowStackOverflow);
2562014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      }
2563014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ bind(&done);
2564014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
2565014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2566014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Adjust effective number of arguments to include return address.
2567014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ inc(eax);
2568014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2569014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Relocate arguments and return address down the stack.
2570014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    {
2571014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Label loop;
2572014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ Set(ecx, 0);
2573014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ lea(ebx, Operand(esp, ebx, times_pointer_size, 0));
2574014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ bind(&loop);
2575014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ fld_s(Operand(ebx, ecx, times_pointer_size, 0));
2576014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ fstp_s(Operand(esp, ecx, times_pointer_size, 0));
2577014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ inc(ecx);
2578014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ cmp(ecx, eax);
2579014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ j(less, &loop);
2580014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
2581014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2582014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Copy [[BoundArguments]] to the stack (below the arguments).
2583014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    {
2584014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Label loop;
2585014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset));
2586014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
2587014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ SmiUntag(ebx);
2588014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ bind(&loop);
2589014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ dec(ebx);
2590014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ fld_s(
2591014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          FieldOperand(ecx, ebx, times_pointer_size, FixedArray::kHeaderSize));
2592014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ fstp_s(Operand(esp, eax, times_pointer_size, 0));
2593014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ lea(eax, Operand(eax, 1));
2594014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ j(greater, &loop);
2595014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
2596014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2597014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Adjust effective number of arguments (eax contains the number of
2598014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // arguments from the call plus return address plus the number of
2599014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // [[BoundArguments]]), so we need to subtract one for the return address.
2600014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ dec(eax);
2601014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2602014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&no_bound_arguments);
2603014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
2604014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2605014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace
2606014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2607014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
2608109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochvoid Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm,
2609109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                                              TailCallMode tail_call_mode) {
2610014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
2611014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax : the number of arguments (not including the receiver)
2612014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi : the function to call (checked to be a JSBoundFunction)
2613014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
2614014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ AssertBoundFunction(edi);
2615014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2616109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  if (tail_call_mode == TailCallMode::kAllow) {
2617109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    PrepareForTailCall(masm, eax, ebx, ecx, edx);
2618109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  }
2619109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2620014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Patch the receiver to [[BoundThis]].
2621014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ebx, FieldOperand(edi, JSBoundFunction::kBoundThisOffset));
2622014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ebx);
2623014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2624014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Push the [[BoundArguments]] onto the stack.
2625014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Generate_PushBoundArguments(masm);
2626014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2627014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Call the [[BoundTargetFunction]] via the Call builtin.
2628014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2629014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, Operand::StaticVariable(ExternalReference(
2630014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                  Builtins::kCall_ReceiverIsAny, masm->isolate())));
2631014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2632014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ jmp(ecx);
2633014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
2634014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2635014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
2636109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochvoid Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
2637109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                             TailCallMode tail_call_mode) {
2638014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
2639014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax : the number of arguments (not including the receiver)
2640014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi : the target to call (can be any Object).
2641014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
2642014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2643014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label non_callable, non_function, non_smi;
2644014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ JumpIfSmi(edi, &non_callable);
2645014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&non_smi);
2646014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
2647109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(equal, masm->isolate()->builtins()->CallFunction(mode, tail_call_mode),
2648014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch       RelocInfo::CODE_TARGET);
2649014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE);
2650109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(equal, masm->isolate()->builtins()->CallBoundFunction(tail_call_mode),
2651014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch       RelocInfo::CODE_TARGET);
2652109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2653109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Check if target has a [[Call]] internal method.
26543b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
26553b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch            Immediate(1 << Map::kIsCallable));
2656109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(zero, &non_callable);
2657109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2658014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CmpInstanceType(ecx, JS_PROXY_TYPE);
2659014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(not_equal, &non_function);
2660014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2661109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // 0. Prepare for tail call if necessary.
2662109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  if (tail_call_mode == TailCallMode::kAllow) {
2663109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    PrepareForTailCall(masm, eax, ebx, ecx, edx);
2664109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  }
2665109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2666014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 1. Runtime fallback for Proxy [[Call]].
2667014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ PopReturnAddressTo(ecx);
2668014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Push(edi);
2669014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ PushReturnAddressFrom(ecx);
2670014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Increase the arguments size to include the pushed function and the
2671014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // existing receiver on the stack.
2672014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ add(eax, Immediate(2));
2673014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Tail-call to the runtime.
2674014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ JumpToExternalReference(
2675014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      ExternalReference(Runtime::kJSProxyCall, masm->isolate()));
2676014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2677014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 2. Call to something else, which might have a [[Call]] internal method (if
2678014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // not we raise an exception).
2679014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&non_function);
2680014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Overwrite the original receiver with the (original) target.
2681014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
2682014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Let the "call_as_function_delegate" take care of the rest.
2683014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, edi);
2684014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Jump(masm->isolate()->builtins()->CallFunction(
2685109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch              ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode),
2686014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          RelocInfo::CODE_TARGET);
2687014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2688014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 3. Call to something that is not callable.
2689014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&non_callable);
2690014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2691014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
2692014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Push(edi);
2693014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CallRuntime(Runtime::kThrowCalledNonCallable);
2694014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2695014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
2696014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
269762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdochstatic void CheckSpreadAndPushToStack(MacroAssembler* masm) {
269862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // Free up some registers.
269962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // Save edx/edi to stX0/stX1.
270062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ push(edx);
270162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ push(edi);
270262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ fld_s(MemOperand(esp, 0));
270362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ fld_s(MemOperand(esp, 4));
270462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ lea(esp, Operand(esp, 2 * kFloatSize));
270562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
270662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Register argc = eax;
270762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
270862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Register scratch = ecx;
270962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Register scratch2 = edi;
271062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
271162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Register spread = ebx;
271262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Register spread_map = edx;
271362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
271462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Register spread_len = edx;
271562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
271662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Label runtime_call, push_args;
271762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ mov(spread, Operand(esp, kPointerSize));
271862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ JumpIfSmi(spread, &runtime_call);
271962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ mov(spread_map, FieldOperand(spread, HeapObject::kMapOffset));
272062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
272162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // Check that the spread is an array.
272262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ CmpInstanceType(spread_map, JS_ARRAY_TYPE);
272362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ j(not_equal, &runtime_call);
272462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
272562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // Check that we have the original ArrayPrototype.
272662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ mov(scratch, FieldOperand(spread_map, Map::kPrototypeOffset));
272762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ mov(scratch2, NativeContextOperand());
272862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ cmp(scratch,
272962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch         ContextOperand(scratch2, Context::INITIAL_ARRAY_PROTOTYPE_INDEX));
273062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ j(not_equal, &runtime_call);
273162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
273262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // Check that the ArrayPrototype hasn't been modified in a way that would
273362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // affect iteration.
273462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ LoadRoot(scratch, Heap::kArrayIteratorProtectorRootIndex);
273562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ cmp(FieldOperand(scratch, PropertyCell::kValueOffset),
273662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch         Immediate(Smi::FromInt(Isolate::kProtectorValid)));
273762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ j(not_equal, &runtime_call);
273862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
273962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // Check that the map of the initial array iterator hasn't changed.
274062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ mov(scratch2, NativeContextOperand());
274162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ mov(scratch,
274262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch         ContextOperand(scratch2,
274362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                        Context::INITIAL_ARRAY_ITERATOR_PROTOTYPE_INDEX));
274462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
274562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ cmp(scratch,
274662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch         ContextOperand(scratch2,
274762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                        Context::INITIAL_ARRAY_ITERATOR_PROTOTYPE_MAP_INDEX));
274862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ j(not_equal, &runtime_call);
274962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
275062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // For FastPacked kinds, iteration will have the same effect as simply
275162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // accessing each property in order.
275262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Label no_protector_check;
275362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ mov(scratch, FieldOperand(spread_map, Map::kBitField2Offset));
275462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ DecodeField<Map::ElementsKindBits>(scratch);
275562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ cmp(scratch, Immediate(FAST_HOLEY_ELEMENTS));
275662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ j(above, &runtime_call);
275762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // For non-FastHoley kinds, we can skip the protector check.
275862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ cmp(scratch, Immediate(FAST_SMI_ELEMENTS));
275962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ j(equal, &no_protector_check);
276062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ cmp(scratch, Immediate(FAST_ELEMENTS));
276162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ j(equal, &no_protector_check);
276262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // Check the ArrayProtector cell.
276362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ LoadRoot(scratch, Heap::kArrayProtectorRootIndex);
276462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ cmp(FieldOperand(scratch, PropertyCell::kValueOffset),
276562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch         Immediate(Smi::FromInt(Isolate::kProtectorValid)));
276662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ j(not_equal, &runtime_call);
276762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
276862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ bind(&no_protector_check);
276962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // Load the FixedArray backing store, but use the length from the array.
277062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ mov(spread_len, FieldOperand(spread, JSArray::kLengthOffset));
277162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ SmiUntag(spread_len);
277262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ mov(spread, FieldOperand(spread, JSArray::kElementsOffset));
277362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ jmp(&push_args);
277462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
277562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ bind(&runtime_call);
277662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  {
277762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // Call the builtin for the result of the spread.
277862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
277962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // Need to save these on the stack.
278062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // Restore edx/edi from stX0/stX1.
278162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ lea(esp, Operand(esp, -2 * kFloatSize));
278262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ fstp_s(MemOperand(esp, 0));
278362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ fstp_s(MemOperand(esp, 4));
278462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ pop(edx);
278562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ pop(edi);
278662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
278762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ Push(edi);
278862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ Push(edx);
278962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ SmiTag(argc);
279062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ Push(argc);
279162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ Push(spread);
279262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ CallRuntime(Runtime::kSpreadIterableFixed);
279362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ mov(spread, eax);
279462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ Pop(argc);
279562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ SmiUntag(argc);
279662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ Pop(edx);
279762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ Pop(edi);
279862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // Free up some registers.
279962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // Save edx/edi to stX0/stX1.
280062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ push(edx);
280162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ push(edi);
280262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ fld_s(MemOperand(esp, 0));
280362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ fld_s(MemOperand(esp, 4));
280462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ lea(esp, Operand(esp, 2 * kFloatSize));
280562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  }
280662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
280762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  {
280862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // Calculate the new nargs including the result of the spread.
280962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ mov(spread_len, FieldOperand(spread, FixedArray::kLengthOffset));
281062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ SmiUntag(spread_len);
281162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
281262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ bind(&push_args);
281362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // argc += spread_len - 1. Subtract 1 for the spread itself.
281462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ lea(argc, Operand(argc, spread_len, times_1, -1));
281562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  }
281662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
281762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // Check for stack overflow.
281862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  {
281962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // Check the stack for overflow. We are not trying to catch interruptions
282062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // (i.e. debug break and preemption) here, so check the "real stack limit".
282162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Label done;
282262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ LoadRoot(scratch, Heap::kRealStackLimitRootIndex);
282362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // Make scratch the space we have left. The stack might already be
282462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // overflowed here which will cause scratch to become negative.
282562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ neg(scratch);
282662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ add(scratch, esp);
282762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ sar(scratch, kPointerSizeLog2);
282862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // Check if the arguments will overflow the stack.
282962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ cmp(scratch, spread_len);
283062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ j(greater, &done, Label::kNear);  // Signed comparison.
283162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ TailCallRuntime(Runtime::kThrowStackOverflow);
283262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ bind(&done);
283362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  }
283462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
283562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // Put the evaluated spread onto the stack as additional arguments.
283662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  {
283762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Register return_address = edi;
283862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // Pop the return address and spread argument.
283962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ PopReturnAddressTo(return_address);
284062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ Pop(scratch);
284162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
284262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Register scratch2 = esi;
284362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // Save esi to stX0, edx/edi in stX1/stX2 now.
284462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ push(esi);
284562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ fld_s(MemOperand(esp, 0));
284662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ lea(esp, Operand(esp, 1 * kFloatSize));
284762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
284862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ mov(scratch, Immediate(0));
284962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Label done, push, loop;
285062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ bind(&loop);
285162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ cmp(scratch, spread_len);
285262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ j(equal, &done, Label::kNear);
285362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ mov(scratch2, FieldOperand(spread, scratch, times_pointer_size,
285462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                                  FixedArray::kHeaderSize));
285562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ JumpIfNotRoot(scratch2, Heap::kTheHoleValueRootIndex, &push);
285662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ LoadRoot(scratch2, Heap::kUndefinedValueRootIndex);
285762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ bind(&push);
285862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ Push(scratch2);
285962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ inc(scratch);
286062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ jmp(&loop);
286162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ bind(&done);
286262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ PushReturnAddressFrom(return_address);
286362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
286462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // Now Restore esi from stX0, edx/edi from stX1/stX2.
286562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ lea(esp, Operand(esp, -3 * kFloatSize));
286662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ fstp_s(MemOperand(esp, 0));
286762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ fstp_s(MemOperand(esp, 4));
286862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ fstp_s(MemOperand(esp, 8));
286962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ pop(esi);
287062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ pop(edx);
287162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ pop(edi);
287262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  }
287362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch}
287462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
287562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch// static
287662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdochvoid Builtins::Generate_CallWithSpread(MacroAssembler* masm) {
287762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // ----------- S t a t e -------------
287862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  //  -- eax : the number of arguments (not including the receiver)
287962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  //  -- edi : the target to call (can be any Object)
288062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // -----------------------------------
288162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
288262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // CheckSpreadAndPushToStack will push edx to save it.
288362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
288462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  CheckSpreadAndPushToStack(masm);
288562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
288662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                                            TailCallMode::kDisallow),
288762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch          RelocInfo::CODE_TARGET);
288862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch}
288962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
2890014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
2891014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
2892014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
2893014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax : the number of arguments (not including the receiver)
2894014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx : the new target (checked to be a constructor)
2895014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi : the constructor to call (checked to be a JSFunction)
2896014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
2897014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ AssertFunction(edi);
2898014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2899014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Calling convention for function specific ConstructStubs require
2900014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ebx to contain either an AllocationSite or undefined.
2901014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ LoadRoot(ebx, Heap::kUndefinedValueRootIndex);
2902014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2903014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Tail call to the function-specific construct stub (still in the caller
2904014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // context at this point).
2905014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2906014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset));
2907014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2908014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ jmp(ecx);
2909014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
2910014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2911014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
2912014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) {
2913014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
2914014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax : the number of arguments (not including the receiver)
2915014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx : the new target (checked to be a constructor)
2916014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi : the constructor to call (checked to be a JSBoundFunction)
2917014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
2918014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ AssertBoundFunction(edi);
2919014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2920014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Push the [[BoundArguments]] onto the stack.
2921014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Generate_PushBoundArguments(masm);
2922014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2923014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Patch new.target to [[BoundTargetFunction]] if new.target equals target.
2924014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2925014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label done;
2926014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(edi, edx);
2927014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(not_equal, &done, Label::kNear);
2928014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(edx, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2929014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&done);
2930014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2931014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2932014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Construct the [[BoundTargetFunction]] via the Construct builtin.
2933014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2934014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, Operand::StaticVariable(
2935014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                  ExternalReference(Builtins::kConstruct, masm->isolate())));
2936014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2937014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ jmp(ecx);
2938014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
2939014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2940014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
2941014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
2942014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
2943014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax : the number of arguments (not including the receiver)
2944014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi : the constructor to call (checked to be a JSProxy)
2945014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx : the new target (either the same as the constructor or
2946014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //           the JSFunction on which new was invoked initially)
2947014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
2948014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2949014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Call into the Runtime for Proxy [[Construct]].
2950014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ PopReturnAddressTo(ecx);
2951014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Push(edi);
2952014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Push(edx);
2953014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ PushReturnAddressFrom(ecx);
2954014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Include the pushed new_target, constructor and the receiver.
2955014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ add(eax, Immediate(3));
2956014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Tail-call to the runtime.
2957014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ JumpToExternalReference(
2958014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      ExternalReference(Runtime::kJSProxyConstruct, masm->isolate()));
2959014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
2960014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2961014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
2962014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_Construct(MacroAssembler* masm) {
2963014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
2964014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax : the number of arguments (not including the receiver)
2965014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx : the new target (either the same as the constructor or
2966014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //           the JSFunction on which new was invoked initially)
2967014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi : the constructor to call (can be any Object)
2968014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
2969014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2970014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Check if target is a Smi.
2971014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label non_constructor;
2972014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ JumpIfSmi(edi, &non_constructor, Label::kNear);
2973014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2974014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Dispatch based on instance type.
2975014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
2976014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(equal, masm->isolate()->builtins()->ConstructFunction(),
2977014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch       RelocInfo::CODE_TARGET);
2978014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2979014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Check if target has a [[Construct]] internal method.
29803b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
29813b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch            Immediate(1 << Map::kIsConstructor));
2982014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(zero, &non_constructor, Label::kNear);
2983014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2984014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Only dispatch to bound functions after checking whether they are
2985014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // constructors.
2986014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE);
2987014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(equal, masm->isolate()->builtins()->ConstructBoundFunction(),
2988014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch       RelocInfo::CODE_TARGET);
2989014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2990014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Only dispatch to proxies after checking whether they are constructors.
2991014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CmpInstanceType(ecx, JS_PROXY_TYPE);
2992014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(equal, masm->isolate()->builtins()->ConstructProxy(),
2993014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch       RelocInfo::CODE_TARGET);
2994014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2995014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Called Construct on an exotic Object with a [[Construct]] internal method.
2996014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2997014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Overwrite the original receiver with the (original) target.
2998014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
2999014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Let the "call_as_constructor_delegate" take care of the rest.
3000014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, edi);
3001014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Jump(masm->isolate()->builtins()->CallFunction(),
3002014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch            RelocInfo::CODE_TARGET);
3003014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
3004014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3005014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Called Construct on an Object that doesn't have a [[Construct]] internal
3006014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // method.
3007014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&non_constructor);
3008014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Jump(masm->isolate()->builtins()->ConstructedNonConstructable(),
3009014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          RelocInfo::CODE_TARGET);
3010014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
3011014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3012bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch// static
301362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdochvoid Builtins::Generate_ConstructWithSpread(MacroAssembler* masm) {
301462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // ----------- S t a t e -------------
301562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  //  -- eax : the number of arguments (not including the receiver)
301662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  //  -- edx : the new target (either the same as the constructor or
301762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  //           the JSFunction on which new was invoked initially)
301862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  //  -- edi : the constructor to call (can be any Object)
301962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // -----------------------------------
302062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
302162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  CheckSpreadAndPushToStack(masm);
302262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
302362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch}
302462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
302562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch// static
3026bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdochvoid Builtins::Generate_AllocateInNewSpace(MacroAssembler* masm) {
3027bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // ----------- S t a t e -------------
3028bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- edx    : requested object size (untagged)
3029bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- esp[0] : return address
3030bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // -----------------------------------
3031bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ SmiTag(edx);
3032bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ PopReturnAddressTo(ecx);
3033bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ Push(edx);
3034bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ PushReturnAddressFrom(ecx);
3035c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ Move(esi, Smi::kZero);
3036bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ TailCallRuntime(Runtime::kAllocateInNewSpace);
3037bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch}
3038bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
3039bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch// static
3040bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdochvoid Builtins::Generate_AllocateInOldSpace(MacroAssembler* masm) {
3041bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // ----------- S t a t e -------------
3042bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- edx    : requested object size (untagged)
3043bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- esp[0] : return address
3044bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // -----------------------------------
3045bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ SmiTag(edx);
3046bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ PopReturnAddressTo(ecx);
3047bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ Push(edx);
3048bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ Push(Smi::FromInt(AllocateTargetSpace::encode(OLD_SPACE)));
3049bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ PushReturnAddressFrom(ecx);
3050c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ Move(esi, Smi::kZero);
3051bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ TailCallRuntime(Runtime::kAllocateInTargetSpace);
3052bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch}
3053014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
305413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch// static
3055f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochvoid Builtins::Generate_Abort(MacroAssembler* masm) {
3056f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // ----------- S t a t e -------------
3057f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  //  -- edx    : message_id as Smi
3058f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  //  -- esp[0] : return address
3059f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // -----------------------------------
3060f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ PopReturnAddressTo(ecx);
3061f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ Push(edx);
3062f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ PushReturnAddressFrom(ecx);
3063c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ Move(esi, Smi::kZero);
3064f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ TailCallRuntime(Runtime::kAbort);
306513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch}
306613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
3067b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
3068b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // ----------- S t a t e -------------
3069b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- eax : actual number of arguments
3070b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- ebx : expected number of arguments
3071014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx : new target (passed through to callee)
3072b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- edi : function (passed through to callee)
3073b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // -----------------------------------
3074b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3075014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label invoke, dont_adapt_arguments, stack_overflow;
3076b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1);
3077b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3078b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Label enough, too_few;
3079b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ cmp(eax, ebx);
3080b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ j(less, &too_few);
3081b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
3082b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ j(equal, &dont_adapt_arguments);
3083b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3084b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  {  // Enough parameters: Actual >= expected.
3085b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ bind(&enough);
3086b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    EnterArgumentsAdaptorFrame(masm);
3087f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // edi is used as a scratch register. It should be restored from the frame
3088f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // when needed.
3089f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    Generate_StackOverflowCheck(masm, ebx, ecx, edi, &stack_overflow);
3090b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3091b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Copy receiver and all expected arguments.
3092b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    const int offset = StandardFrameConstants::kCallerSPOffset;
3093014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ lea(edi, Operand(ebp, eax, times_4, offset));
3094014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(eax, -1);  // account for receiver
3095b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3096b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Label copy;
3097b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ bind(&copy);
3098014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ inc(eax);
3099014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ push(Operand(edi, 0));
3100014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ sub(edi, Immediate(kPointerSize));
3101014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(eax, ebx);
3102b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ j(less, &copy);
3103014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // eax now contains the expected number of arguments.
3104b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ jmp(&invoke);
3105b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
3106b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3107b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  {  // Too few parameters: Actual < expected.
3108b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ bind(&too_few);
3109b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    EnterArgumentsAdaptorFrame(masm);
3110f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // edi is used as a scratch register. It should be restored from the frame
3111f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // when needed.
3112f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    Generate_StackOverflowCheck(masm, ebx, ecx, edi, &stack_overflow);
3113014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3114014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Remember expected arguments in ecx.
3115014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ecx, ebx);
3116b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3117b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Copy receiver and all actual arguments.
3118b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    const int offset = StandardFrameConstants::kCallerSPOffset;
3119b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ lea(edi, Operand(ebp, eax, times_4, offset));
3120b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // ebx = expected - actual.
3121b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ sub(ebx, eax);
3122b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // eax = -actual - 1
3123b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ neg(eax);
3124b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ sub(eax, Immediate(1));
3125b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3126b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Label copy;
3127b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ bind(&copy);
3128b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ inc(eax);
3129b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ push(Operand(edi, 0));
3130b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ sub(edi, Immediate(kPointerSize));
3131b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ test(eax, eax);
3132b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ j(not_zero, &copy);
3133b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3134b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Fill remaining expected arguments with undefined values.
3135b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Label fill;
3136b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ bind(&fill);
3137b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ inc(eax);
3138b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ push(Immediate(masm->isolate()->factory()->undefined_value()));
3139b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ cmp(eax, ebx);
3140b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ j(less, &fill);
3141014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3142014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Restore expected arguments.
3143014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(eax, ecx);
3144b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
3145b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3146b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Call the entry point.
3147b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ bind(&invoke);
3148b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Restore function pointer.
31493b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ mov(edi, Operand(ebp, ArgumentsAdaptorFrameConstants::kFunctionOffset));
3150014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // eax : expected number of arguments
3151014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // edx : new target (passed through to callee)
3152014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // edi : function (passed through to callee)
3153014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
3154014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ call(ecx);
3155b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3156b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Store offset of return address for deoptimizer.
3157b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
3158b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3159b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Leave frame and return.
3160b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  LeaveArgumentsAdaptorFrame(masm);
3161b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ ret(0);
3162b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3163b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // -------------------------------------------
3164b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Dont adapt arguments.
3165b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // -------------------------------------------
3166b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ bind(&dont_adapt_arguments);
3167014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
3168014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ jmp(ecx);
3169b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3170b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ bind(&stack_overflow);
3171b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  {
3172b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    FrameScope frame(masm, StackFrame::MANUAL);
3173014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CallRuntime(Runtime::kThrowStackOverflow);
3174b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ int3();
3175b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
3176b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
3177b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3178014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochstatic void CompatibleReceiverCheck(MacroAssembler* masm, Register receiver,
3179014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                    Register function_template_info,
3180014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                    Register scratch0, Register scratch1,
3181014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                    Label* receiver_check_failed) {
3182014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // If there is no signature, return the holder.
3183014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CompareRoot(FieldOperand(function_template_info,
3184014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                              FunctionTemplateInfo::kSignatureOffset),
3185014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                 Heap::kUndefinedValueRootIndex);
3186014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label receiver_check_passed;
3187014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(equal, &receiver_check_passed, Label::kNear);
3188014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3189014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Walk the prototype chain.
3190014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
3191014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label prototype_loop_start;
3192014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&prototype_loop_start);
3193014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3194014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Get the constructor, if any.
3195014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ GetMapConstructor(scratch0, scratch0, scratch1);
3196014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CmpInstanceType(scratch1, JS_FUNCTION_TYPE);
3197014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label next_prototype;
3198014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(not_equal, &next_prototype, Label::kNear);
3199014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3200014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Get the constructor's signature.
3201014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(scratch0,
3202014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch         FieldOperand(scratch0, JSFunction::kSharedFunctionInfoOffset));
3203014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(scratch0,
3204014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch         FieldOperand(scratch0, SharedFunctionInfo::kFunctionDataOffset));
3205014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3206014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Loop through the chain of inheriting function templates.
3207014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label function_template_loop;
3208014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&function_template_loop);
3209014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3210014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // If the signatures match, we have a compatible receiver.
3211014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ cmp(scratch0, FieldOperand(function_template_info,
3212014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                FunctionTemplateInfo::kSignatureOffset));
3213014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(equal, &receiver_check_passed, Label::kNear);
3214014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3215014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // If the current type is not a FunctionTemplateInfo, load the next prototype
3216014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // in the chain.
3217014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ JumpIfSmi(scratch0, &next_prototype, Label::kNear);
3218014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CmpObjectType(scratch0, FUNCTION_TEMPLATE_INFO_TYPE, scratch1);
3219014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(not_equal, &next_prototype, Label::kNear);
3220014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3221014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Otherwise load the parent function template and iterate.
3222014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(scratch0,
3223014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch         FieldOperand(scratch0, FunctionTemplateInfo::kParentTemplateOffset));
3224014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ jmp(&function_template_loop, Label::kNear);
3225014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3226014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Load the next prototype.
3227014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&next_prototype);
3228014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(receiver, FieldOperand(receiver, HeapObject::kMapOffset));
3229109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ test(FieldOperand(receiver, Map::kBitField3Offset),
3230109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch          Immediate(Map::HasHiddenPrototype::kMask));
3231109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(zero, receiver_check_failed);
3232109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
3233014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(receiver, FieldOperand(receiver, Map::kPrototypeOffset));
3234014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
3235014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Iterate.
3236014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ jmp(&prototype_loop_start, Label::kNear);
3237014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3238014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&receiver_check_passed);
3239014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
3240014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3241014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_HandleFastApiCall(MacroAssembler* masm) {
3242014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
3243014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax                : number of arguments (not including the receiver)
3244014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi                : callee
3245014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esi                : context
3246014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[0]             : return address
3247014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[4]             : last argument
3248014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- ...
3249014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[eax * 4]       : first argument
3250014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[(eax + 1) * 4] : receiver
3251014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
3252014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3253014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Load the FunctionTemplateInfo.
3254014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
3255014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kFunctionDataOffset));
3256014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3257014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Do the compatible receiver check.
3258014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label receiver_check_failed;
3259014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, Operand(esp, eax, times_pointer_size, kPCOnStackSize));
3260014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Push(eax);
3261014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  CompatibleReceiverCheck(masm, ecx, ebx, edx, eax, &receiver_check_failed);
3262014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Pop(eax);
3263014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Get the callback offset from the FunctionTemplateInfo, and jump to the
3264014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // beginning of the code.
3265014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(edx, FieldOperand(ebx, FunctionTemplateInfo::kCallCodeOffset));
3266014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(edx, FieldOperand(edx, CallHandlerInfo::kFastHandlerOffset));
3267014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag));
3268014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ jmp(edx);
3269014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3270014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Compatible receiver check failed: pop return address, arguments and
3271014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // receiver and throw an Illegal Invocation exception.
3272014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&receiver_check_failed);
3273014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Pop(eax);
3274014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ PopReturnAddressTo(ebx);
3275014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ lea(eax, Operand(eax, times_pointer_size, 1 * kPointerSize));
3276014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ add(esp, eax);
3277014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ PushReturnAddressFrom(ebx);
3278014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
3279014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
3280014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ TailCallRuntime(Runtime::kThrowIllegalInvocation);
3281014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
3282014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
3283014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3284f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochstatic void Generate_OnStackReplacementHelper(MacroAssembler* masm,
3285f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                                              bool has_handler_frame) {
3286b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Lookup the function in the JavaScript frame.
3287f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  if (has_handler_frame) {
3288f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ mov(eax, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3289f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ mov(eax, Operand(eax, JavaScriptFrameConstants::kFunctionOffset));
3290f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  } else {
3291f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
3292f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
3293f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
3294b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  {
3295b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
3296b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Pass function as argument.
3297b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ push(eax);
3298014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CallRuntime(Runtime::kCompileForOnStackReplacement);
3299b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
3300b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3301b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Label skip;
3302f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // If the code object is null, just return to the caller.
3303b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ cmp(eax, Immediate(0));
3304b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ j(not_equal, &skip, Label::kNear);
3305b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ ret(0);
3306b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3307b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ bind(&skip);
3308b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3309f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // Drop any potential handler frame that is be sitting on top of the actual
3310f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // JavaScript frame. This is the case then OSR is triggered from bytecode.
3311f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  if (has_handler_frame) {
3312f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ leave();
3313f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
3314f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
3315b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Load deoptimization data from the code object.
3316b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(ebx, Operand(eax, Code::kDeoptimizationDataOffset - kHeapObjectTag));
3317b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3318b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Load the OSR entrypoint offset from the deoptimization data.
3319b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(ebx, Operand(ebx, FixedArray::OffsetOfElementAt(
3320f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                               DeoptimizationInputData::kOsrPcOffsetIndex) -
3321f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                               kHeapObjectTag));
3322b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ SmiUntag(ebx);
3323b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3324b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Compute the target address = code_obj + header_size + osr_offset
3325b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ lea(eax, Operand(eax, ebx, times_1, Code::kHeaderSize - kHeapObjectTag));
3326b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3327b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Overwrite the return address on the stack.
3328b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(Operand(esp, 0), eax);
3329b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3330b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // And "return" to the OSR entry point of the function.
3331b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ ret(0);
3332b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
3333b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3334f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochvoid Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
3335f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  Generate_OnStackReplacementHelper(masm, false);
3336f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}
3337f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
3338f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochvoid Builtins::Generate_InterpreterOnStackReplacement(MacroAssembler* masm) {
3339f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  Generate_OnStackReplacementHelper(masm, true);
3340f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}
3341b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3342b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#undef __
3343014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace internal
3344014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace v8
3345b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3346b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#endif  // V8_TARGET_ARCH_X87
3347