13ef787dbeca8a5fb1086949cda830dccee07bfbdBen 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_IA32
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/ia32/frames-ia32.h"
12a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
13a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace v8 {
14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace internal {
15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#define __ ACCESS_MASM(masm)
17a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
18f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochvoid Builtins::Generate_Adaptor(MacroAssembler* masm, Address address,
19f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                                ExitFrameType exit_frame_type) {
20e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // ----------- S t a t e -------------
21e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- eax                : number of arguments excluding receiver
22014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi                : target
23014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx                : new.target
24e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[0]             : return address
25e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[4]             : last argument
26e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ...
27014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[4 * argc]      : first argument
28e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[4 * (argc +1)] : receiver
29e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // -----------------------------------
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));
37e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
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
43e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // 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);
51e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
52f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ JumpToExternalReference(ExternalReference(address, masm->isolate()),
53f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                             exit_frame_type == BUILTIN_EXIT);
54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
55a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
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);
86f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch}
87f2e3994fa5148cc3d9946666f0b0596290192b0eBen 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);
93b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
94b8a8cc1952d61a2f3a2568848933943a543b5d3eBen 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) {
118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax: number of arguments
1203b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  //  -- esi: context
121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- edi: constructor function
122014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx: new target
123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Enter a construct frame.
1263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  {
1273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    FrameScope scope(masm, StackFrame::CONSTRUCT);
128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
129014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Preserve the incoming parameters on the stack.
1303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ SmiTag(eax);
131c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    __ push(esi);
1323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ push(eax);
133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
134014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (create_implicit_receiver) {
135109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      // Allocate the new receiver object.
136109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ Push(edi);
137109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ Push(edx);
138109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      FastNewObjectStub stub(masm->isolate());
139109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ CallStub(&stub);
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));
1523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
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
1663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Set up pointer to last argument.
1673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Copy arguments and receiver to the expression stack.
1703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label loop, entry;
1713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(ecx, eax);
1723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ jmp(&entry);
1733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&loop);
1743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ push(Operand(ebx, ecx, times_4, 0));
1753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&entry);
1763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ dec(ecx);
1773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ j(greater_equal, &loop);
1783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Call the function.
180bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    ParameterCount actual(eax);
181bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ InvokeFunction(edi, edx, actual, CALL_FUNCTION,
182bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch                      CheckDebugStepCallWrapper());
183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Store offset of return address for deoptimizer.
185014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (create_implicit_receiver && !is_api_function) {
1863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
1873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
1885d4cdbf7a67d3662fa0bee4efdb7edd8daec9b0bBen Murdoch
1893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Restore context from the frame.
1903b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    __ mov(esi, Operand(ebp, ConstructFrameConstants::kContextOffset));
191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
192014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (create_implicit_receiver) {
193014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // If the result is an object (in the ECMA sense), we should get rid
194109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      // of the receiver and use the result.
195014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Label use_receiver, exit;
196014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
197014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // If the result is a smi, it is *not* an object in the ECMA sense.
198c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      __ JumpIfSmi(eax, &use_receiver, Label::kNear);
199014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
200014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // If the type of the result (stored in its map) is less than
201014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense.
202014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ecx);
203c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      __ j(above_equal, &exit, Label::kNear);
204014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
205014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Throw away the result of the constructor invocation and use the
206014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // on-stack receiver as the result.
207014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ bind(&use_receiver);
208014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ mov(eax, Operand(esp, 0));
209014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
210014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Restore the arguments count and leave the construct frame. The
211014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // arguments count is stored below the receiver.
212014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ bind(&exit);
213014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ mov(ebx, Operand(esp, 1 * kPointerSize));
214014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    } else {
215014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ mov(ebx, Operand(esp, 0));
216014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Leave construct frame.
2193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
221109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // ES6 9.2.2. Step 13+
222109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Check that the result is not a Smi, indicating that the constructor result
223109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // from a derived class is neither undefined nor an Object.
224109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  if (check_derived_construct) {
225109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    Label dont_throw;
226109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ JumpIfNotSmi(eax, &dont_throw);
227109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    {
228109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      FrameScope scope(masm, StackFrame::INTERNAL);
229109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject);
230109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    }
231109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ bind(&dont_throw);
232109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  }
233109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Remove caller arguments from the stack and return.
23569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(ecx);
237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize));  // 1 ~ receiver
238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ecx);
239014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (create_implicit_receiver) {
240014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);
241014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
245c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch}  // namespace
246c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch
247e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
248109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Generate_JSConstructStubHelper(masm, false, true, false);
249e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
250e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
251e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
252109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Generate_JSConstructStubHelper(masm, true, false, false);
253014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
254014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
255014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) {
256109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Generate_JSConstructStubHelper(masm, false, false, false);
257109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch}
258109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
259109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochvoid Builtins::Generate_JSBuiltinsConstructStubForDerived(
260109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    MacroAssembler* masm) {
261109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Generate_JSConstructStubHelper(masm, false, false, true);
262014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
263014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
264014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_ConstructedNonConstructable(MacroAssembler* masm) {
265014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  FrameScope scope(masm, StackFrame::INTERNAL);
266014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ push(edi);
267014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CallRuntime(Runtime::kThrowConstructedNonConstructable);
268014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
269014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
270014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochenum IsTagged { kEaxIsSmiTagged, kEaxIsUntaggedInt };
271014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
272014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// Clobbers ecx, edx, edi; preserves all other registers.
273014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochstatic void Generate_CheckStackOverflow(MacroAssembler* masm,
274014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                        IsTagged eax_is_tagged) {
275014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // eax   : the number of items to be pushed to the stack
276014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //
277014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Check the stack for overflow. We are not trying to catch
278014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // interruptions (e.g. debug break and preemption) here, so the "real stack
279014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // limit" is checked.
280014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label okay;
281014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  ExternalReference real_stack_limit =
282014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      ExternalReference::address_of_real_stack_limit(masm->isolate());
283014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(edi, Operand::StaticVariable(real_stack_limit));
284014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Make ecx the space we have left. The stack might already be overflowed
285014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // here which will cause ecx to become negative.
286014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, esp);
287014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ sub(ecx, edi);
288014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Make edx the space we need for the array when it is unrolled onto the
289014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // stack.
290014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(edx, eax);
291014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  int smi_tag = eax_is_tagged == kEaxIsSmiTagged ? kSmiTagSize : 0;
292014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ shl(edx, kPointerSizeLog2 - smi_tag);
293014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Check if the arguments will overflow the stack.
294014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ cmp(ecx, edx);
295014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(greater, &okay);  // Signed comparison.
296014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
297014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Out of stack space.
298014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CallRuntime(Runtime::kThrowStackOverflow);
299014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
300014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&okay);
301e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
302e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                             bool is_construct) {
305b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  ProfileEntryHookStub::MaybeCallEntryHook(masm);
306b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  {
3083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
310014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Setup the context (we need to use the caller context from the isolate).
311014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    ExternalReference context_address(Isolate::kContextAddress,
312014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                      masm->isolate());
313014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(esi, Operand::StaticVariable(context_address));
314014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Load the previous frame pointer (ebx) to access C arguments
3163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(ebx, Operand(ebp, 0));
317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Push the function and the receiver onto the stack.
319014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ push(Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
3203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Load the number of arguments and setup pointer to the arguments.
3233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset));
3243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset));
325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
326014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Check if we have enough stack space to push all arguments.
327014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Expects argument count in eax. Clobbers ecx, edx, edi.
328014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Generate_CheckStackOverflow(masm, kEaxIsUntaggedInt);
329014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Copy arguments to the stack in a loop.
3313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label loop, entry;
332b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ Move(ecx, Immediate(0));
333014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ jmp(&entry, Label::kNear);
3343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&loop);
3353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(edx, Operand(ebx, ecx, times_4, 0));  // push parameter from argv
336f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ push(Operand(edx, 0));                    // dereference handle
3373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ inc(ecx);
3383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&entry);
3393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cmp(ecx, eax);
3403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ j(not_equal, &loop);
3413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
342014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Load the previous frame pointer (ebx) to access C arguments
343014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ebx, Operand(ebp, 0));
344014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
345014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Get the new.target and function from the frame.
346014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(edx, Operand(ebx, EntryFrameConstants::kNewTargetArgOffset));
347014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(edi, Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
3483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Invoke the code.
350014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Handle<Code> builtin = is_construct
351014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                               ? masm->isolate()->builtins()->Construct()
352014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                               : masm->isolate()->builtins()->Call();
353014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Call(builtin, RelocInfo::CODE_TARGET);
354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Exit the internal frame. Notice that this also removes the empty.
3563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // context and the function left on the stack by the code
3573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // invocation.
358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
3593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ ret(kPointerSize);  // Remove receiver.
360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Generate_JSEntryTrampolineHelper(masm, false);
364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Generate_JSEntryTrampolineHelper(masm, true);
368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
370bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch// static
371bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdochvoid Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
372bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // ----------- S t a t e -------------
373bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- eax    : the value to pass to the generator
374bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- ebx    : the JSGeneratorObject to resume
375bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- edx    : the resume mode (tagged)
376bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- esp[0] : return address
377bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // -----------------------------------
378bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ AssertGeneratorObject(ebx);
379bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
380bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Store input value into generator object.
38113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ mov(FieldOperand(ebx, JSGeneratorObject::kInputOrDebugPosOffset), eax);
38213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ RecordWriteField(ebx, JSGeneratorObject::kInputOrDebugPosOffset, eax, ecx,
383bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch                      kDontSaveFPRegs);
384bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
385bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Store resume mode into generator object.
386bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(FieldOperand(ebx, JSGeneratorObject::kResumeModeOffset), edx);
387bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
388bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Load suspended function and context.
389bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(esi, FieldOperand(ebx, JSGeneratorObject::kContextOffset));
390bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(edi, FieldOperand(ebx, JSGeneratorObject::kFunctionOffset));
391bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
392bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Flood function if we are stepping.
39313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  Label prepare_step_in_if_stepping, prepare_step_in_suspended_generator;
39413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  Label stepping_prepared;
39513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  ExternalReference last_step_action =
39613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      ExternalReference::debug_last_step_action_address(masm->isolate());
39713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  STATIC_ASSERT(StepFrame > StepIn);
39813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ cmpb(Operand::StaticVariable(last_step_action), Immediate(StepIn));
39913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ j(greater_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
440bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Dispatch on the kind of generator object.
441bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Label old_generator;
442bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
443bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kFunctionDataOffset));
444bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ CmpObjectType(ecx, BYTECODE_ARRAY_TYPE, ecx);
445bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ j(not_equal, &old_generator);
446bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
447bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // New-style (ignition/turbofan) generator object
448bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  {
449bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ PushReturnAddressFrom(eax);
450bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
451bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ mov(eax,
452f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch           FieldOperand(ecx, SharedFunctionInfo::kFormalParameterCountOffset));
453bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    // We abuse new.target both to indicate that this is a resume call and to
454bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    // pass in the generator object.  In ordinary calls, new.target is always
455bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    // undefined because generator functions are non-constructable.
456bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ mov(edx, ebx);
457bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ jmp(FieldOperand(edi, JSFunction::kCodeEntryOffset));
458bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  }
459bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
460bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Old-style (full-codegen) generator object
461bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ bind(&old_generator);
462bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  {
463bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    // Enter a new JavaScript frame, and initialize its slots as they were when
464bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    // the generator was suspended.
465bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    FrameScope scope(masm, StackFrame::MANUAL);
466bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ PushReturnAddressFrom(eax);  // Return address.
467bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ Push(ebp);                   // Caller's frame pointer.
468bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ Move(ebp, esp);
469bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ Push(esi);  // Callee's context.
470bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ Push(edi);  // Callee's JS Function.
471bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
472bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    // Restore the operand stack.
473bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ mov(eax, FieldOperand(ebx, JSGeneratorObject::kOperandStackOffset));
474bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    {
475bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch      Label done_loop, loop;
476c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      __ Move(ecx, Smi::kZero);
477bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch      __ bind(&loop);
478bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch      __ cmp(ecx, FieldOperand(eax, FixedArray::kLengthOffset));
479bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch      __ j(equal, &done_loop, Label::kNear);
480bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch      __ Push(FieldOperand(eax, ecx, times_half_pointer_size,
481bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch                           FixedArray::kHeaderSize));
482bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch      __ add(ecx, Immediate(Smi::FromInt(1)));
483bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch      __ jmp(&loop);
484bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch      __ bind(&done_loop);
485bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    }
486bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
487bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    // Reset operand stack so we don't leak.
488bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ mov(FieldOperand(ebx, JSGeneratorObject::kOperandStackOffset),
489bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch           Immediate(masm->isolate()->factory()->empty_fixed_array()));
490bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
491bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    // Resume the generator function at the continuation.
492bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
493bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset));
494bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ mov(ecx, FieldOperand(ebx, JSGeneratorObject::kContinuationOffset));
495bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ SmiUntag(ecx);
496bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ lea(edx, FieldOperand(edx, ecx, times_1, Code::kHeaderSize));
497bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ mov(FieldOperand(ebx, JSGeneratorObject::kContinuationOffset),
498bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch           Immediate(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)));
499bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ mov(eax, ebx);  // Continuation expects generator object in eax.
500bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    __ jmp(edx);
501bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  }
50213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
50313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ bind(&prepare_step_in_if_stepping);
50413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  {
50513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
50613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ Push(ebx);
50713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ Push(edx);
50813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ Push(edi);
50913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ CallRuntime(Runtime::kDebugPrepareStepInIfStepping);
51013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ Pop(edx);
51113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ Pop(ebx);
51213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ mov(edi, FieldOperand(ebx, JSGeneratorObject::kFunctionOffset));
51313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  }
51413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ jmp(&stepping_prepared);
51513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
51613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ bind(&prepare_step_in_suspended_generator);
51713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  {
51813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
51913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ Push(ebx);
52013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ Push(edx);
52113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ CallRuntime(Runtime::kDebugPrepareStepInSuspendedGenerator);
52213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ Pop(edx);
52313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ Pop(ebx);
52413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ mov(edi, FieldOperand(ebx, JSGeneratorObject::kFunctionOffset));
52513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  }
52613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ jmp(&stepping_prepared);
52713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch}
52813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
52913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochstatic void LeaveInterpreterFrame(MacroAssembler* masm, Register scratch1,
53013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch                                  Register scratch2) {
53113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  Register args_count = scratch1;
53213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  Register return_pc = scratch2;
53313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
53413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  // Get the arguments + reciever count.
53513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ mov(args_count,
53613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch         Operand(ebp, InterpreterFrameConstants::kBytecodeArrayFromFp));
53713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ mov(args_count,
53813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch         FieldOperand(args_count, BytecodeArray::kParameterSizeOffset));
53913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
54013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  // Leave the frame (also dropping the register file).
54113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ leave();
54213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
54313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  // Drop receiver + arguments.
54413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ pop(return_pc);
54513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ add(esp, args_count);
54613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ push(return_pc);
547bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch}
548a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
549014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// Generate code for entering a JS function with the interpreter.
550014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// On entry to the function the receiver and arguments have been pushed on the
551014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// stack left to right.  The actual argument count matches the formal parameter
552014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// count expected by the function.
553014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch//
554014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// The live registers are:
555014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch//   o edi: the JS function object being called
556014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch//   o edx: the new target
557014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch//   o esi: our context
558014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch//   o ebp: the caller's frame pointer
559014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch//   o esp: stack pointer (pointing to return address)
560014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch//
561109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// The function builds an interpreter frame.  See InterpreterFrameConstants in
562109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// frames.h for its layout.
563014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
564bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  ProfileEntryHookStub::MaybeCallEntryHook(masm);
565bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
566014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Open a frame scope to indicate that there is a frame on the stack.  The
567014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // MANUAL indicates that the scope shouldn't actually generate code to set up
568014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // the frame (that is done below).
569014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  FrameScope frame_scope(masm, StackFrame::MANUAL);
570014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ push(ebp);  // Caller's frame pointer.
571014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ebp, esp);
572014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ push(esi);  // Callee's context.
573014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ push(edi);  // Callee's JS function.
574014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ push(edx);  // Callee's new target.
575014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
576bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Get the bytecode array from the function object (or from the DebugInfo if
577bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // it is present) and load it into kInterpreterBytecodeArrayRegister.
578014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
579109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Label load_debug_bytecode_array, bytecode_array_loaded;
580109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ cmp(FieldOperand(eax, SharedFunctionInfo::kDebugInfoOffset),
581109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch         Immediate(DebugInfo::uninitialized()));
582109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(not_equal, &load_debug_bytecode_array);
583014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(kInterpreterBytecodeArrayRegister,
584014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch         FieldOperand(eax, SharedFunctionInfo::kFunctionDataOffset));
585109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ bind(&bytecode_array_loaded);
586014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
587f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // Check whether we should continue to use the interpreter.
588f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  Label switch_to_different_code_kind;
589f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ Move(ecx, masm->CodeObject());  // Self-reference to this code.
590f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ cmp(ecx, FieldOperand(eax, SharedFunctionInfo::kCodeOffset));
591f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ j(not_equal, &switch_to_different_code_kind);
592f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
593f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Increment invocation count for the function.
594f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ EmitLoadTypeFeedbackVector(ecx);
595f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ add(FieldOperand(ecx,
596f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch                      TypeFeedbackVector::kInvocationCountIndex * kPointerSize +
597f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch                          TypeFeedbackVector::kHeaderSize),
598f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch         Immediate(Smi::FromInt(1)));
599f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
600bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Check function data field is actually a BytecodeArray object.
601014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (FLAG_debug_code) {
602014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ AssertNotSmi(kInterpreterBytecodeArrayRegister);
603014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CmpObjectType(kInterpreterBytecodeArrayRegister, BYTECODE_ARRAY_TYPE,
604014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                     eax);
605014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
606014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
607014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
608109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Push bytecode array.
609109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ push(kInterpreterBytecodeArrayRegister);
610bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Push Smi tagged initial bytecode array offset.
611bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ push(Immediate(Smi::FromInt(BytecodeArray::kHeaderSize - kHeapObjectTag)));
612109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
613014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Allocate the local and temporary register file on the stack.
614014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
615014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Load frame size from the BytecodeArray object.
616014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ebx, FieldOperand(kInterpreterBytecodeArrayRegister,
617014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                             BytecodeArray::kFrameSizeOffset));
618014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
619014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Do a stack check to ensure we don't go over the limit.
620014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label ok;
621014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ecx, esp);
622014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ sub(ecx, ebx);
623014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    ExternalReference stack_limit =
624014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        ExternalReference::address_of_real_stack_limit(masm->isolate());
625014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(ecx, Operand::StaticVariable(stack_limit));
626014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(above_equal, &ok);
627014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CallRuntime(Runtime::kThrowStackOverflow);
628014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&ok);
629014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
630014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // If ok, push undefined as the initial value for all register file entries.
631014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label loop_header;
632014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label loop_check;
633014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(eax, Immediate(masm->isolate()->factory()->undefined_value()));
634014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ jmp(&loop_check);
635014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&loop_header);
636014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // TODO(rmcilroy): Consider doing more than one push per loop iteration.
637014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ push(eax);
638014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Continue loop if not done.
639014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&loop_check);
640014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ sub(ebx, Immediate(kPointerSize));
641014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(greater_equal, &loop_header);
642014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
643014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
644bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Load accumulator, bytecode offset and dispatch table into registers.
645014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
646014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(kInterpreterBytecodeOffsetRegister,
647014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch         Immediate(BytecodeArray::kHeaderSize - kHeapObjectTag));
648bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(kInterpreterDispatchTableRegister,
649bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch         Immediate(ExternalReference::interpreter_dispatch_table_address(
650bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch             masm->isolate())));
651014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
652014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Dispatch to the first bytecode handler for the function.
653bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ movzx_b(ebx, Operand(kInterpreterBytecodeArrayRegister,
654014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                          kInterpreterBytecodeOffsetRegister, times_1, 0));
655bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(ebx, Operand(kInterpreterDispatchTableRegister, ebx,
656bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch                      times_pointer_size, 0));
657014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ call(ebx);
658bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  masm->isolate()->heap()->SetInterpreterEntryReturnPCOffset(masm->pc_offset());
659109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
660bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // The return value is in eax.
66113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  LeaveInterpreterFrame(masm, ebx, ecx);
662014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ ret(0);
663014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
664bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Load debug copy of the bytecode array.
665bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ bind(&load_debug_bytecode_array);
666bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Register debug_info = kInterpreterBytecodeArrayRegister;
667bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(debug_info, FieldOperand(eax, SharedFunctionInfo::kDebugInfoOffset));
668bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(kInterpreterBytecodeArrayRegister,
669f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch         FieldOperand(debug_info, DebugInfo::kDebugBytecodeArrayIndex));
670bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ jmp(&bytecode_array_loaded);
671bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
672f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // If the shared code is no longer this entry trampoline, then the underlying
673f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // function has been switched to a different kind of code and we heal the
674f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // closure by switching the code entry field over to the new code as well.
675f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ bind(&switch_to_different_code_kind);
676bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ pop(edx);  // Callee's new target.
677bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ pop(edi);  // Callee's JS function.
678bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ pop(esi);  // Callee's context.
679bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ leave();   // Leave the frame so we can tail call.
680bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
681bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kCodeOffset));
682bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
683bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(FieldOperand(edi, JSFunction::kCodeEntryOffset), ecx);
684bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ RecordWriteCodeEntryField(edi, ecx, ebx);
685bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ jmp(ecx);
686bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch}
687014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
688f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdochstatic void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args,
689f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch                                        Register scratch1, Register scratch2,
690f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch                                        Label* stack_overflow,
691f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch                                        bool include_receiver = false) {
692f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Check the stack for overflow. We are not trying to catch
693f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // interruptions (e.g. debug break and preemption) here, so the "real stack
694f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // limit" is checked.
695f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  ExternalReference real_stack_limit =
696f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch      ExternalReference::address_of_real_stack_limit(masm->isolate());
697f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ mov(scratch1, Operand::StaticVariable(real_stack_limit));
698f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Make scratch2 the space we have left. The stack might already be overflowed
699f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // here which will cause scratch2 to become negative.
700f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ mov(scratch2, esp);
701f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ sub(scratch2, scratch1);
702f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Make scratch1 the space we need for the array when it is unrolled onto the
703f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // stack.
704f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ mov(scratch1, num_args);
705f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  if (include_receiver) {
706f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ add(scratch1, Immediate(1));
707f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  }
708f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ shl(scratch1, kPointerSizeLog2);
709f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Check if the arguments will overflow the stack.
710f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ cmp(scratch2, scratch1);
711f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ j(less_equal, stack_overflow);  // Signed comparison.
712f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch}
713f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
714014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochstatic void Generate_InterpreterPushArgs(MacroAssembler* masm,
715f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch                                         Register array_limit,
716f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch                                         Register start_address) {
717014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
718f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  //  -- start_address : Pointer to the last argument in the args array.
719014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- array_limit : Pointer to one before the first argument in the
720014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //                   args array.
721014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
722014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label loop_header, loop_check;
723014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ jmp(&loop_check);
724014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&loop_header);
725f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ Push(Operand(start_address, 0));
726f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ sub(start_address, Immediate(kPointerSize));
727014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&loop_check);
728f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ cmp(start_address, array_limit);
729014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(greater, &loop_header, Label::kNear);
730014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
731014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
732014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
733109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochvoid Builtins::Generate_InterpreterPushArgsAndCallImpl(
734f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    MacroAssembler* masm, TailCallMode tail_call_mode,
735f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    CallableType function_type) {
736014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
737014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax : the number of arguments (not including the receiver)
738014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- ebx : the address of the first argument to be pushed. Subsequent
739014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //           arguments should be consecutive above this, in the same order as
740014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //           they are to be pushed onto the stack.
741014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi : the target to call (can be any Object).
742014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
743f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  Label stack_overflow;
744f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Compute the expected number of arguments.
745f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ mov(ecx, eax);
746f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ add(ecx, Immediate(1));  // Add one for receiver.
747f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
748f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Add a stack check before pushing the arguments. We need an extra register
749f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // to perform a stack check. So push it onto the stack temporarily. This
750f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // might cause stack overflow, but it will be detected by the check.
751f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ Push(edi);
752f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  Generate_StackOverflowCheck(masm, ecx, edx, edi, &stack_overflow);
753f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ Pop(edi);
754014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
755014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Pop return address to allow tail-call after pushing arguments.
756014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Pop(edx);
757014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
758014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Find the address of the last argument.
759014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ shl(ecx, kPointerSizeLog2);
760014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ neg(ecx);
761014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ add(ecx, ebx);
762f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  Generate_InterpreterPushArgs(masm, ecx, ebx);
763014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
764014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Call the target.
765014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Push(edx);  // Re-push return address.
766014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
767f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  if (function_type == CallableType::kJSFunction) {
768f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny,
769f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                                                      tail_call_mode),
770f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch            RelocInfo::CODE_TARGET);
771f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  } else {
772f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    DCHECK_EQ(function_type, CallableType::kAny);
773f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
774f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                                              tail_call_mode),
775f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch            RelocInfo::CODE_TARGET);
776f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
777f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
778f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ bind(&stack_overflow);
779f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  {
780f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // Pop the temporary registers, so that return address is on top of stack.
781f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ Pop(edi);
782f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
783f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ TailCallRuntime(Runtime::kThrowStackOverflow);
784f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
785f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // This should be unreachable.
786f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ int3();
787f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  }
788f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}
789014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
790f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdochnamespace {
791f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
792f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch// This function modified start_addr, and only reads the contents of num_args
793f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch// register. scratch1 and scratch2 are used as temporary registers. Their
794f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch// original values are restored after the use.
795f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdochvoid Generate_InterpreterPushArgsAndReturnAddress(
796f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    MacroAssembler* masm, Register num_args, Register start_addr,
797f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    Register scratch1, Register scratch2, bool receiver_in_args,
798f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    int num_slots_above_ret_addr, Label* stack_overflow) {
799f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // We have to move return address and the temporary registers above it
800f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // before we can copy arguments onto the stack. To achieve this:
801f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Step 1: Increment the stack pointer by num_args + 1 (for receiver).
802f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Step 2: Move the return address and values above it to the top of stack.
803f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Step 3: Copy the arguments into the correct locations.
804f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  //  current stack    =====>    required stack layout
805f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // |             |            | scratch1      | (2) <-- esp(1)
806f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // |             |            | ....          | (2)
807f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // |             |            | scratch-n     | (2)
808f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // |             |            | return addr   | (2)
809f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // |             |            | arg N         | (3)
810f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // | scratch1    | <-- esp    | ....          |
811f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // | ....        |            | arg 0         |
812f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // | scratch-n   |            | arg 0         |
813f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // | return addr |            | receiver slot |
814f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
815f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Check for stack overflow before we increment the stack pointer.
816f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  Generate_StackOverflowCheck(masm, num_args, scratch1, scratch2,
817f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch                              stack_overflow, true);
818f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
819f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch// Step 1 - Update the stack pointer. scratch1 already contains the required
820f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch// increment to the stack. i.e. num_args + 1 stack slots. This is computed in
821f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch// the Generate_StackOverflowCheck.
822f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
823f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch#ifdef _MSC_VER
824f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // TODO(mythria): Move it to macro assembler.
825f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // In windows, we cannot increment the stack size by more than one page
826f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // (mimimum page size is 4KB) without accessing at least one byte on the
827f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // page. Check this:
828f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // https://msdn.microsoft.com/en-us/library/aa227153(v=vs.60).aspx.
829f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  const int page_size = 4 * 1024;
830f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  Label check_offset, update_stack_pointer;
831f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ bind(&check_offset);
832f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ cmp(scratch1, page_size);
833f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ j(less, &update_stack_pointer);
834f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ sub(esp, Immediate(page_size));
835f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Just to touch the page, before we increment further.
836f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ mov(Operand(esp, 0), Immediate(0));
837f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ sub(scratch1, Immediate(page_size));
838f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ jmp(&check_offset);
839f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ bind(&update_stack_pointer);
840f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch#endif
841f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
842f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ sub(esp, scratch1);
843f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
844f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Step 2 move return_address and slots above it to the correct locations.
845f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Move from top to bottom, otherwise we may overwrite when num_args = 0 or 1,
846f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // basically when the source and destination overlap. We at least need one
847f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // extra slot for receiver, so no extra checks are required to avoid copy.
848f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  for (int i = 0; i < num_slots_above_ret_addr + 1; i++) {
849f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ mov(scratch1,
850f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch           Operand(esp, num_args, times_pointer_size, (i + 1) * kPointerSize));
851f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ mov(Operand(esp, i * kPointerSize), scratch1);
852f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  }
853f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
854f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Step 3 copy arguments to correct locations.
855f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  if (receiver_in_args) {
856f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ mov(scratch1, num_args);
857f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ add(scratch1, Immediate(1));
858f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  } else {
859f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // Slot meant for receiver contains return address. Reset it so that
860f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // we will not incorrectly interpret return address as an object.
861f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ mov(Operand(esp, num_args, times_pointer_size,
862f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch                   (num_slots_above_ret_addr + 1) * kPointerSize),
863f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch           Immediate(0));
864f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ mov(scratch1, num_args);
865f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  }
866f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
867f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  Label loop_header, loop_check;
868f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ jmp(&loop_check);
869f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ bind(&loop_header);
870f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ mov(scratch2, Operand(start_addr, 0));
871f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ mov(Operand(esp, scratch1, times_pointer_size,
872f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch                 num_slots_above_ret_addr * kPointerSize),
873f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch         scratch2);
874f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ sub(start_addr, Immediate(kPointerSize));
875f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ sub(scratch1, Immediate(1));
876f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ bind(&loop_check);
877f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ cmp(scratch1, Immediate(0));
878f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ j(greater, &loop_header, Label::kNear);
879f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch}
880f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
881f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch}  // end anonymous namespace
882f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
883014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
884f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdochvoid Builtins::Generate_InterpreterPushArgsAndConstructImpl(
885f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    MacroAssembler* masm, CallableType construct_type) {
886014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
887014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax : the number of arguments (not including the receiver)
888014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx : the new target
889014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi : the constructor
890f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  //  -- ebx : allocation site feedback (if available or undefined)
891f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  //  -- ecx : the address of the first argument to be pushed. Subsequent
892014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //           arguments should be consecutive above this, in the same order as
893014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //           they are to be pushed onto the stack.
894014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
895f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  Label stack_overflow;
896f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // We need two scratch registers. Push edi and edx onto stack.
897f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ Push(edi);
898f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ Push(edx);
899014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
900f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Push arguments and move return address to the top of stack.
901f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // The eax register is readonly. The ecx register will be modified. The edx
902f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // and edi registers will be modified but restored to their original values.
903f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  Generate_InterpreterPushArgsAndReturnAddress(masm, eax, ecx, edx, edi, false,
904f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch                                               2, &stack_overflow);
905014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
906f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Restore edi and edx
907f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ Pop(edx);
908f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ Pop(edi);
909f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
910f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ AssertUndefinedOrAllocationSite(ebx);
911f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  if (construct_type == CallableType::kJSFunction) {
912f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // Tail call to the function-specific construct stub (still in the caller
913f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // context at this point).
914f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ AssertFunction(edi);
915f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
916f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
917f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset));
918f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
919f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ jmp(ecx);
920f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  } else {
921f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    DCHECK_EQ(construct_type, CallableType::kAny);
922014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
923f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // Call the constructor with unmodified eax, edi, edx values.
924f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
925f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  }
926014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
927f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ bind(&stack_overflow);
928f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  {
929f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // Pop the temporary registers, so that return address is on top of stack.
930f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ Pop(edx);
931f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ Pop(edi);
932f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
933f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ TailCallRuntime(Runtime::kThrowStackOverflow);
934014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
935f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // This should be unreachable.
936f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ int3();
937f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  }
938f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch}
939f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
940f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch// static
941f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdochvoid Builtins::Generate_InterpreterPushArgsAndConstructArray(
942f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    MacroAssembler* masm) {
943f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // ----------- S t a t e -------------
944f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  //  -- eax : the number of arguments (not including the receiver)
945f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  //  -- edx : the target to call checked to be Array function.
946f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  //  -- ebx : the allocation site feedback
947f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  //  -- ecx : the address of the first argument to be pushed. Subsequent
948f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  //           arguments should be consecutive above this, in the same order as
949f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  //           they are to be pushed onto the stack.
950f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // -----------------------------------
951f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  Label stack_overflow;
952f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // We need two scratch registers. Register edi is available, push edx onto
953f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // stack.
954f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ Push(edx);
955014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
956f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Push arguments and move return address to the top of stack.
957f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // The eax register is readonly. The ecx register will be modified. The edx
958f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // and edi registers will be modified but restored to their original values.
959f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  Generate_InterpreterPushArgsAndReturnAddress(masm, eax, ecx, edx, edi, true,
960f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch                                               1, &stack_overflow);
961014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
962f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Restore edx.
963f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ Pop(edx);
964f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
965f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Array constructor expects constructor in edi. It is same as edx here.
966f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ Move(edi, edx);
967f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
968f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  ArrayConstructorStub stub(masm->isolate());
969f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ TailCallStub(&stub);
970f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
971f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ bind(&stack_overflow);
972f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  {
973f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // Pop the temporary registers, so that return address is on top of stack.
974f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ Pop(edx);
975f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
976f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ TailCallRuntime(Runtime::kThrowStackOverflow);
977f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch
978f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // This should be unreachable.
979f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ int3();
980f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  }
981014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
982014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
983c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdochstatic void Generate_InterpreterEnterBytecode(MacroAssembler* masm) {
984bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Set the return address to the correct point in the interpreter entry
985bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // trampoline.
986bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Smi* interpreter_entry_return_pc_offset(
987bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch      masm->isolate()->heap()->interpreter_entry_return_pc_offset());
988c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  DCHECK_NE(interpreter_entry_return_pc_offset, Smi::kZero);
989bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ LoadHeapObject(ebx,
990bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch                    masm->isolate()->builtins()->InterpreterEntryTrampoline());
991bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ add(ebx, Immediate(interpreter_entry_return_pc_offset->value() +
992bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch                        Code::kHeaderSize - kHeapObjectTag));
993bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ push(ebx);
994014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
995bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Initialize the dispatch table register.
996bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(kInterpreterDispatchTableRegister,
997bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch         Immediate(ExternalReference::interpreter_dispatch_table_address(
998bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch             masm->isolate())));
999014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1000014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Get the bytecode array pointer from the frame.
1001014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(kInterpreterBytecodeArrayRegister,
1002bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch         Operand(ebp, InterpreterFrameConstants::kBytecodeArrayFromFp));
1003014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1004014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (FLAG_debug_code) {
1005014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Check function data field is actually a BytecodeArray object.
1006014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ AssertNotSmi(kInterpreterBytecodeArrayRegister);
1007014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CmpObjectType(kInterpreterBytecodeArrayRegister, BYTECODE_ARRAY_TYPE,
1008014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                     ebx);
1009014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
1010014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
1011014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1012014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Get the target bytecode offset from the frame.
1013bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(kInterpreterBytecodeOffsetRegister,
1014bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch         Operand(ebp, InterpreterFrameConstants::kBytecodeOffsetFromFp));
1015014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ SmiUntag(kInterpreterBytecodeOffsetRegister);
1016014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1017014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Dispatch to the target bytecode.
1018bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ movzx_b(ebx, Operand(kInterpreterBytecodeArrayRegister,
1019014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                          kInterpreterBytecodeOffsetRegister, times_1, 0));
1020bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(ebx, Operand(kInterpreterDispatchTableRegister, ebx,
1021bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch                      times_pointer_size, 0));
1022014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ jmp(ebx);
1023014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
1024014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1025c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdochvoid Builtins::Generate_InterpreterEnterBytecodeAdvance(MacroAssembler* masm) {
1026c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // Advance the current bytecode offset stored within the given interpreter
1027c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // stack frame. This simulates what all bytecode handlers do upon completion
1028c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // of the underlying operation.
1029c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ mov(ebx, Operand(ebp, InterpreterFrameConstants::kBytecodeArrayFromFp));
1030c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ mov(edx, Operand(ebp, InterpreterFrameConstants::kBytecodeOffsetFromFp));
1031c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
1032c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  {
1033c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
1034c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    __ Push(kInterpreterAccumulatorRegister);
1035c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    __ Push(ebx);  // First argument is the bytecode array.
1036c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    __ Push(edx);  // Second argument is the bytecode offset.
1037c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    __ CallRuntime(Runtime::kInterpreterAdvanceBytecodeOffset);
1038c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    __ Move(edx, eax);  // Result is the new bytecode offset.
1039c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    __ Pop(kInterpreterAccumulatorRegister);
1040c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  }
1041c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ mov(Operand(ebp, InterpreterFrameConstants::kBytecodeOffsetFromFp), edx);
1042c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch
1043c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  Generate_InterpreterEnterBytecode(masm);
1044c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch}
1045c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch
1046c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdochvoid Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
1047c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  Generate_InterpreterEnterBytecode(masm);
1048c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch}
1049c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch
1050014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_CompileLazy(MacroAssembler* masm) {
1051bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // ----------- S t a t e -------------
1052bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- eax : argument count (preserved for callee)
1053bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- edx : new target (preserved for callee)
1054bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- edi : target function (preserved for callee)
1055bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // -----------------------------------
1056bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // First lookup code, maybe we don't need to compile!
1057bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Label gotta_call_runtime, gotta_call_runtime_no_stack;
1058bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Label try_shared;
1059bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Label loop_top, loop_bottom;
1060bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1061bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Register closure = edi;
1062bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Register new_target = edx;
1063bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Register argument_count = eax;
1064bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1065bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ push(argument_count);
1066bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ push(new_target);
1067bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ push(closure);
1068bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1069bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Register map = argument_count;
1070bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Register index = ebx;
1071bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(map, FieldOperand(closure, JSFunction::kSharedFunctionInfoOffset));
1072bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(map, FieldOperand(map, SharedFunctionInfo::kOptimizedCodeMapOffset));
1073bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(index, FieldOperand(map, FixedArray::kLengthOffset));
1074bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ cmp(index, Immediate(Smi::FromInt(2)));
1075bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ j(less, &gotta_call_runtime);
1076bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1077bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Find literals.
1078bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // edx : native context
1079bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // ebx : length / index
1080bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // eax : optimized code map
1081bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // stack[0] : new target
1082bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // stack[4] : closure
1083bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Register native_context = edx;
1084bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(native_context, NativeContextOperand());
1085bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1086bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ bind(&loop_top);
1087bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Register temp = edi;
1088bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1089bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Does the native context match?
1090bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(temp, FieldOperand(map, index, times_half_pointer_size,
1091bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch                            SharedFunctionInfo::kOffsetToPreviousContext));
1092bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(temp, FieldOperand(temp, WeakCell::kValueOffset));
1093bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ cmp(temp, native_context);
1094bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ j(not_equal, &loop_bottom);
1095bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // OSR id set to none?
1096bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(temp, FieldOperand(map, index, times_half_pointer_size,
1097bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch                            SharedFunctionInfo::kOffsetToPreviousOsrAstId));
1098bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  const int bailout_id = BailoutId::None().ToInt();
1099bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ cmp(temp, Immediate(Smi::FromInt(bailout_id)));
1100bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ j(not_equal, &loop_bottom);
1101bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Literals available?
1102bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(temp, FieldOperand(map, index, times_half_pointer_size,
1103bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch                            SharedFunctionInfo::kOffsetToPreviousLiterals));
1104bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(temp, FieldOperand(temp, WeakCell::kValueOffset));
1105f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ JumpIfSmi(temp, &gotta_call_runtime);
1106bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1107bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Save the literals in the closure.
1108bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(ecx, Operand(esp, 0));
1109bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(FieldOperand(ecx, JSFunction::kLiteralsOffset), temp);
1110bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ push(index);
1111bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ RecordWriteField(ecx, JSFunction::kLiteralsOffset, temp, index,
1112bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch                      kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
1113bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ pop(index);
1114bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1115bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Code available?
1116bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Register entry = ecx;
1117bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(entry, FieldOperand(map, index, times_half_pointer_size,
1118bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch                             SharedFunctionInfo::kOffsetToPreviousCachedCode));
1119bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(entry, FieldOperand(entry, WeakCell::kValueOffset));
1120c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ JumpIfSmi(entry, &try_shared);
1121bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1122bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Found literals and code. Get them into the closure and return.
1123bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ pop(closure);
1124bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Store code entry in the closure.
1125bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ lea(entry, FieldOperand(entry, Code::kHeaderSize));
1126bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(FieldOperand(closure, JSFunction::kCodeEntryOffset), entry);
1127bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ RecordWriteCodeEntryField(closure, entry, eax);
1128bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1129bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Link the closure into the optimized function list.
1130bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // ecx : code entry
1131bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // edx : native context
1132bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // edi : closure
1133bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(ebx,
1134bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch         ContextOperand(native_context, Context::OPTIMIZED_FUNCTIONS_LIST));
1135bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(FieldOperand(closure, JSFunction::kNextFunctionLinkOffset), ebx);
1136bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ RecordWriteField(closure, JSFunction::kNextFunctionLinkOffset, ebx, eax,
1137bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch                      kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
1138bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  const int function_list_offset =
1139bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch      Context::SlotOffset(Context::OPTIMIZED_FUNCTIONS_LIST);
1140bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(ContextOperand(native_context, Context::OPTIMIZED_FUNCTIONS_LIST),
1141bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch         closure);
1142bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Save closure before the write barrier.
1143bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(ebx, closure);
1144bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ RecordWriteContextSlot(native_context, function_list_offset, closure, eax,
1145bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch                            kDontSaveFPRegs);
1146bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(closure, ebx);
1147bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ pop(new_target);
1148bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ pop(argument_count);
1149bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ jmp(entry);
1150bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1151bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ bind(&loop_bottom);
1152bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ sub(index, Immediate(Smi::FromInt(SharedFunctionInfo::kEntryLength)));
1153bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ cmp(index, Immediate(Smi::FromInt(1)));
1154bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ j(greater, &loop_top);
1155bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1156bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // We found neither literals nor code.
1157bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ jmp(&gotta_call_runtime);
1158bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1159bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ bind(&try_shared);
1160c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ pop(closure);
1161bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ pop(new_target);
1162bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ pop(argument_count);
1163bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(entry, FieldOperand(closure, JSFunction::kSharedFunctionInfoOffset));
1164c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // Is the shared function marked for tier up?
1165c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ test_b(FieldOperand(entry, SharedFunctionInfo::kMarkedForTierUpByteOffset),
1166c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch            Immediate(1 << SharedFunctionInfo::kMarkedForTierUpBitWithinByte));
1167c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ j(not_zero, &gotta_call_runtime_no_stack);
1168c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // Is the full code valid?
1169bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(entry, FieldOperand(entry, SharedFunctionInfo::kCodeOffset));
1170bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(ebx, FieldOperand(entry, Code::kFlagsOffset));
1171bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ and_(ebx, Code::KindField::kMask);
1172bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ shr(ebx, Code::KindField::kShift);
1173bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ cmp(ebx, Immediate(Code::BUILTIN));
1174bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ j(equal, &gotta_call_runtime_no_stack);
1175bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Yes, install the full code.
1176bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ lea(entry, FieldOperand(entry, Code::kHeaderSize));
1177bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ mov(FieldOperand(closure, JSFunction::kCodeEntryOffset), entry);
1178bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ RecordWriteCodeEntryField(closure, entry, ebx);
1179bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ jmp(entry);
1180bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1181bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ bind(&gotta_call_runtime);
1182bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ pop(closure);
1183bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ pop(new_target);
1184bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ pop(argument_count);
1185bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ bind(&gotta_call_runtime_no_stack);
1186bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1187109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy);
1188b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1189756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
1190bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdochvoid Builtins::Generate_CompileBaseline(MacroAssembler* masm) {
1191bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  GenerateTailCallToReturnedCode(masm, Runtime::kCompileBaseline);
1192bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch}
1193b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1194b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
1195109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  GenerateTailCallToReturnedCode(masm,
1196109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                                 Runtime::kCompileOptimized_NotConcurrent);
1197756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick}
1198756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
1199b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) {
1200109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  GenerateTailCallToReturnedCode(masm, Runtime::kCompileOptimized_Concurrent);
1201b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1202b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1203f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochvoid Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
1204f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // ----------- S t a t e -------------
1205f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  //  -- eax : argument count (preserved for callee)
1206f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  //  -- edx : new target (preserved for callee)
1207f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  //  -- edi : target function (preserved for callee)
1208f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // -----------------------------------
1209f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  Label failed;
1210f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  {
1211f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
1212f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // Preserve argument count for later compare.
1213f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ mov(ecx, eax);
1214f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // Push the number of arguments to the callee.
1215f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ SmiTag(eax);
1216f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ push(eax);
1217f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // Push a copy of the target function and the new target.
1218f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ push(edi);
1219f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ push(edx);
1220f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
1221f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // The function.
1222f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ push(edi);
1223f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // Copy arguments from caller (stdlib, foreign, heap).
1224f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    Label args_done;
1225f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    for (int j = 0; j < 4; ++j) {
1226f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      Label over;
1227f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      if (j < 3) {
1228f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        __ cmp(ecx, Immediate(j));
1229f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        __ j(not_equal, &over, Label::kNear);
1230f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      }
1231f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      for (int i = j - 1; i >= 0; --i) {
1232f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        __ Push(Operand(
1233f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch            ebp, StandardFrameConstants::kCallerSPOffset + i * kPointerSize));
1234f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      }
1235f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      for (int i = 0; i < 3 - j; ++i) {
1236f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        __ PushRoot(Heap::kUndefinedValueRootIndex);
1237f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      }
1238f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      if (j < 3) {
1239f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        __ jmp(&args_done, Label::kNear);
1240f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        __ bind(&over);
1241f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      }
1242f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    }
1243f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ bind(&args_done);
1244f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
1245f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // Call runtime, on success unwind frame, and parent frame.
1246f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ CallRuntime(Runtime::kInstantiateAsmJs, 4);
1247f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // A smi 0 is returned on failure, an object on success.
1248f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ JumpIfSmi(eax, &failed, Label::kNear);
1249f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
1250f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ Drop(2);
1251f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ Pop(ecx);
1252f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ SmiUntag(ecx);
1253f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    scope.GenerateLeaveFrame();
1254f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
1255f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ PopReturnAddressTo(ebx);
1256f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ inc(ecx);
1257f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ lea(esp, Operand(esp, ecx, times_pointer_size, 0));
1258f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ PushReturnAddressFrom(ebx);
1259f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ ret(0);
1260f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
1261f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ bind(&failed);
1262f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // Restore target function and new target.
1263f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ pop(edx);
1264f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ pop(edi);
1265f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ pop(eax);
1266f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ SmiUntag(eax);
1267f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
1268f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // On failure, tail call back to regular js.
1269f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy);
1270f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}
1271b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1272b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochstatic void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
1273b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // For now, we are relying on the fact that make_code_young doesn't do any
1274b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // garbage collection which allows us to save/restore the registers without
1275b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // worrying about which of them contain pointers. We also don't build an
1276b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // internal frame to make the code faster, since we shouldn't have to do stack
1277b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // crawls in MakeCodeYoung. This seems a bit fragile.
1278b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1279b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Re-execute the code that was patched back to the young age when
1280b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // the stub returns.
1281b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ sub(Operand(esp, 0), Immediate(5));
1282b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ pushad();
1283b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(eax, Operand(esp, 8 * kPointerSize));
12843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  {
1285b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    FrameScope scope(masm, StackFrame::MANUAL);
1286b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ PrepareCallCFunction(2, ebx);
1287b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ mov(Operand(esp, 1 * kPointerSize),
1288b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch           Immediate(ExternalReference::isolate_address(masm->isolate())));
1289b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ mov(Operand(esp, 0), eax);
1290b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ CallCFunction(
1291b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        ExternalReference::get_make_code_young_function(masm->isolate()), 2);
1292b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1293b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ popad();
1294b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ ret(0);
1295b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1296b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1297f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C)                  \
1298f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \
1299f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      MacroAssembler* masm) {                                 \
1300f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    GenerateMakeCodeYoungAgainCommon(masm);                   \
1301f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }                                                           \
1302f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  void Builtins::Generate_Make##C##CodeYoungAgainOddMarking(  \
1303f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      MacroAssembler* masm) {                                 \
1304f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    GenerateMakeCodeYoungAgainCommon(masm);                   \
1305f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
1306b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochCODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
1307b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
1308b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1309b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
1310b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact
1311b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // that make_code_young doesn't do any garbage collection which allows us to
1312b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // save/restore the registers without worrying about which of them contain
1313b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // pointers.
1314b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ pushad();
1315b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(eax, Operand(esp, 8 * kPointerSize));
1316b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ sub(eax, Immediate(Assembler::kCallInstructionLength));
1317b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  {  // NOLINT
1318b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    FrameScope scope(masm, StackFrame::MANUAL);
1319b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ PrepareCallCFunction(2, ebx);
1320b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ mov(Operand(esp, 1 * kPointerSize),
1321b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch           Immediate(ExternalReference::isolate_address(masm->isolate())));
1322b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ mov(Operand(esp, 0), eax);
1323b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ CallCFunction(
1324b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        ExternalReference::get_mark_code_as_executed_function(masm->isolate()),
1325b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        2);
1326b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1327b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ popad();
1328b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1329b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Perform prologue operations usually performed by the young code stub.
1330b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ pop(eax);   // Pop return address into scratch register.
1331b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ push(ebp);  // Caller's frame pointer.
1332b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(ebp, esp);
1333b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ push(esi);  // Callee's context.
1334b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ push(edi);  // Callee's JS Function.
1335b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ push(eax);  // Push return address after frame prologue.
1336b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1337b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Jump to point after the code-age stub.
1338b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ ret(0);
1339b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1340b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1341b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
1342b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  GenerateMakeCodeYoungAgainCommon(masm);
1343b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1344b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1345014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_MarkCodeAsToBeExecutedOnce(MacroAssembler* masm) {
1346014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Generate_MarkCodeAsExecutedOnce(masm);
1347014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
1348014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1349b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochstatic void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
1350b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                             SaveFPRegsMode save_doubles) {
1351b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Enter an internal frame.
1352b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  {
1353b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
1354b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1355b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Preserve registers across notification, this is important for compiled
1356b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // stubs that tail call the runtime on deopts passing their parameters in
1357b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // registers.
1358b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ pushad();
1359014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CallRuntime(Runtime::kNotifyStubFailure, save_doubles);
1360b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ popad();
13613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Tear down internal frame.
13623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
1363b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1364b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ pop(MemOperand(esp, 0));  // Ignore state offset
1365b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ ret(0);  // Return to IC Miss stub, continuation still on stack.
1366b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1367b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1368b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
1369b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
1370b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1371b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1372b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
1373b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
1374b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1375b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1376b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochstatic void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
1377b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                             Deoptimizer::BailoutType type) {
13783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  {
13793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
1380b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
13813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Pass deoptimization type to the runtime system.
13823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ push(Immediate(Smi::FromInt(static_cast<int>(type))));
1383014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CallRuntime(Runtime::kNotifyDeoptimized);
1384b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
13853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Tear down internal frame.
13863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
1387b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1388b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Get the full codegen state from the stack and untag it.
1389b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ecx, Operand(esp, 1 * kPointerSize));
1390b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ SmiUntag(ecx);
1391b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1392b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Switch on the state.
1393257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_no_registers, not_tos_eax;
1394bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ cmp(ecx, static_cast<int>(Deoptimizer::BailoutState::NO_REGISTERS));
1395257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &not_no_registers, Label::kNear);
1396b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ret(1 * kPointerSize);  // Remove state.
1397b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1398b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&not_no_registers);
1399bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  DCHECK_EQ(kInterpreterAccumulatorRegister.code(), eax.code());
1400b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(eax, Operand(esp, 2 * kPointerSize));
1401bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ cmp(ecx, static_cast<int>(Deoptimizer::BailoutState::TOS_REGISTER));
1402257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &not_tos_eax, Label::kNear);
1403b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ret(2 * kPointerSize);  // Remove state, eax.
1404b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1405b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&not_tos_eax);
1406b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ Abort(kNoCasesLeft);
1407b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1408b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1409b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
1410b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
1411b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1412b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1413b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
1414b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
1415b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1416b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1417b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
1418b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
1419b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1420b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1421014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
1422014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
1423014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
1424014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax     : argc
1425014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[0]  : return address
1426014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[4]  : argArray
1427014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[8]  : thisArg
1428014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[12] : receiver
1429014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
1430014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1431014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 1. Load receiver into edi, argArray into eax (if present), remove all
1432014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // arguments from the stack (including the receiver), and push thisArg (if
1433014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // present) instead.
1434014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1435014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label no_arg_array, no_this_arg;
1436014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
1437014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ebx, edx);
1438014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize));
1439014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ test(eax, eax);
1440014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(zero, &no_this_arg, Label::kNear);
1441014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    {
1442014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ mov(edx, Operand(esp, eax, times_pointer_size, 0));
1443014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ cmp(eax, Immediate(1));
1444014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ j(equal, &no_arg_array, Label::kNear);
1445014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ mov(ebx, Operand(esp, eax, times_pointer_size, -kPointerSize));
1446014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ bind(&no_arg_array);
14473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
1448014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&no_this_arg);
1449014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PopReturnAddressTo(ecx);
1450014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1451014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Push(edx);
1452014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PushReturnAddressFrom(ecx);
1453014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Move(eax, ebx);
1454014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
1455014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1456014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
1457014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax    : argArray
1458014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi    : receiver
1459014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[0] : return address
1460014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[4] : thisArg
1461014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
1462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1463014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 2. Make sure the receiver is actually callable.
1464014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label receiver_not_callable;
1465014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ JumpIfSmi(edi, &receiver_not_callable, Label::kNear);
1466014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
14673b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
14683b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch            Immediate(1 << Map::kIsCallable));
1469014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(zero, &receiver_not_callable, Label::kNear);
1470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1471014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 3. Tail call with no arguments if argArray is null or undefined.
1472014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label no_arguments;
1473014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ JumpIfRoot(eax, Heap::kNullValueRootIndex, &no_arguments, Label::kNear);
1474014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ JumpIfRoot(eax, Heap::kUndefinedValueRootIndex, &no_arguments,
1475014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                Label::kNear);
1476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1477014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 4a. Apply the receiver to the given argArray (passing undefined for
1478014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // new.target).
1479014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
1480014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1482014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 4b. The argArray is either null or undefined, so we tail call without any
1483014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // arguments to the receiver.
1484014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&no_arguments);
1485014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1486014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Set(eax, 0);
1487014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1488e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  }
1489e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
1490014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 4c. The receiver is not callable, throw an appropriate TypeError.
1491014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&receiver_not_callable);
1492014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1493014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(Operand(esp, kPointerSize), edi);
1494014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ TailCallRuntime(Runtime::kThrowApplyNonFunction);
1495014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
1496014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
1497014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1498014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
1499014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) {
1500014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Stack Layout:
1501014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // esp[0]           : Return address
1502014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // esp[8]           : Argument n
1503014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // esp[16]          : Argument n-1
1504014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  ...
1505014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // esp[8 * n]       : Argument 1
1506014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // esp[8 * (n + 1)] : Receiver (callable to call)
1507014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //
1508014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // eax contains the number of arguments, n, not counting the receiver.
1509014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //
1510014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 1. Make sure we have at least one argument.
1511014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1512014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label done;
1513014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ test(eax, eax);
1514014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(not_zero, &done, Label::kNear);
1515014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PopReturnAddressTo(ebx);
1516014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PushRoot(Heap::kUndefinedValueRootIndex);
1517014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PushReturnAddressFrom(ebx);
1518014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ inc(eax);
1519014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&done);
1520014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
1521589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch
1522014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 2. Get the callable to call (passed as receiver) from the stack.
1523014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize));
1524402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
1525014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 3. Shift arguments and return address one slot down on the stack
1526402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //    (overwriting the original receiver).  Adjust argument count to make
1527402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //    the original first argument the new receiver.
1528014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1529014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label loop;
1530e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ mov(ecx, eax);
1531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&loop);
1532014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ebx, Operand(esp, ecx, times_pointer_size, 0));
1533014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(Operand(esp, ecx, times_pointer_size, kPointerSize), ebx);
1534a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ dec(ecx);
1535402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ j(not_sign, &loop);  // While non-negative (to copy return address).
1536014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ pop(ebx);            // Discard copy of return address.
1537e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ dec(eax);  // One fewer argument (first argument is new receiver).
1538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1540014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 4. Call the callable.
1541014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1544014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_ReflectApply(MacroAssembler* masm) {
1545014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
1546014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax     : argc
1547014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[0]  : return address
1548014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[4]  : argumentsList
1549014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[8]  : thisArgument
1550014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[12] : target
1551014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[16] : receiver
1552014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
1553014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1554014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 1. Load target into edi (if present), argumentsList into eax (if present),
1555014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // remove all arguments from the stack (including the receiver), and push
1556014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // thisArgument (if present) instead.
15573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  {
1558014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label done;
1559014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ LoadRoot(edi, Heap::kUndefinedValueRootIndex);
1560014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(edx, edi);
1561014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ebx, edi);
1562014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(eax, Immediate(1));
1563014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(below, &done, Label::kNear);
1564014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(edi, Operand(esp, eax, times_pointer_size, -0 * kPointerSize));
1565014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(equal, &done, Label::kNear);
1566014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(edx, Operand(esp, eax, times_pointer_size, -1 * kPointerSize));
1567014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(eax, Immediate(3));
1568014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(below, &done, Label::kNear);
1569014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ebx, Operand(esp, eax, times_pointer_size, -2 * kPointerSize));
1570014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&done);
1571014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PopReturnAddressTo(ecx);
1572014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1573014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Push(edx);
1574014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PushReturnAddressFrom(ecx);
1575014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Move(eax, ebx);
1576014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
15773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1578014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
1579014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax    : argumentsList
1580014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi    : target
1581014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[0] : return address
1582014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[4] : thisArgument
1583014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
15843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1585014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 2. Make sure the target is actually callable.
1586014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label target_not_callable;
1587014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ JumpIfSmi(edi, &target_not_callable, Label::kNear);
1588014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
15893b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
15903b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch            Immediate(1 << Map::kIsCallable));
1591014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(zero, &target_not_callable, Label::kNear);
15923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1593014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 3a. Apply the target to the given argumentsList (passing undefined for
1594014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // new.target).
1595014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
1596014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1597a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1598014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 3b. The target is not callable, throw an appropriate TypeError.
1599014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&target_not_callable);
1600014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1601014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(Operand(esp, kPointerSize), edi);
1602014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ TailCallRuntime(Runtime::kThrowApplyNonFunction);
1603014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
1604014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
1605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1606014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
1607014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
1608014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax     : argc
1609014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[0]  : return address
1610014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[4]  : new.target (optional)
1611014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[8]  : argumentsList
1612014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[12] : target
1613014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[16] : receiver
1614014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
1615589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch
1616014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 1. Load target into edi (if present), argumentsList into eax (if present),
1617014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // new.target into edx (if present, otherwise use target), remove all
1618014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // arguments from the stack (including the receiver), and push thisArgument
1619014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // (if present) instead.
1620014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1621014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label done;
1622014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ LoadRoot(edi, Heap::kUndefinedValueRootIndex);
1623014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(edx, edi);
1624014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ebx, edi);
1625014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(eax, Immediate(1));
1626014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(below, &done, Label::kNear);
1627014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(edi, Operand(esp, eax, times_pointer_size, -0 * kPointerSize));
1628014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(edx, edi);
1629014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(equal, &done, Label::kNear);
1630014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ebx, Operand(esp, eax, times_pointer_size, -1 * kPointerSize));
1631014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(eax, Immediate(3));
1632014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(below, &done, Label::kNear);
1633014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(edx, Operand(esp, eax, times_pointer_size, -2 * kPointerSize));
1634014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&done);
1635014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PopReturnAddressTo(ecx);
1636014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1637014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PushRoot(Heap::kUndefinedValueRootIndex);
1638014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PushReturnAddressFrom(ecx);
1639014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Move(eax, ebx);
1640014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
1641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1642014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
1643014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax    : argumentsList
1644014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx    : new.target
1645014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi    : target
1646014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[0] : return address
1647014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[4] : receiver (undefined)
1648014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
16493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1650014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 2. Make sure the target is actually a constructor.
1651014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label target_not_constructor;
1652014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ JumpIfSmi(edi, &target_not_constructor, Label::kNear);
1653014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
16543b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
16553b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch            Immediate(1 << Map::kIsConstructor));
1656014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(zero, &target_not_constructor, Label::kNear);
1657014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1658014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 3. Make sure the target is actually a constructor.
1659014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label new_target_not_constructor;
1660014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ JumpIfSmi(edx, &new_target_not_constructor, Label::kNear);
1661014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
16623b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
16633b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch            Immediate(1 << Map::kIsConstructor));
1664014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(zero, &new_target_not_constructor, Label::kNear);
1665014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1666014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 4a. Construct the target with the given new.target and argumentsList.
1667014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1668014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1669014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 4b. The target is not a constructor, throw an appropriate TypeError.
1670014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&target_not_constructor);
1671014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1672014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(Operand(esp, kPointerSize), edi);
1673014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ TailCallRuntime(Runtime::kThrowCalledNonCallable);
1674014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
1675a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1676014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 4c. The new.target is not a constructor, throw an appropriate TypeError.
1677014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&new_target_not_constructor);
1678014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1679014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(Operand(esp, kPointerSize), edx);
1680014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ TailCallRuntime(Runtime::kThrowCalledNonCallable);
16813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
1682592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch}
1683a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
16843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
16853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // ----------- S t a t e -------------
16863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  //  -- eax : argc
16873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  //  -- esp[0] : return address
16883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  //  -- esp[4] : last argument
16893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // -----------------------------------
16903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label generic_array_code;
16913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
16923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Get the InternalArray function.
16933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi);
16943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
16953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (FLAG_debug_code) {
16963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Initial map for the builtin InternalArray function should be a map.
16973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
16983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Will both indicate a NULL and a Smi.
16993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ test(ebx, Immediate(kSmiTagMask));
1700b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ Assert(not_zero, kUnexpectedInitialMapForInternalArrayFunction);
17013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ CmpObjectType(ebx, MAP_TYPE, ecx);
1702b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ Assert(equal, kUnexpectedInitialMapForInternalArrayFunction);
17033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
17043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
17053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Run the native code for the InternalArray function called as a normal
17063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // function.
1707b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // tail call a stub
1708b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  InternalArrayConstructorStub stub(masm->isolate());
1709b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ TailCallStub(&stub);
17103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
17113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Builtins::Generate_ArrayCode(MacroAssembler* masm) {
1713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1714a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax : argc
1715a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1716a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[4] : last argument
1717a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
171825f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen  Label generic_array_code;
1719a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1720a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the Array function.
172180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi);
1722014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(edx, edi);
1723a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1724a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (FLAG_debug_code) {
17253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Initial map for the builtin Array function should be a map.
1726a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1727a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Will both indicate a NULL and a Smi.
1728a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ test(ebx, Immediate(kSmiTagMask));
1729b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction);
1730a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ CmpObjectType(ebx, MAP_TYPE, ecx);
1731b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ Assert(equal, kUnexpectedInitialMapForArrayFunction);
1732a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1733a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1734a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Run the native code for the Array function called as a normal function.
1735b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // tail call a stub
1736b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(ebx, masm->isolate()->factory()->undefined_value());
1737b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  ArrayConstructorStub stub(masm->isolate());
1738b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ TailCallStub(&stub);
1739a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1740a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1741014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
1742109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochvoid Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
1743109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // ----------- S t a t e -------------
1744109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  //  -- eax                 : number of arguments
174513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  //  -- edi                 : function
174613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  //  -- esi                 : context
1747109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  //  -- esp[0]              : return address
1748109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  //  -- esp[(argc - n) * 8] : arg[n] (zero-based)
1749109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  //  -- esp[(argc + 1) * 8] : receiver
1750109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // -----------------------------------
1751109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Condition const cc = (kind == MathMaxMinKind::kMin) ? below : above;
1752109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Heap::RootListIndex const root_index =
1753109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      (kind == MathMaxMinKind::kMin) ? Heap::kInfinityValueRootIndex
1754109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                                     : Heap::kMinusInfinityValueRootIndex;
1755109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  XMMRegister const reg = (kind == MathMaxMinKind::kMin) ? xmm1 : xmm0;
1756109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1757109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Load the accumulator with the default return value (either -Infinity or
1758109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // +Infinity), with the tagged value in edx and the double value in xmm0.
1759109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ LoadRoot(edx, root_index);
1760109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ movsd(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
1761109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ Move(ecx, eax);
1762109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1763109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Label done_loop, loop;
1764109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ bind(&loop);
1765109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  {
1766109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Check if all parameters done.
1767109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ test(ecx, ecx);
1768109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ j(zero, &done_loop);
1769109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1770109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Load the next parameter tagged value into ebx.
1771109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ mov(ebx, Operand(esp, ecx, times_pointer_size, 0));
1772109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1773109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Load the double value of the parameter into xmm1, maybe converting the
177413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    // parameter to a number first using the ToNumber builtin if necessary.
1775109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    Label convert, convert_smi, convert_number, done_convert;
1776109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ bind(&convert);
1777109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ JumpIfSmi(ebx, &convert_smi);
1778109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ JumpIfRoot(FieldOperand(ebx, HeapObject::kMapOffset),
1779109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                  Heap::kHeapNumberMapRootIndex, &convert_number);
1780109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    {
178113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      // Parameter is not a Number, use the ToNumber builtin to convert it.
178213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      FrameScope scope(masm, StackFrame::MANUAL);
1783109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ SmiTag(eax);
1784109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ SmiTag(ecx);
1785f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      __ EnterBuiltinFrame(esi, edi, eax);
1786109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ Push(ecx);
1787109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ Push(edx);
1788109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ mov(eax, ebx);
178913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      __ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
1790109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ mov(ebx, eax);
1791109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ Pop(edx);
1792109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ Pop(ecx);
1793f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      __ LeaveBuiltinFrame(esi, edi, eax);
1794f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      __ SmiUntag(ecx);
1795f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      __ SmiUntag(eax);
1796109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      {
1797109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        // Restore the double accumulator value (xmm0).
1798109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        Label restore_smi, done_restore;
1799109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        __ JumpIfSmi(edx, &restore_smi, Label::kNear);
1800109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        __ movsd(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
1801109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        __ jmp(&done_restore, Label::kNear);
1802109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        __ bind(&restore_smi);
1803109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        __ SmiUntag(edx);
1804109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        __ Cvtsi2sd(xmm0, edx);
1805109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        __ SmiTag(edx);
1806109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        __ bind(&done_restore);
1807109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      }
1808109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    }
1809109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ jmp(&convert);
1810109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ bind(&convert_number);
1811109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ movsd(xmm1, FieldOperand(ebx, HeapNumber::kValueOffset));
1812109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ jmp(&done_convert, Label::kNear);
1813109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ bind(&convert_smi);
1814109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ SmiUntag(ebx);
1815109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ Cvtsi2sd(xmm1, ebx);
1816109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ SmiTag(ebx);
1817109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ bind(&done_convert);
1818109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1819109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Perform the actual comparison with the accumulator value on the left hand
1820109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // side (xmm0) and the next parameter value on the right hand side (xmm1).
1821109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    Label compare_equal, compare_nan, compare_swap, done_compare;
1822109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ ucomisd(xmm0, xmm1);
1823109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ j(parity_even, &compare_nan, Label::kNear);
1824109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ j(cc, &done_compare, Label::kNear);
1825109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ j(equal, &compare_equal, Label::kNear);
1826109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1827109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Result is on the right hand side.
1828109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ bind(&compare_swap);
1829109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ movaps(xmm0, xmm1);
1830109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ mov(edx, ebx);
1831109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ jmp(&done_compare, Label::kNear);
1832109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1833109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // At least one side is NaN, which means that the result will be NaN too.
1834109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ bind(&compare_nan);
1835109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ LoadRoot(edx, Heap::kNanValueRootIndex);
1836109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ movsd(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
1837109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ jmp(&done_compare, Label::kNear);
1838109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1839109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Left and right hand side are equal, check for -0 vs. +0.
1840109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ bind(&compare_equal);
184113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ Push(edi);  // Preserve function in edi.
1842109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ movmskpd(edi, reg);
1843109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ test(edi, Immediate(1));
184413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ Pop(edi);
1845109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ j(not_zero, &compare_swap);
1846109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1847109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ bind(&done_compare);
1848109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ dec(ecx);
1849109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ jmp(&loop);
1850109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  }
1851109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1852109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ bind(&done_loop);
1853109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ PopReturnAddressTo(ecx);
1854109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1855109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ PushReturnAddressFrom(ecx);
1856109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ mov(eax, edx);
1857109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ Ret();
1858109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch}
1859109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1860109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// static
1861014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
186280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ----------- S t a t e -------------
186380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  -- eax                 : number of arguments
186480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  -- edi                 : constructor function
1865f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  //  -- esi                 : context
186680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  -- esp[0]              : return address
186780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
186880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  -- esp[(argc + 1) * 4] : receiver
186980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // -----------------------------------
187080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1871f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // 1. Load the first argument into ebx.
1872014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label no_arguments;
1873014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1874014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ test(eax, eax);
1875014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(zero, &no_arguments, Label::kNear);
1876014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
187780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
187880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1879014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 2a. Convert the first argument to a number.
1880f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  {
1881f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    FrameScope scope(masm, StackFrame::MANUAL);
1882f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ SmiTag(eax);
1883f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ EnterBuiltinFrame(esi, edi, eax);
1884f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ mov(eax, ebx);
1885f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
1886f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ LeaveBuiltinFrame(esi, edi, ebx);  // Argc popped to ebx.
1887f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ SmiUntag(ebx);
1888f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
1889f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
1890f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  {
1891f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // Drop all arguments including the receiver.
1892f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ PopReturnAddressTo(ecx);
1893f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ lea(esp, Operand(esp, ebx, times_pointer_size, kPointerSize));
1894f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ PushReturnAddressFrom(ecx);
1895f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ Ret();
1896f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
1897014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1898014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 2b. No arguments, return +0 (already in eax).
1899014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&no_arguments);
1900014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ ret(1 * kPointerSize);
1901014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
1902014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1903014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
1904014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
190580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ----------- S t a t e -------------
1906014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax                 : number of arguments
1907014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi                 : constructor function
1908014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx                 : new target
1909f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  //  -- esi                 : context
1910014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[0]              : return address
1911014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1912014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[(argc + 1) * 4] : receiver
191380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // -----------------------------------
191480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1915014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 1. Make sure we operate in the context of the called function.
1916014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
191780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1918f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // Store argc in r8.
1919f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ mov(ecx, eax);
1920f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ SmiTag(ecx);
1921f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
1922f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // 2. Load the first argument into ebx.
1923014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1924014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label no_arguments, done;
1925014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ test(eax, eax);
1926014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(zero, &no_arguments, Label::kNear);
1927014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1928014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ jmp(&done, Label::kNear);
1929014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&no_arguments);
1930c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    __ Move(ebx, Smi::kZero);
1931014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&done);
1932014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
193380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1934014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 3. Make sure ebx is a number.
1935014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
1936014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label done_convert;
1937014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ JumpIfSmi(ebx, &done_convert);
1938014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CompareRoot(FieldOperand(ebx, HeapObject::kMapOffset),
1939014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                   Heap::kHeapNumberMapRootIndex);
1940014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(equal, &done_convert);
1941014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    {
1942f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      FrameScope scope(masm, StackFrame::MANUAL);
1943f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      __ EnterBuiltinFrame(esi, edi, ecx);
1944014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ Push(edx);
1945014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ Move(eax, ebx);
194613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      __ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
1947014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ Move(ebx, eax);
1948014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ Pop(edx);
1949f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      __ LeaveBuiltinFrame(esi, edi, ecx);
1950014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
1951014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&done_convert);
1952014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
195380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1954014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 4. Check if new target and constructor differ.
1955f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  Label drop_frame_and_ret, done_alloc, new_object;
1956014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ cmp(edx, edi);
1957014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(not_equal, &new_object);
195880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1959014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 5. Allocate a JSValue wrapper for the number.
1960f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ AllocateJSValue(eax, edi, ebx, esi, &done_alloc);
1961f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ jmp(&drop_frame_and_ret);
1962f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
1963f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ bind(&done_alloc);
1964f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));  // Restore esi.
196580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1966014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 6. Fallback to the runtime to create new object.
1967014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&new_object);
19683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  {
1969f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    FrameScope scope(masm, StackFrame::MANUAL);
1970f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ EnterBuiltinFrame(esi, edi, ecx);
1971014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Push(ebx);  // the first argument
1972109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    FastNewObjectStub stub(masm->isolate());
1973109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ CallStub(&stub);
1974014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Pop(FieldOperand(eax, JSValue::kValueOffset));
1975f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ LeaveBuiltinFrame(esi, edi, ecx);
19763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
197780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1978f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ bind(&drop_frame_and_ret);
1979f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  {
1980f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // Drop all arguments including the receiver.
1981f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ PopReturnAddressTo(esi);
1982f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ SmiUntag(ecx);
1983f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ lea(esp, Operand(esp, ecx, times_pointer_size, kPointerSize));
1984f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ PushReturnAddressFrom(esi);
1985f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ Ret();
1986f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
1987f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}
1988014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1989014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
1990014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_StringConstructor(MacroAssembler* masm) {
1991014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
1992014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax                 : number of arguments
1993014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi                 : constructor function
1994f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  //  -- esi                 : context
1995014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[0]              : return address
1996014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1997014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[(argc + 1) * 4] : receiver
1998014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
1999014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2000f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // 1. Load the first argument into eax.
2001014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label no_arguments;
2002014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2003f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ mov(ebx, eax);  // Store argc in ebx.
2004014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ test(eax, eax);
2005014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(zero, &no_arguments, Label::kNear);
2006f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ mov(eax, Operand(esp, eax, times_pointer_size, 0));
2007014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2008014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2009014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 2a. At least one argument, return eax if it's a string, otherwise
2010014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // dispatch to appropriate conversion.
2011f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  Label drop_frame_and_ret, to_string, symbol_descriptive_string;
2012014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2013014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ JumpIfSmi(eax, &to_string, Label::kNear);
2014014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    STATIC_ASSERT(FIRST_NONSTRING_TYPE == SYMBOL_TYPE);
2015014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
2016014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(above, &to_string, Label::kNear);
2017014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(equal, &symbol_descriptive_string, Label::kNear);
2018f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ jmp(&drop_frame_and_ret, Label::kNear);
2019014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2020014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2021014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 2b. No arguments, return the empty string (and pop the receiver).
202280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&no_arguments);
2023014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2024014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ LoadRoot(eax, Heap::kempty_stringRootIndex);
2025014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ ret(1 * kPointerSize);
2026014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2027014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2028014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 3a. Convert eax to a string.
2029014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&to_string);
2030014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2031f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    FrameScope scope(masm, StackFrame::MANUAL);
2032f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ SmiTag(ebx);
2033f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ EnterBuiltinFrame(esi, edi, ebx);
2034f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    __ Call(masm->isolate()->builtins()->ToString(), RelocInfo::CODE_TARGET);
2035f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ LeaveBuiltinFrame(esi, edi, ebx);
2036f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ SmiUntag(ebx);
2037014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2038f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ jmp(&drop_frame_and_ret, Label::kNear);
203980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2040014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 3b. Convert symbol in eax to a string.
2041014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&symbol_descriptive_string);
2042014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2043014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PopReturnAddressTo(ecx);
2044f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ lea(esp, Operand(esp, ebx, times_pointer_size, kPointerSize));
2045014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Push(eax);
2046014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PushReturnAddressFrom(ecx);
2047014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ TailCallRuntime(Runtime::kSymbolDescriptiveString);
2048014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2049014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2050f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ bind(&drop_frame_and_ret);
2051f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  {
2052f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // Drop all arguments including the receiver.
2053f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ PopReturnAddressTo(ecx);
2054f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ lea(esp, Operand(esp, ebx, times_pointer_size, kPointerSize));
2055f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ PushReturnAddressFrom(ecx);
2056f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ Ret();
2057f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
2058f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}
2059014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2060014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
2061014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
2062014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
2063014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax                 : number of arguments
2064014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi                 : constructor function
2065014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx                 : new target
2066f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  //  -- esi                 : context
2067014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[0]              : return address
2068014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
2069014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[(argc + 1) * 4] : receiver
2070014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
2071014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2072014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 1. Make sure we operate in the context of the called function.
2073014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
2074014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2075f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ mov(ebx, eax);
2076f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
2077f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // 2. Load the first argument into eax.
2078014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2079014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label no_arguments, done;
2080f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ test(ebx, ebx);
2081014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(zero, &no_arguments, Label::kNear);
2082f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ mov(eax, Operand(esp, ebx, times_pointer_size, 0));
2083014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ jmp(&done, Label::kNear);
2084014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&no_arguments);
2085f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ LoadRoot(eax, Heap::kempty_stringRootIndex);
2086014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&done);
2087014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2088014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2089f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // 3. Make sure eax is a string.
2090014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2091014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label convert, done_convert;
2092f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ JumpIfSmi(eax, &convert, Label::kNear);
2093f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx);
2094014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(below, &done_convert);
2095014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&convert);
2096014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    {
2097f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      FrameScope scope(masm, StackFrame::MANUAL);
2098f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      __ SmiTag(ebx);
2099f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      __ EnterBuiltinFrame(esi, edi, ebx);
2100014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ Push(edx);
2101f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch      __ Call(masm->isolate()->builtins()->ToString(), RelocInfo::CODE_TARGET);
2102014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ Pop(edx);
2103f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      __ LeaveBuiltinFrame(esi, edi, ebx);
2104f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      __ SmiUntag(ebx);
2105014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
2106014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&done_convert);
2107014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2108014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2109014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 4. Check if new target and constructor differ.
2110f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  Label drop_frame_and_ret, done_alloc, new_object;
2111014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ cmp(edx, edi);
2112014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(not_equal, &new_object);
2113014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2114014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 5. Allocate a JSValue wrapper for the string.
2115f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // AllocateJSValue can't handle src == dst register. Reuse esi and restore it
2116f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // as needed after the call.
2117f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ mov(esi, eax);
2118f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ AllocateJSValue(eax, edi, esi, ecx, &done_alloc);
2119f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ jmp(&drop_frame_and_ret);
2120f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
2121f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ bind(&done_alloc);
2122f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  {
2123f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // Restore eax to the first argument and esi to the context.
2124f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ mov(eax, esi);
2125f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
2126f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
2127014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2128014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 6. Fallback to the runtime to create new object.
2129014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&new_object);
21303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  {
2131f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    FrameScope scope(masm, StackFrame::MANUAL);
2132f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ SmiTag(ebx);
2133f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ EnterBuiltinFrame(esi, edi, ebx);
2134f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ Push(eax);  // the first argument
2135109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    FastNewObjectStub stub(masm->isolate());
2136109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ CallStub(&stub);
2137014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Pop(FieldOperand(eax, JSValue::kValueOffset));
2138f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ LeaveBuiltinFrame(esi, edi, ebx);
2139f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ SmiUntag(ebx);
21403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
214180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2142f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ bind(&drop_frame_and_ret);
2143f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  {
2144f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    // Drop all arguments including the receiver.
2145f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ PopReturnAddressTo(ecx);
2146f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ lea(esp, Operand(esp, ebx, times_pointer_size, kPointerSize));
2147f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ PushReturnAddressFrom(ecx);
2148f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ Ret();
2149f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
2150f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}
215180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
2153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ebp);
21543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ebp, esp);
2155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Store the arguments adaptor context sentinel.
2157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Push the function on the stack.
2160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(edi);
2161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2162257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Preserve the number of arguments on the stack. Must preserve eax,
2163257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // ebx and ecx because these registers are used when copying the
2164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // arguments and the receiver.
216569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  STATIC_ASSERT(kSmiTagSize == 1);
2166257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lea(edi, Operand(eax, eax, times_1, kSmiTag));
2167257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(edi);
2168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
2171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Retrieve the number of arguments from the stack.
2172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
2173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Leave the frame.
2175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ leave();
2176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Remove caller arguments from the stack.
217869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
2179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(ecx);
2180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize));  // 1 ~ receiver
2181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ecx);
2182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2184014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
2185014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_Apply(MacroAssembler* masm) {
2186014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
2187014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax    : argumentsList
2188014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi    : target
2189014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx    : new.target (checked to be constructor or undefined)
2190014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[0] : return address.
2191014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[4] : thisArgument
2192014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
2193014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2194014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Create the list of arguments from the array-like argumentsList.
2195014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2196014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label create_arguments, create_array, create_runtime, done_create;
2197014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ JumpIfSmi(eax, &create_runtime);
2198014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2199014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Load the map of argumentsList into ecx.
2200014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
2201014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2202014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Load native context into ebx.
2203014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ebx, NativeContextOperand());
2204014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2205014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Check if argumentsList is an (unmodified) arguments object.
2206014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(ecx, ContextOperand(ebx, Context::SLOPPY_ARGUMENTS_MAP_INDEX));
2207014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(equal, &create_arguments);
2208014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(ecx, ContextOperand(ebx, Context::STRICT_ARGUMENTS_MAP_INDEX));
2209014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(equal, &create_arguments);
2210014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2211014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Check if argumentsList is a fast JSArray.
2212014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CmpInstanceType(ecx, JS_ARRAY_TYPE);
2213014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(equal, &create_array);
2214014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2215014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Ask the runtime to create the list (actually a FixedArray).
2216014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&create_runtime);
2217014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    {
2218014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      FrameScope scope(masm, StackFrame::INTERNAL);
2219014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ Push(edi);
2220014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ Push(edx);
2221014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ Push(eax);
2222014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ CallRuntime(Runtime::kCreateListFromArrayLike);
2223014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ Pop(edx);
2224014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ Pop(edi);
2225014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ mov(ebx, FieldOperand(eax, FixedArray::kLengthOffset));
2226014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ SmiUntag(ebx);
2227014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
2228014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ jmp(&done_create);
2229014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2230014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Try to create the list from an arguments object.
2231014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&create_arguments);
2232109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ mov(ebx, FieldOperand(eax, JSArgumentsObject::kLengthOffset));
2233014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ecx, FieldOperand(eax, JSObject::kElementsOffset));
2234014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
2235014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(not_equal, &create_runtime);
2236014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ SmiUntag(ebx);
2237014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(eax, ecx);
2238014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ jmp(&done_create);
2239014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2240014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Try to create the list from a JSArray object.
2241014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&create_array);
2242014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
2243014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ DecodeField<Map::ElementsKindBits>(ecx);
2244014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
2245014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
2246014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    STATIC_ASSERT(FAST_ELEMENTS == 2);
2247014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(ecx, Immediate(FAST_ELEMENTS));
2248014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(above, &create_runtime);
2249014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(ecx, Immediate(FAST_HOLEY_SMI_ELEMENTS));
2250014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(equal, &create_runtime);
2251014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ebx, FieldOperand(eax, JSArray::kLengthOffset));
2252014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ SmiUntag(ebx);
2253014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(eax, FieldOperand(eax, JSArray::kElementsOffset));
2254014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2255014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&done_create);
2256014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2257014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2258014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Check for stack overflow.
2259014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2260014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Check the stack for overflow. We are not trying to catch interruptions
2261014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // (i.e. debug break and preemption) here, so check the "real stack limit".
2262014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label done;
2263014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    ExternalReference real_stack_limit =
2264014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        ExternalReference::address_of_real_stack_limit(masm->isolate());
2265014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ecx, Operand::StaticVariable(real_stack_limit));
2266014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Make ecx the space we have left. The stack might already be overflowed
2267014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // here which will cause ecx to become negative.
2268014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ neg(ecx);
2269014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ add(ecx, esp);
2270014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ sar(ecx, kPointerSizeLog2);
2271014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Check if the arguments will overflow the stack.
2272014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(ecx, ebx);
2273014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(greater, &done, Label::kNear);  // Signed comparison.
2274014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ TailCallRuntime(Runtime::kThrowStackOverflow);
2275014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&done);
2276014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2277014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2278014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
2279014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi    : target
2280014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax    : args (a FixedArray built from argumentsList)
2281014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- ebx    : len (number of elements to push from args)
2282014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx    : new.target (checked to be constructor or undefined)
2283014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[0] : return address.
2284014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[4] : thisArgument
2285014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
2286014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2287014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Push arguments onto the stack (thisArgument is already on the stack).
2288014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2289014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ movd(xmm0, edx);
2290014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PopReturnAddressTo(edx);
2291014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Move(ecx, Immediate(0));
2292014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label done, loop;
2293014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&loop);
2294014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(ecx, ebx);
2295014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(equal, &done, Label::kNear);
2296014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Push(
2297014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        FieldOperand(eax, ecx, times_pointer_size, FixedArray::kHeaderSize));
2298014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ inc(ecx);
2299014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ jmp(&loop);
2300014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&done);
2301014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PushReturnAddressFrom(edx);
2302014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ movd(edx, xmm0);
2303014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Move(eax, ebx);
2304014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2305014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2306014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Dispatch to Call or Construct depending on whether new.target is undefined.
2307014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2308014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CompareRoot(edx, Heap::kUndefinedValueRootIndex);
2309014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(equal, masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
2310014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
2311014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2312014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
2313014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2314109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochnamespace {
2315109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2316109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// Drops top JavaScript frame and an arguments adaptor frame below it (if
2317109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// present) preserving all the arguments prepared for current call.
2318109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// Does nothing if debugger is currently active.
2319109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// ES6 14.6.3. PrepareForTailCall
2320109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch//
2321109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// Stack structure for the function g() tail calling f():
2322109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch//
2323109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// ------- Caller frame: -------
2324109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  ...
2325109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  g()'s arg M
2326109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  ...
2327109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  g()'s arg 1
2328109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  g()'s receiver arg
2329109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  g()'s caller pc
2330109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// ------- g()'s frame: -------
2331109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  g()'s caller fp      <- fp
2332109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  g()'s context
2333109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  function pointer: g
2334109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  -------------------------
2335109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  ...
2336109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  ...
2337109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  f()'s arg N
2338109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  ...
2339109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  f()'s arg 1
2340109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  f()'s receiver arg
2341109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// |  f()'s caller pc      <- sp
2342109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// ----------------------
2343109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch//
2344109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochvoid PrepareForTailCall(MacroAssembler* masm, Register args_reg,
2345109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                        Register scratch1, Register scratch2,
2346109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                        Register scratch3) {
2347109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
2348109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Comment cmnt(masm, "[ PrepareForTailCall");
2349109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
23503b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  // Prepare for tail call only if ES2015 tail call elimination is enabled.
2351109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Label done;
23523b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  ExternalReference is_tail_call_elimination_enabled =
23533b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch      ExternalReference::is_tail_call_elimination_enabled_address(
23543b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch          masm->isolate());
23553b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ movzx_b(scratch1,
23563b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch             Operand::StaticVariable(is_tail_call_elimination_enabled));
2357109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ cmp(scratch1, Immediate(0));
23583b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ j(equal, &done, Label::kNear);
2359109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2360109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Drop possible interpreter handler/stub frame.
2361109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  {
2362109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    Label no_interpreter_frame;
23633b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    __ cmp(Operand(ebp, CommonFrameConstants::kContextOrFrameTypeOffset),
2364109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch           Immediate(Smi::FromInt(StackFrame::STUB)));
2365109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ j(not_equal, &no_interpreter_frame, Label::kNear);
2366109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ mov(ebp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2367109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ bind(&no_interpreter_frame);
2368109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  }
2369109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2370109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Check if next frame is an arguments adaptor frame.
23713b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  Register caller_args_count_reg = scratch1;
2372109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Label no_arguments_adaptor, formal_parameter_count_loaded;
2373109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ mov(scratch2, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
23743b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ cmp(Operand(scratch2, CommonFrameConstants::kContextOrFrameTypeOffset),
2375109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch         Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2376109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(not_equal, &no_arguments_adaptor, Label::kNear);
2377109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
23783b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  // Drop current frame and load arguments count from arguments adaptor frame.
2379109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ mov(ebp, scratch2);
23803b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ mov(caller_args_count_reg,
23813b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch         Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
23823b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ SmiUntag(caller_args_count_reg);
2383109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ jmp(&formal_parameter_count_loaded, Label::kNear);
2384109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2385109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ bind(&no_arguments_adaptor);
2386109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Load caller's formal parameter count
2387109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ mov(scratch1, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
2388109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ mov(scratch1,
2389109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch         FieldOperand(scratch1, JSFunction::kSharedFunctionInfoOffset));
2390109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ mov(
23913b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch      caller_args_count_reg,
2392109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      FieldOperand(scratch1, SharedFunctionInfo::kFormalParameterCountOffset));
23933b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ SmiUntag(caller_args_count_reg);
2394109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2395109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ bind(&formal_parameter_count_loaded);
2396109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
23973b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  ParameterCount callee_args_count(args_reg);
23983b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
23993b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch                        scratch3, ReturnAddressState::kOnStack, 0);
2400109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ bind(&done);
2401109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch}
2402109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch}  // namespace
2403014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2404014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
2405014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_CallFunction(MacroAssembler* masm,
2406109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                                     ConvertReceiverMode mode,
2407109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                                     TailCallMode tail_call_mode) {
2408014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
2409014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax : the number of arguments (not including the receiver)
2410014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi : the function to call (checked to be a JSFunction)
2411014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
2412014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ AssertFunction(edi);
2413014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2414014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
2415014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Check that the function is not a "classConstructor".
2416014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label class_constructor;
2417014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2418014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ test_b(FieldOperand(edx, SharedFunctionInfo::kFunctionKindByteOffset),
24193b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch            Immediate(SharedFunctionInfo::kClassConstructorBitsWithinByte));
2420014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(not_zero, &class_constructor);
2421014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2422014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Enter the context of the function; ToObject has to run in the function
2423014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // context, and we also need to take the global proxy from the function
2424014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // context in case of conversion.
2425014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  STATIC_ASSERT(SharedFunctionInfo::kNativeByteOffset ==
2426014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                SharedFunctionInfo::kStrictModeByteOffset);
2427014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
2428014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // We need to convert the receiver for non-native sloppy mode functions.
2429014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label done_convert;
2430014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ test_b(FieldOperand(edx, SharedFunctionInfo::kNativeByteOffset),
24313b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch            Immediate((1 << SharedFunctionInfo::kNativeBitWithinByte) |
24323b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch                      (1 << SharedFunctionInfo::kStrictModeBitWithinByte)));
2433014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(not_zero, &done_convert);
2434014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2435014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // ----------- S t a t e -------------
2436014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    //  -- eax : the number of arguments (not including the receiver)
2437014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    //  -- edx : the shared function info.
2438014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    //  -- edi : the function to call (checked to be a JSFunction)
2439014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    //  -- esi : the function context.
2440014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // -----------------------------------
2441014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2442014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (mode == ConvertReceiverMode::kNullOrUndefined) {
2443014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Patch receiver to global proxy.
2444014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ LoadGlobalProxy(ecx);
2445014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    } else {
2446014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Label convert_to_object, convert_receiver;
2447014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ mov(ecx, Operand(esp, eax, times_pointer_size, kPointerSize));
2448014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ JumpIfSmi(ecx, &convert_to_object, Label::kNear);
2449014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
2450014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ CmpObjectType(ecx, FIRST_JS_RECEIVER_TYPE, ebx);
2451014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ j(above_equal, &done_convert);
2452014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      if (mode != ConvertReceiverMode::kNotNullOrUndefined) {
2453014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        Label convert_global_proxy;
2454014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ JumpIfRoot(ecx, Heap::kUndefinedValueRootIndex,
2455014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                      &convert_global_proxy, Label::kNear);
2456014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ JumpIfNotRoot(ecx, Heap::kNullValueRootIndex, &convert_to_object,
2457014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                         Label::kNear);
2458014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ bind(&convert_global_proxy);
2459014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        {
2460014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          // Patch receiver to global proxy.
2461014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          __ LoadGlobalProxy(ecx);
2462014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        }
2463014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ jmp(&convert_receiver);
2464014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      }
2465014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ bind(&convert_to_object);
2466014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      {
2467014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        // Convert receiver using ToObject.
2468014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        // TODO(bmeurer): Inline the allocation here to avoid building the frame
2469014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        // in the fast case? (fall back to AllocateInNewSpace?)
2470014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        FrameScope scope(masm, StackFrame::INTERNAL);
2471014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ SmiTag(eax);
2472014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ Push(eax);
2473014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ Push(edi);
2474014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ mov(eax, ecx);
2475f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        __ Push(esi);
2476c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        __ Call(masm->isolate()->builtins()->ToObject(),
2477c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch                RelocInfo::CODE_TARGET);
2478f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        __ Pop(esi);
2479014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ mov(ecx, eax);
2480014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ Pop(edi);
2481014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ Pop(eax);
2482014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ SmiUntag(eax);
2483014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      }
2484014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2485014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ bind(&convert_receiver);
2486014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
2487014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ecx);
2488014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2489014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&done_convert);
2490014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2491014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
2492014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax : the number of arguments (not including the receiver)
2493014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx : the shared function info.
2494014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi : the function to call (checked to be a JSFunction)
2495014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esi : the function context.
2496014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
2497014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2498109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  if (tail_call_mode == TailCallMode::kAllow) {
2499109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    PrepareForTailCall(masm, eax, ebx, ecx, edx);
2500109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Reload shared function info.
2501109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2502109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  }
2503109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2504014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ebx,
2505014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch         FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
2506014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ SmiUntag(ebx);
2507014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  ParameterCount actual(eax);
2508014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  ParameterCount expected(ebx);
2509014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ InvokeFunctionCode(edi, no_reg, expected, actual, JUMP_FUNCTION,
2510014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                        CheckDebugStepCallWrapper());
2511014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // The function is a "classConstructor", need to raise an exception.
2512014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&class_constructor);
2513014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2514014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    FrameScope frame(masm, StackFrame::INTERNAL);
2515014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ push(edi);
2516014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CallRuntime(Runtime::kThrowConstructorNonCallableError);
2517014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2518014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
2519014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2520014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochnamespace {
2521014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2522014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Generate_PushBoundArguments(MacroAssembler* masm) {
2523014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
2524014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax : the number of arguments (not including the receiver)
2525014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx : new.target (only in case of [[Construct]])
2526014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi : target (checked to be a JSBoundFunction)
2527014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
2528014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2529014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Load [[BoundArguments]] into ecx and length of that into ebx.
2530014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label no_bound_arguments;
2531014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset));
2532014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
2533014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ SmiUntag(ebx);
2534014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ test(ebx, ebx);
2535014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(zero, &no_bound_arguments);
2536014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2537014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // ----------- S t a t e -------------
2538014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    //  -- eax : the number of arguments (not including the receiver)
2539014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    //  -- edx : new.target (only in case of [[Construct]])
2540014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    //  -- edi : target (checked to be a JSBoundFunction)
2541014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    //  -- ecx : the [[BoundArguments]] (implemented as FixedArray)
2542014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    //  -- ebx : the number of [[BoundArguments]]
2543014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // -----------------------------------
2544014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2545014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Reserve stack space for the [[BoundArguments]].
2546014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    {
2547014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Label done;
2548014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ lea(ecx, Operand(ebx, times_pointer_size, 0));
2549014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ sub(esp, ecx);
2550014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Check the stack for overflow. We are not trying to catch interruptions
2551014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // (i.e. debug break and preemption) here, so check the "real stack
2552014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // limit".
2553014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ CompareRoot(esp, ecx, Heap::kRealStackLimitRootIndex);
2554014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ j(greater, &done, Label::kNear);  // Signed comparison.
2555014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Restore the stack pointer.
2556014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ lea(esp, Operand(esp, ebx, times_pointer_size, 0));
2557014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      {
2558014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        FrameScope scope(masm, StackFrame::MANUAL);
2559014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ EnterFrame(StackFrame::INTERNAL);
2560014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        __ CallRuntime(Runtime::kThrowStackOverflow);
2561014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      }
2562014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ bind(&done);
2563014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
2564014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2565014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Adjust effective number of arguments to include return address.
2566014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ inc(eax);
2567014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2568014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Relocate arguments and return address down the stack.
2569014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    {
2570014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Label loop;
2571014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ Set(ecx, 0);
2572014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ lea(ebx, Operand(esp, ebx, times_pointer_size, 0));
2573014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ bind(&loop);
2574014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ movd(xmm0, Operand(ebx, ecx, times_pointer_size, 0));
2575014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ movd(Operand(esp, ecx, times_pointer_size, 0), xmm0);
2576014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ inc(ecx);
2577014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ cmp(ecx, eax);
2578014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ j(less, &loop);
2579014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
2580014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2581014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Copy [[BoundArguments]] to the stack (below the arguments).
2582014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    {
2583014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Label loop;
2584014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset));
2585014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
2586014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ SmiUntag(ebx);
2587014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ bind(&loop);
2588014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ dec(ebx);
2589014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ movd(xmm0, FieldOperand(ecx, ebx, times_pointer_size,
2590014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                 FixedArray::kHeaderSize));
2591014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ movd(Operand(esp, eax, times_pointer_size, 0), xmm0);
2592014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ lea(eax, Operand(eax, 1));
2593014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ j(greater, &loop);
2594014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
2595014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2596014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Adjust effective number of arguments (eax contains the number of
2597014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // arguments from the call plus return address plus the number of
2598014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // [[BoundArguments]]), so we need to subtract one for the return address.
2599014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ dec(eax);
2600014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2601014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&no_bound_arguments);
2602014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
2603014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2604014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace
2605014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2606014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
2607109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochvoid Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm,
2608109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                                              TailCallMode tail_call_mode) {
2609014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
2610014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax : the number of arguments (not including the receiver)
2611014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi : the function to call (checked to be a JSBoundFunction)
2612014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
2613014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ AssertBoundFunction(edi);
2614014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2615109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  if (tail_call_mode == TailCallMode::kAllow) {
2616109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    PrepareForTailCall(masm, eax, ebx, ecx, edx);
2617109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  }
2618109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2619014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Patch the receiver to [[BoundThis]].
2620014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ebx, FieldOperand(edi, JSBoundFunction::kBoundThisOffset));
2621014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ebx);
2622014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2623014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Push the [[BoundArguments]] onto the stack.
2624014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Generate_PushBoundArguments(masm);
2625014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2626014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Call the [[BoundTargetFunction]] via the Call builtin.
2627014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2628014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, Operand::StaticVariable(ExternalReference(
2629014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                  Builtins::kCall_ReceiverIsAny, masm->isolate())));
2630014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2631014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ jmp(ecx);
2632014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
2633014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2634014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
2635109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochvoid Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
2636109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                             TailCallMode tail_call_mode) {
2637014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
2638014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax : the number of arguments (not including the receiver)
2639014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi : the target to call (can be any Object).
2640014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
2641014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2642014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label non_callable, non_function, non_smi;
2643014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ JumpIfSmi(edi, &non_callable);
2644014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&non_smi);
2645014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
2646109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(equal, masm->isolate()->builtins()->CallFunction(mode, tail_call_mode),
2647014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch       RelocInfo::CODE_TARGET);
2648014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE);
2649109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(equal, masm->isolate()->builtins()->CallBoundFunction(tail_call_mode),
2650014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch       RelocInfo::CODE_TARGET);
2651109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2652109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Check if target has a [[Call]] internal method.
26533b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
26543b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch            Immediate(1 << Map::kIsCallable));
2655109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(zero, &non_callable);
2656109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2657014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CmpInstanceType(ecx, JS_PROXY_TYPE);
2658014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(not_equal, &non_function);
2659014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2660109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // 0. Prepare for tail call if necessary.
2661109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  if (tail_call_mode == TailCallMode::kAllow) {
2662109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    PrepareForTailCall(masm, eax, ebx, ecx, edx);
2663109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  }
2664109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2665014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 1. Runtime fallback for Proxy [[Call]].
2666014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ PopReturnAddressTo(ecx);
2667014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Push(edi);
2668014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ PushReturnAddressFrom(ecx);
2669014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Increase the arguments size to include the pushed function and the
2670014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // existing receiver on the stack.
2671014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ add(eax, Immediate(2));
2672014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Tail-call to the runtime.
2673014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ JumpToExternalReference(
2674014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      ExternalReference(Runtime::kJSProxyCall, masm->isolate()));
2675014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2676014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 2. Call to something else, which might have a [[Call]] internal method (if
2677014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // not we raise an exception).
2678014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&non_function);
2679014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Overwrite the original receiver with the (original) target.
2680014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
2681014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Let the "call_as_function_delegate" take care of the rest.
2682014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, edi);
2683014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Jump(masm->isolate()->builtins()->CallFunction(
2684109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch              ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode),
2685014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          RelocInfo::CODE_TARGET);
2686014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2687014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // 3. Call to something that is not callable.
2688014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&non_callable);
2689014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2690014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
2691014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Push(edi);
2692014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CallRuntime(Runtime::kThrowCalledNonCallable);
2693014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2694014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
2695014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2696014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
2697014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
2698014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
2699014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax : the number of arguments (not including the receiver)
2700014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx : the new target (checked to be a constructor)
2701014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi : the constructor to call (checked to be a JSFunction)
2702014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
2703014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ AssertFunction(edi);
2704014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2705014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Calling convention for function specific ConstructStubs require
2706014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ebx to contain either an AllocationSite or undefined.
2707014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ LoadRoot(ebx, Heap::kUndefinedValueRootIndex);
2708014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2709014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Tail call to the function-specific construct stub (still in the caller
2710014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // context at this point).
2711014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2712014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset));
2713014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2714014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ jmp(ecx);
2715014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
2716014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2717014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
2718014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) {
2719014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
2720014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax : the number of arguments (not including the receiver)
2721014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx : the new target (checked to be a constructor)
2722014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi : the constructor to call (checked to be a JSBoundFunction)
2723014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
2724014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ AssertBoundFunction(edi);
2725014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2726014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Push the [[BoundArguments]] onto the stack.
2727014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Generate_PushBoundArguments(masm);
2728014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2729014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Patch new.target to [[BoundTargetFunction]] if new.target equals target.
2730014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2731014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Label done;
2732014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(edi, edx);
2733014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ j(not_equal, &done, Label::kNear);
2734014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(edx, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2735014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ bind(&done);
2736014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2737014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2738014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Construct the [[BoundTargetFunction]] via the Construct builtin.
2739014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2740014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, Operand::StaticVariable(
2741014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                  ExternalReference(Builtins::kConstruct, masm->isolate())));
2742014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2743014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ jmp(ecx);
2744014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
2745014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2746014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
2747014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
2748014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
2749014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax : the number of arguments (not including the receiver)
2750014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi : the constructor to call (checked to be a JSProxy)
2751014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx : the new target (either the same as the constructor or
2752014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //           the JSFunction on which new was invoked initially)
2753014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
2754014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2755014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Call into the Runtime for Proxy [[Construct]].
2756014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ PopReturnAddressTo(ecx);
2757014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Push(edi);
2758014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Push(edx);
2759014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ PushReturnAddressFrom(ecx);
2760014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Include the pushed new_target, constructor and the receiver.
2761014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ add(eax, Immediate(3));
2762014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Tail-call to the runtime.
2763014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ JumpToExternalReference(
2764014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      ExternalReference(Runtime::kJSProxyConstruct, masm->isolate()));
2765014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
2766014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2767014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// static
2768014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_Construct(MacroAssembler* masm) {
2769014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
2770014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax : the number of arguments (not including the receiver)
2771014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx : the new target (either the same as the constructor or
2772014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //           the JSFunction on which new was invoked initially)
2773014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi : the constructor to call (can be any Object)
2774014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
2775014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2776014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Check if target is a Smi.
2777014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label non_constructor;
2778014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ JumpIfSmi(edi, &non_constructor, Label::kNear);
2779014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2780014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Dispatch based on instance type.
2781014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
2782014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(equal, masm->isolate()->builtins()->ConstructFunction(),
2783014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch       RelocInfo::CODE_TARGET);
2784014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2785014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Check if target has a [[Construct]] internal method.
27863b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
27873b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch            Immediate(1 << Map::kIsConstructor));
2788014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(zero, &non_constructor, Label::kNear);
2789014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2790014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Only dispatch to bound functions after checking whether they are
2791014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // constructors.
2792014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE);
2793014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(equal, masm->isolate()->builtins()->ConstructBoundFunction(),
2794014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch       RelocInfo::CODE_TARGET);
2795014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2796014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Only dispatch to proxies after checking whether they are constructors.
2797014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CmpInstanceType(ecx, JS_PROXY_TYPE);
2798014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(equal, masm->isolate()->builtins()->ConstructProxy(),
2799014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch       RelocInfo::CODE_TARGET);
2800014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2801014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Called Construct on an exotic Object with a [[Construct]] internal method.
2802014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
2803014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Overwrite the original receiver with the (original) target.
2804014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
2805014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Let the "call_as_constructor_delegate" take care of the rest.
2806014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, edi);
2807014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Jump(masm->isolate()->builtins()->CallFunction(),
2808014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch            RelocInfo::CODE_TARGET);
2809014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2810014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2811014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Called Construct on an Object that doesn't have a [[Construct]] internal
2812014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // method.
2813014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&non_constructor);
2814014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Jump(masm->isolate()->builtins()->ConstructedNonConstructable(),
2815014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          RelocInfo::CODE_TARGET);
2816014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
2817014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2818bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch// static
2819bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdochvoid Builtins::Generate_AllocateInNewSpace(MacroAssembler* masm) {
2820bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // ----------- S t a t e -------------
2821bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- edx    : requested object size (untagged)
2822bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- esp[0] : return address
2823bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // -----------------------------------
2824bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ SmiTag(edx);
2825bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ PopReturnAddressTo(ecx);
2826bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ Push(edx);
2827bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ PushReturnAddressFrom(ecx);
2828c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ Move(esi, Smi::kZero);
2829bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ TailCallRuntime(Runtime::kAllocateInNewSpace);
2830bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch}
2831bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
2832bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch// static
2833bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdochvoid Builtins::Generate_AllocateInOldSpace(MacroAssembler* masm) {
2834bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // ----------- S t a t e -------------
2835bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- edx    : requested object size (untagged)
2836bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  //  -- esp[0] : return address
2837bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // -----------------------------------
2838bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ SmiTag(edx);
2839bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ PopReturnAddressTo(ecx);
2840bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ Push(edx);
2841bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ Push(Smi::FromInt(AllocateTargetSpace::encode(OLD_SPACE)));
2842bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ PushReturnAddressFrom(ecx);
2843c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ Move(esi, Smi::kZero);
2844bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ TailCallRuntime(Runtime::kAllocateInTargetSpace);
2845bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch}
2846014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
284713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch// static
2848f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochvoid Builtins::Generate_Abort(MacroAssembler* masm) {
2849f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // ----------- S t a t e -------------
2850f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  //  -- edx    : message_id as Smi
2851f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  //  -- esp[0] : return address
2852f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // -----------------------------------
2853f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ PopReturnAddressTo(ecx);
2854f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ Push(edx);
2855f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ PushReturnAddressFrom(ecx);
2856c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ Move(esi, Smi::kZero);
2857f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ TailCallRuntime(Runtime::kAbort);
285813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch}
285913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
2860a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
2861a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
2862a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax : actual number of arguments
2863a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ebx : expected number of arguments
2864014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edx : new target (passed through to callee)
2865b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- edi : function (passed through to callee)
2866a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
2867a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2868014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label invoke, dont_adapt_arguments, stack_overflow;
286944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1);
2870a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2871a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label enough, too_few;
28723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(eax, ebx);
2873a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(less, &too_few);
2874a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
2875a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, &dont_adapt_arguments);
2876a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2877a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  {  // Enough parameters: Actual >= expected.
2878a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&enough);
2879a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    EnterArgumentsAdaptorFrame(masm);
2880f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // edi is used as a scratch register. It should be restored from the frame
2881f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // when needed.
2882f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    Generate_StackOverflowCheck(masm, ebx, ecx, edi, &stack_overflow);
2883a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2884a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Copy receiver and all expected arguments.
2885a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    const int offset = StandardFrameConstants::kCallerSPOffset;
2886014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ lea(edi, Operand(ebp, eax, times_4, offset));
2887014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(eax, -1);  // account for receiver
2888a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2889a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Label copy;
2890a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&copy);
2891014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ inc(eax);
2892014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ push(Operand(edi, 0));
2893014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ sub(edi, Immediate(kPointerSize));
2894014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ cmp(eax, ebx);
2895a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ j(less, &copy);
2896014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // eax now contains the expected number of arguments.
2897a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ jmp(&invoke);
2898a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2899a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2900a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  {  // Too few parameters: Actual < expected.
2901a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&too_few);
2902a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    EnterArgumentsAdaptorFrame(masm);
2903f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // edi is used as a scratch register. It should be restored from the frame
2904f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // when needed.
2905f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    Generate_StackOverflowCheck(masm, ebx, ecx, edi, &stack_overflow);
2906014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2907014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Remember expected arguments in ecx.
2908014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(ecx, ebx);
2909a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2910a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Copy receiver and all actual arguments.
2911a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    const int offset = StandardFrameConstants::kCallerSPOffset;
2912a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ lea(edi, Operand(ebp, eax, times_4, offset));
2913257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // ebx = expected - actual.
29143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sub(ebx, eax);
2915257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // eax = -actual - 1
2916257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ neg(eax);
29173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sub(eax, Immediate(1));
2918a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2919a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Label copy;
2920a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&copy);
2921257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ inc(eax);
2922a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ push(Operand(edi, 0));
29233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sub(edi, Immediate(kPointerSize));
29243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ test(eax, eax);
2925257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_zero, &copy);
2926a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2927a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Fill remaining expected arguments with undefined values.
2928a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Label fill;
2929a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&fill);
2930257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ inc(eax);
293144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ push(Immediate(masm->isolate()->factory()->undefined_value()));
29323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cmp(eax, ebx);
2933a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ j(less, &fill);
2934014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2935014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Restore expected arguments.
2936014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ mov(eax, ecx);
2937a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2938a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2939a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Call the entry point.
2940a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&invoke);
2941257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Restore function pointer.
29423b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ mov(edi, Operand(ebp, ArgumentsAdaptorFrameConstants::kFunctionOffset));
2943014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // eax : expected number of arguments
2944014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // edx : new target (passed through to callee)
2945014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // edi : function (passed through to callee)
2946014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
2947014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ call(ecx);
29483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
29493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Store offset of return address for deoptimizer.
29503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
29515d4cdbf7a67d3662fa0bee4efdb7edd8daec9b0bBen Murdoch
2952a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Leave frame and return.
2953a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  LeaveArgumentsAdaptorFrame(masm);
2954a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
2955a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2956a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -------------------------------------------
2957a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Dont adapt arguments.
2958a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -------------------------------------------
2959a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&dont_adapt_arguments);
2960014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
2961014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ jmp(ecx);
2962a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2963b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ bind(&stack_overflow);
2964b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  {
2965b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    FrameScope frame(masm, StackFrame::MANUAL);
2966014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CallRuntime(Runtime::kThrowStackOverflow);
2967b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ int3();
2968b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
2969b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
2970b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2971014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochstatic void CompatibleReceiverCheck(MacroAssembler* masm, Register receiver,
2972014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                    Register function_template_info,
2973014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                    Register scratch0, Register scratch1,
2974014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                    Label* receiver_check_failed) {
2975014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // If there is no signature, return the holder.
2976014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CompareRoot(FieldOperand(function_template_info,
2977014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                              FunctionTemplateInfo::kSignatureOffset),
2978014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                 Heap::kUndefinedValueRootIndex);
2979014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label receiver_check_passed;
2980014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(equal, &receiver_check_passed, Label::kNear);
2981014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2982014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Walk the prototype chain.
2983014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
2984014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label prototype_loop_start;
2985014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&prototype_loop_start);
2986014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2987014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Get the constructor, if any.
2988014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ GetMapConstructor(scratch0, scratch0, scratch1);
2989014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CmpInstanceType(scratch1, JS_FUNCTION_TYPE);
2990014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label next_prototype;
2991014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(not_equal, &next_prototype, Label::kNear);
2992014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2993014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Get the constructor's signature.
2994014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(scratch0,
2995014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch         FieldOperand(scratch0, JSFunction::kSharedFunctionInfoOffset));
2996014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(scratch0,
2997014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch         FieldOperand(scratch0, SharedFunctionInfo::kFunctionDataOffset));
2998014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2999014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Loop through the chain of inheriting function templates.
3000014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label function_template_loop;
3001014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&function_template_loop);
3002014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3003014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // If the signatures match, we have a compatible receiver.
3004014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ cmp(scratch0, FieldOperand(function_template_info,
3005014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                FunctionTemplateInfo::kSignatureOffset));
3006014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(equal, &receiver_check_passed, Label::kNear);
3007014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3008014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // If the current type is not a FunctionTemplateInfo, load the next prototype
3009014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // in the chain.
3010014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ JumpIfSmi(scratch0, &next_prototype, Label::kNear);
3011014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CmpObjectType(scratch0, FUNCTION_TEMPLATE_INFO_TYPE, scratch1);
3012014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(not_equal, &next_prototype, Label::kNear);
3013014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3014014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Otherwise load the parent function template and iterate.
3015014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(scratch0,
3016014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch         FieldOperand(scratch0, FunctionTemplateInfo::kParentTemplateOffset));
3017014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ jmp(&function_template_loop, Label::kNear);
3018014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3019014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Load the next prototype.
3020014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&next_prototype);
3021014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(receiver, FieldOperand(receiver, HeapObject::kMapOffset));
3022109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ test(FieldOperand(receiver, Map::kBitField3Offset),
3023109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch          Immediate(Map::HasHiddenPrototype::kMask));
3024109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(zero, receiver_check_failed);
3025109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
3026014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(receiver, FieldOperand(receiver, Map::kPrototypeOffset));
3027014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
3028014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Iterate.
3029014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ jmp(&prototype_loop_start, Label::kNear);
3030014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3031014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&receiver_check_passed);
3032014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
3033014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3034014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Builtins::Generate_HandleFastApiCall(MacroAssembler* masm) {
3035014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // ----------- S t a t e -------------
3036014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- eax                : number of arguments (not including the receiver)
3037014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- edi                : callee
3038014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esi                : context
3039014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[0]             : return address
3040014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[4]             : last argument
3041014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- ...
3042014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[eax * 4]       : first argument
3043014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- esp[(eax + 1) * 4] : receiver
3044014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // -----------------------------------
3045014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3046014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Load the FunctionTemplateInfo.
3047014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
3048014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kFunctionDataOffset));
3049014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3050014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Do the compatible receiver check.
3051014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label receiver_check_failed;
3052014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(ecx, Operand(esp, eax, times_pointer_size, kPCOnStackSize));
3053014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Push(eax);
3054014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  CompatibleReceiverCheck(masm, ecx, ebx, edx, eax, &receiver_check_failed);
3055014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Pop(eax);
3056014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Get the callback offset from the FunctionTemplateInfo, and jump to the
3057014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // beginning of the code.
3058014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(edx, FieldOperand(ebx, FunctionTemplateInfo::kCallCodeOffset));
3059014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(edx, FieldOperand(edx, CallHandlerInfo::kFastHandlerOffset));
3060014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag));
3061014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ jmp(edx);
3062014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3063014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Compatible receiver check failed: pop return address, arguments and
3064014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // receiver and throw an Illegal Invocation exception.
3065014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&receiver_check_failed);
3066014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Pop(eax);
3067014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ PopReturnAddressTo(ebx);
3068014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ lea(eax, Operand(eax, times_pointer_size, 1 * kPointerSize));
3069014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ add(esp, eax);
3070014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ PushReturnAddressFrom(ebx);
3071014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  {
3072014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
3073014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ TailCallRuntime(Runtime::kThrowIllegalInvocation);
3074014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
3075014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
3076014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3077f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochstatic void Generate_OnStackReplacementHelper(MacroAssembler* masm,
3078f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                                              bool has_handler_frame) {
3079b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Lookup the function in the JavaScript frame.
3080f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  if (has_handler_frame) {
3081f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ mov(eax, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3082f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ mov(eax, Operand(eax, JavaScriptFrameConstants::kFunctionOffset));
3083f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  } else {
3084f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
3085f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
3086f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
30873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  {
30883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
3089b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Pass function as argument.
30903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ push(eax);
3091014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CallRuntime(Runtime::kCompileForOnStackReplacement);
30923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
3093b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3094257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label skip;
3095f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // If the code object is null, just return to the caller.
3096b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ cmp(eax, Immediate(0));
3097257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &skip, Label::kNear);
3098b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ret(0);
3099b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3100b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ bind(&skip);
3101b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3102f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // Drop any potential handler frame that is be sitting on top of the actual
3103f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // JavaScript frame. This is the case then OSR is triggered from bytecode.
3104f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  if (has_handler_frame) {
3105f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ leave();
3106f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
3107f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
3108b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Load deoptimization data from the code object.
3109b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(ebx, Operand(eax, Code::kDeoptimizationDataOffset - kHeapObjectTag));
3110b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3111b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Load the OSR entrypoint offset from the deoptimization data.
3112b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(ebx, Operand(ebx, FixedArray::OffsetOfElementAt(
3113f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                               DeoptimizationInputData::kOsrPcOffsetIndex) -
3114f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                               kHeapObjectTag));
3115b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ SmiUntag(ebx);
3116b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3117b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Compute the target address = code_obj + header_size + osr_offset
3118b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ lea(eax, Operand(eax, ebx, times_1, Code::kHeaderSize - kHeapObjectTag));
3119b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3120b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Overwrite the return address on the stack.
3121b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(Operand(esp, 0), eax);
3122b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3123b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // And "return" to the OSR entry point of the function.
3124b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ ret(0);
3125b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
3126b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3127f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochvoid Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
3128f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  Generate_OnStackReplacementHelper(masm, false);
3129f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}
3130f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
3131f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochvoid Builtins::Generate_InterpreterOnStackReplacement(MacroAssembler* masm) {
3132f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  Generate_OnStackReplacementHelper(masm, true);
3133f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}
3134b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#undef __
3136014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace internal
3137014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace v8
3138f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke
3139f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke#endif  // V8_TARGET_ARCH_IA32
3140