blob: b7e33d9a74fce5291cf0e0a85f2c05870815526a [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Steve Blocka7e24c12009-10-30 11:49:00 +00004
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#if V8_TARGET_ARCH_IA32
Leon Clarkef7060e22010-06-03 12:02:55 +01006
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#include "src/code-factory.h"
8#include "src/codegen.h"
9#include "src/deoptimizer.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010#include "src/full-codegen/full-codegen.h"
11#include "src/ia32/frames-ia32.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000012
13namespace v8 {
14namespace internal {
15
16
17#define __ ACCESS_MASM(masm)
18
19
Leon Clarkee46be812010-01-19 14:06:41 +000020void Builtins::Generate_Adaptor(MacroAssembler* masm,
21 CFunctionId id,
22 BuiltinExtraArguments extra_args) {
23 // ----------- S t a t e -------------
24 // -- eax : number of arguments excluding receiver
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000025 // -- edi : target
26 // -- edx : new.target
Leon Clarkee46be812010-01-19 14:06:41 +000027 // -- esp[0] : return address
28 // -- esp[4] : last argument
29 // -- ...
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000030 // -- esp[4 * argc] : first argument
Leon Clarkee46be812010-01-19 14:06:41 +000031 // -- esp[4 * (argc +1)] : receiver
32 // -----------------------------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000033 __ AssertFunction(edi);
34
35 // Make sure we operate in the context of the called function (for example
36 // ConstructStubs implemented in C++ will be run in the context of the caller
37 // instead of the callee, due to the way that [[Construct]] is defined for
38 // ordinary functions).
39 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +000040
Leon Clarkee46be812010-01-19 14:06:41 +000041 // Insert extra arguments.
42 int num_extra_args = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000043 if (extra_args != BuiltinExtraArguments::kNone) {
44 __ PopReturnAddressTo(ecx);
45 if (extra_args & BuiltinExtraArguments::kTarget) {
46 ++num_extra_args;
47 __ Push(edi);
48 }
49 if (extra_args & BuiltinExtraArguments::kNewTarget) {
50 ++num_extra_args;
51 __ Push(edx);
52 }
53 __ PushReturnAddressFrom(ecx);
Leon Clarkee46be812010-01-19 14:06:41 +000054 }
55
Steve Block6ded16b2010-05-10 14:33:55 +010056 // JumpToExternalReference expects eax to contain the number of arguments
Leon Clarkee46be812010-01-19 14:06:41 +000057 // including the receiver and the extra arguments.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010058 __ add(eax, Immediate(num_extra_args + 1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000059
Steve Block44f0eee2011-05-26 01:26:41 +010060 __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
Steve Blocka7e24c12009-10-30 11:49:00 +000061}
62
Ben Murdoch097c5b22016-05-18 11:27:45 +010063static void GenerateTailCallToReturnedCode(MacroAssembler* masm,
64 Runtime::FunctionId function_id) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000065 // ----------- S t a t e -------------
Ben Murdoch097c5b22016-05-18 11:27:45 +010066 // -- eax : argument count (preserved for callee)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000067 // -- edx : new target (preserved for callee)
68 // -- edi : target function (preserved for callee)
69 // -----------------------------------
Ben Murdoch097c5b22016-05-18 11:27:45 +010070 {
71 FrameScope scope(masm, StackFrame::INTERNAL);
72 // Push the number of arguments to the callee.
73 __ SmiTag(eax);
74 __ push(eax);
75 // Push a copy of the target function and the new target.
76 __ push(edi);
77 __ push(edx);
78 // Function is also the parameter to the runtime call.
79 __ push(edi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000080
Ben Murdoch097c5b22016-05-18 11:27:45 +010081 __ CallRuntime(function_id, 1);
82 __ mov(ebx, eax);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000083
Ben Murdoch097c5b22016-05-18 11:27:45 +010084 // Restore target function and new target.
85 __ pop(edx);
86 __ pop(edi);
87 __ pop(eax);
88 __ SmiUntag(eax);
89 }
90
91 __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize));
92 __ jmp(ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000093}
94
Ben Murdochb8a8cc12014-11-26 15:28:44 +000095static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010096 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
97 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kCodeOffset));
98 __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize));
99 __ jmp(ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000100}
101
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000102void Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) {
103 // Checking whether the queued function is ready for install is optional,
104 // since we come across interrupts and stack checks elsewhere. However,
105 // not checking may delay installing ready functions, and always checking
106 // would be quite expensive. A good compromise is to first check against
107 // stack limit as a cue for an interrupt signal.
108 Label ok;
109 ExternalReference stack_limit =
110 ExternalReference::address_of_stack_limit(masm->isolate());
111 __ cmp(esp, Operand::StaticVariable(stack_limit));
112 __ j(above_equal, &ok, Label::kNear);
113
Ben Murdoch097c5b22016-05-18 11:27:45 +0100114 GenerateTailCallToReturnedCode(masm, Runtime::kTryInstallOptimizedCode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000115
116 __ bind(&ok);
117 GenerateTailCallToSharedCode(masm);
118}
119
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100120static void Generate_JSConstructStubHelper(MacroAssembler* masm,
121 bool is_api_function,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100122 bool create_implicit_receiver,
123 bool check_derived_construct) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100124 // ----------- S t a t e -------------
125 // -- eax: number of arguments
Ben Murdochda12d292016-06-02 14:46:10 +0100126 // -- esi: context
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100127 // -- edi: constructor function
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000128 // -- ebx: allocation site or undefined
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000129 // -- edx: new target
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100130 // -----------------------------------
131
Steve Blocka7e24c12009-10-30 11:49:00 +0000132 // Enter a construct frame.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100133 {
134 FrameScope scope(masm, StackFrame::CONSTRUCT);
Steve Blocka7e24c12009-10-30 11:49:00 +0000135
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000136 // Preserve the incoming parameters on the stack.
137 __ AssertUndefinedOrAllocationSite(ebx);
Ben Murdochda12d292016-06-02 14:46:10 +0100138 __ push(esi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000139 __ push(ebx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100140 __ SmiTag(eax);
141 __ push(eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000142
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000143 if (create_implicit_receiver) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100144 // Allocate the new receiver object.
145 __ Push(edi);
146 __ Push(edx);
147 FastNewObjectStub stub(masm->isolate());
148 __ CallStub(&stub);
149 __ mov(ebx, eax);
150 __ Pop(edx);
151 __ Pop(edi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000152
Ben Murdoch097c5b22016-05-18 11:27:45 +0100153 // ----------- S t a t e -------------
154 // -- edi: constructor function
155 // -- ebx: newly allocated object
156 // -- edx: new target
157 // -----------------------------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000158
159 // Retrieve smi-tagged arguments count from the stack.
160 __ mov(eax, Operand(esp, 0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000161 }
162
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100163 __ SmiUntag(eax);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000164
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000165 if (create_implicit_receiver) {
166 // Push the allocated receiver to the stack. We need two copies
167 // because we may have to return the original one and the calling
168 // conventions dictate that the called function pops the receiver.
169 __ push(ebx);
170 __ push(ebx);
171 } else {
172 __ PushRoot(Heap::kTheHoleValueRootIndex);
173 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100174
175 // Set up pointer to last argument.
176 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
177
178 // Copy arguments and receiver to the expression stack.
179 Label loop, entry;
180 __ mov(ecx, eax);
181 __ jmp(&entry);
182 __ bind(&loop);
183 __ push(Operand(ebx, ecx, times_4, 0));
184 __ bind(&entry);
185 __ dec(ecx);
186 __ j(greater_equal, &loop);
187
188 // Call the function.
189 if (is_api_function) {
190 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
191 Handle<Code> code =
192 masm->isolate()->builtins()->HandleApiCallConstruct();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000193 __ call(code, RelocInfo::CODE_TARGET);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100194 } else {
195 ParameterCount actual(eax);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000196 __ InvokeFunction(edi, edx, actual, CALL_FUNCTION,
197 CheckDebugStepCallWrapper());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100198 }
199
200 // Store offset of return address for deoptimizer.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000201 if (create_implicit_receiver && !is_api_function) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100202 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
203 }
204
205 // Restore context from the frame.
Ben Murdochda12d292016-06-02 14:46:10 +0100206 __ mov(esi, Operand(ebp, ConstructFrameConstants::kContextOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100207
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000208 if (create_implicit_receiver) {
209 // If the result is an object (in the ECMA sense), we should get rid
Ben Murdoch097c5b22016-05-18 11:27:45 +0100210 // of the receiver and use the result.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000211 Label use_receiver, exit;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100212
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000213 // If the result is a smi, it is *not* an object in the ECMA sense.
214 __ JumpIfSmi(eax, &use_receiver);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100215
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000216 // If the type of the result (stored in its map) is less than
217 // FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense.
218 __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ecx);
219 __ j(above_equal, &exit);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100220
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000221 // Throw away the result of the constructor invocation and use the
222 // on-stack receiver as the result.
223 __ bind(&use_receiver);
224 __ mov(eax, Operand(esp, 0));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100225
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000226 // Restore the arguments count and leave the construct frame. The
227 // arguments count is stored below the receiver.
228 __ bind(&exit);
229 __ mov(ebx, Operand(esp, 1 * kPointerSize));
230 } else {
231 __ mov(ebx, Operand(esp, 0));
232 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100233
234 // Leave construct frame.
Steve Blocka7e24c12009-10-30 11:49:00 +0000235 }
236
Ben Murdoch097c5b22016-05-18 11:27:45 +0100237 // ES6 9.2.2. Step 13+
238 // Check that the result is not a Smi, indicating that the constructor result
239 // from a derived class is neither undefined nor an Object.
240 if (check_derived_construct) {
241 Label dont_throw;
242 __ JumpIfNotSmi(eax, &dont_throw);
243 {
244 FrameScope scope(masm, StackFrame::INTERNAL);
245 __ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject);
246 }
247 __ bind(&dont_throw);
248 }
249
Steve Blocka7e24c12009-10-30 11:49:00 +0000250 // Remove caller arguments from the stack and return.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000251 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000252 __ pop(ecx);
253 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
254 __ push(ecx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000255 if (create_implicit_receiver) {
256 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);
257 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000258 __ ret(0);
259}
260
261
Leon Clarkee46be812010-01-19 14:06:41 +0000262void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100263 Generate_JSConstructStubHelper(masm, false, true, false);
Leon Clarkee46be812010-01-19 14:06:41 +0000264}
265
266
267void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100268 Generate_JSConstructStubHelper(masm, true, false, false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000269}
270
271
272void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100273 Generate_JSConstructStubHelper(masm, false, false, false);
274}
275
276
277void Builtins::Generate_JSBuiltinsConstructStubForDerived(
278 MacroAssembler* masm) {
279 Generate_JSConstructStubHelper(masm, false, false, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000280}
281
282
283void Builtins::Generate_ConstructedNonConstructable(MacroAssembler* masm) {
284 FrameScope scope(masm, StackFrame::INTERNAL);
285 __ push(edi);
286 __ CallRuntime(Runtime::kThrowConstructedNonConstructable);
287}
288
289
290enum IsTagged { kEaxIsSmiTagged, kEaxIsUntaggedInt };
291
292
293// Clobbers ecx, edx, edi; preserves all other registers.
294static void Generate_CheckStackOverflow(MacroAssembler* masm,
295 IsTagged eax_is_tagged) {
296 // eax : the number of items to be pushed to the stack
297 //
298 // Check the stack for overflow. We are not trying to catch
299 // interruptions (e.g. debug break and preemption) here, so the "real stack
300 // limit" is checked.
301 Label okay;
302 ExternalReference real_stack_limit =
303 ExternalReference::address_of_real_stack_limit(masm->isolate());
304 __ mov(edi, Operand::StaticVariable(real_stack_limit));
305 // Make ecx the space we have left. The stack might already be overflowed
306 // here which will cause ecx to become negative.
307 __ mov(ecx, esp);
308 __ sub(ecx, edi);
309 // Make edx the space we need for the array when it is unrolled onto the
310 // stack.
311 __ mov(edx, eax);
312 int smi_tag = eax_is_tagged == kEaxIsSmiTagged ? kSmiTagSize : 0;
313 __ shl(edx, kPointerSizeLog2 - smi_tag);
314 // Check if the arguments will overflow the stack.
315 __ cmp(ecx, edx);
316 __ j(greater, &okay); // Signed comparison.
317
318 // Out of stack space.
319 __ CallRuntime(Runtime::kThrowStackOverflow);
320
321 __ bind(&okay);
Leon Clarkee46be812010-01-19 14:06:41 +0000322}
323
324
Steve Blocka7e24c12009-10-30 11:49:00 +0000325static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
326 bool is_construct) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000327 ProfileEntryHookStub::MaybeCallEntryHook(masm);
328
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100329 {
330 FrameScope scope(masm, StackFrame::INTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000331
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000332 // Setup the context (we need to use the caller context from the isolate).
333 ExternalReference context_address(Isolate::kContextAddress,
334 masm->isolate());
335 __ mov(esi, Operand::StaticVariable(context_address));
336
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100337 // Load the previous frame pointer (ebx) to access C arguments
338 __ mov(ebx, Operand(ebp, 0));
Steve Blocka7e24c12009-10-30 11:49:00 +0000339
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100340 // Push the function and the receiver onto the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000341 __ push(Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100342 __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000343
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100344 // Load the number of arguments and setup pointer to the arguments.
345 __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset));
346 __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000347
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000348 // Check if we have enough stack space to push all arguments.
349 // Expects argument count in eax. Clobbers ecx, edx, edi.
350 Generate_CheckStackOverflow(masm, kEaxIsUntaggedInt);
351
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100352 // Copy arguments to the stack in a loop.
353 Label loop, entry;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000354 __ Move(ecx, Immediate(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000355 __ jmp(&entry, Label::kNear);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100356 __ bind(&loop);
357 __ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv
358 __ push(Operand(edx, 0)); // dereference handle
359 __ inc(ecx);
360 __ bind(&entry);
361 __ cmp(ecx, eax);
362 __ j(not_equal, &loop);
Steve Blocka7e24c12009-10-30 11:49:00 +0000363
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000364 // Load the previous frame pointer (ebx) to access C arguments
365 __ mov(ebx, Operand(ebp, 0));
366
367 // Get the new.target and function from the frame.
368 __ mov(edx, Operand(ebx, EntryFrameConstants::kNewTargetArgOffset));
369 __ mov(edi, Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000370
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100371 // Invoke the code.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000372 Handle<Code> builtin = is_construct
373 ? masm->isolate()->builtins()->Construct()
374 : masm->isolate()->builtins()->Call();
375 __ Call(builtin, RelocInfo::CODE_TARGET);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100376
377 // Exit the internal frame. Notice that this also removes the empty.
378 // context and the function left on the stack by the code
379 // invocation.
Steve Blocka7e24c12009-10-30 11:49:00 +0000380 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100381 __ ret(kPointerSize); // Remove receiver.
Steve Blocka7e24c12009-10-30 11:49:00 +0000382}
383
384
385void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
386 Generate_JSEntryTrampolineHelper(masm, false);
387}
388
389
390void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
391 Generate_JSEntryTrampolineHelper(masm, true);
392}
393
394
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000395// Generate code for entering a JS function with the interpreter.
396// On entry to the function the receiver and arguments have been pushed on the
397// stack left to right. The actual argument count matches the formal parameter
398// count expected by the function.
399//
400// The live registers are:
401// o edi: the JS function object being called
402// o edx: the new target
403// o esi: our context
404// o ebp: the caller's frame pointer
405// o esp: stack pointer (pointing to return address)
406//
Ben Murdoch097c5b22016-05-18 11:27:45 +0100407// The function builds an interpreter frame. See InterpreterFrameConstants in
408// frames.h for its layout.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000409void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
410 // Open a frame scope to indicate that there is a frame on the stack. The
411 // MANUAL indicates that the scope shouldn't actually generate code to set up
412 // the frame (that is done below).
413 FrameScope frame_scope(masm, StackFrame::MANUAL);
414 __ push(ebp); // Caller's frame pointer.
415 __ mov(ebp, esp);
416 __ push(esi); // Callee's context.
417 __ push(edi); // Callee's JS function.
418 __ push(edx); // Callee's new target.
419
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000420 // Get the bytecode array from the function object and load the pointer to the
421 // first entry into edi (InterpreterBytecodeRegister).
422 __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100423
424 Label load_debug_bytecode_array, bytecode_array_loaded;
425 __ cmp(FieldOperand(eax, SharedFunctionInfo::kDebugInfoOffset),
426 Immediate(DebugInfo::uninitialized()));
427 __ j(not_equal, &load_debug_bytecode_array);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000428 __ mov(kInterpreterBytecodeArrayRegister,
429 FieldOperand(eax, SharedFunctionInfo::kFunctionDataOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100430 __ bind(&bytecode_array_loaded);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000431
432 if (FLAG_debug_code) {
433 // Check function data field is actually a BytecodeArray object.
434 __ AssertNotSmi(kInterpreterBytecodeArrayRegister);
435 __ CmpObjectType(kInterpreterBytecodeArrayRegister, BYTECODE_ARRAY_TYPE,
436 eax);
437 __ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
438 }
439
Ben Murdoch097c5b22016-05-18 11:27:45 +0100440 // Push bytecode array.
441 __ push(kInterpreterBytecodeArrayRegister);
442 // Push zero for bytecode array offset.
443 __ push(Immediate(0));
444
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000445 // Allocate the local and temporary register file on the stack.
446 {
447 // Load frame size from the BytecodeArray object.
448 __ mov(ebx, FieldOperand(kInterpreterBytecodeArrayRegister,
449 BytecodeArray::kFrameSizeOffset));
450
451 // Do a stack check to ensure we don't go over the limit.
452 Label ok;
453 __ mov(ecx, esp);
454 __ sub(ecx, ebx);
455 ExternalReference stack_limit =
456 ExternalReference::address_of_real_stack_limit(masm->isolate());
457 __ cmp(ecx, Operand::StaticVariable(stack_limit));
458 __ j(above_equal, &ok);
459 __ CallRuntime(Runtime::kThrowStackOverflow);
460 __ bind(&ok);
461
462 // If ok, push undefined as the initial value for all register file entries.
463 Label loop_header;
464 Label loop_check;
465 __ mov(eax, Immediate(masm->isolate()->factory()->undefined_value()));
466 __ jmp(&loop_check);
467 __ bind(&loop_header);
468 // TODO(rmcilroy): Consider doing more than one push per loop iteration.
469 __ push(eax);
470 // Continue loop if not done.
471 __ bind(&loop_check);
472 __ sub(ebx, Immediate(kPointerSize));
473 __ j(greater_equal, &loop_header);
474 }
475
476 // TODO(rmcilroy): List of things not currently dealt with here but done in
477 // fullcodegen's prologue:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000478 // - Call ProfileEntryHookStub when isolate has a function_entry_hook.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000479 // - Code aging of the BytecodeArray object.
480
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000481 // Load accumulator, register file, bytecode offset, dispatch table into
482 // registers.
483 __ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
484 __ mov(kInterpreterRegisterFileRegister, ebp);
485 __ add(kInterpreterRegisterFileRegister,
486 Immediate(InterpreterFrameConstants::kRegisterFilePointerFromFp));
487 __ mov(kInterpreterBytecodeOffsetRegister,
488 Immediate(BytecodeArray::kHeaderSize - kHeapObjectTag));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100489 __ mov(ebx, Immediate(ExternalReference::interpreter_dispatch_table_address(
490 masm->isolate())));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000491
492 // Push dispatch table as a stack located parameter to the bytecode handler.
493 DCHECK_EQ(-1, kInterpreterDispatchTableSpillSlot);
494 __ push(ebx);
495
496 // Dispatch to the first bytecode handler for the function.
497 __ movzx_b(eax, Operand(kInterpreterBytecodeArrayRegister,
498 kInterpreterBytecodeOffsetRegister, times_1, 0));
499 __ mov(ebx, Operand(ebx, eax, times_pointer_size, 0));
500 // Restore undefined_value in accumulator (eax)
501 // TODO(rmcilroy): Remove this once we move the dispatch table back into a
502 // register.
503 __ mov(eax, Immediate(masm->isolate()->factory()->undefined_value()));
504 // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
505 // and header removal.
506 __ add(ebx, Immediate(Code::kHeaderSize - kHeapObjectTag));
507 __ call(ebx);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100508
509 // Even though the first bytecode handler was called, we will never return.
510 __ Abort(kUnexpectedReturnFromBytecodeHandler);
511
512 // Load debug copy of the bytecode array.
513 __ bind(&load_debug_bytecode_array);
514 Register debug_info = kInterpreterBytecodeArrayRegister;
515 __ mov(debug_info, FieldOperand(eax, SharedFunctionInfo::kDebugInfoOffset));
516 __ mov(kInterpreterBytecodeArrayRegister,
517 FieldOperand(debug_info, DebugInfo::kAbstractCodeIndex));
518 __ jmp(&bytecode_array_loaded);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000519}
520
521
522void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
523 // TODO(rmcilroy): List of things not currently dealt with here but done in
524 // fullcodegen's EmitReturnSequence.
525 // - Supporting FLAG_trace for Runtime::TraceExit.
526 // - Support profiler (specifically decrementing profiling_counter
527 // appropriately and calling out to HandleInterrupts if necessary).
528
529 // The return value is in accumulator, which is already in rax.
530
531 // Leave the frame (also dropping the register file).
532 __ leave();
533
534 // Drop receiver + arguments and return.
535 __ mov(ebx, FieldOperand(kInterpreterBytecodeArrayRegister,
536 BytecodeArray::kParameterSizeOffset));
537 __ pop(ecx);
538 __ add(esp, ebx);
539 __ push(ecx);
540 __ ret(0);
541}
542
543
544static void Generate_InterpreterPushArgs(MacroAssembler* masm,
545 Register array_limit) {
546 // ----------- S t a t e -------------
547 // -- ebx : Pointer to the last argument in the args array.
548 // -- array_limit : Pointer to one before the first argument in the
549 // args array.
550 // -----------------------------------
551 Label loop_header, loop_check;
552 __ jmp(&loop_check);
553 __ bind(&loop_header);
554 __ Push(Operand(ebx, 0));
555 __ sub(ebx, Immediate(kPointerSize));
556 __ bind(&loop_check);
557 __ cmp(ebx, array_limit);
558 __ j(greater, &loop_header, Label::kNear);
559}
560
561
562// static
Ben Murdoch097c5b22016-05-18 11:27:45 +0100563void Builtins::Generate_InterpreterPushArgsAndCallImpl(
564 MacroAssembler* masm, TailCallMode tail_call_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000565 // ----------- S t a t e -------------
566 // -- eax : the number of arguments (not including the receiver)
567 // -- ebx : the address of the first argument to be pushed. Subsequent
568 // arguments should be consecutive above this, in the same order as
569 // they are to be pushed onto the stack.
570 // -- edi : the target to call (can be any Object).
571 // -----------------------------------
572
573 // Pop return address to allow tail-call after pushing arguments.
574 __ Pop(edx);
575
576 // Find the address of the last argument.
577 __ mov(ecx, eax);
578 __ add(ecx, Immediate(1)); // Add one for receiver.
579 __ shl(ecx, kPointerSizeLog2);
580 __ neg(ecx);
581 __ add(ecx, ebx);
582
583 Generate_InterpreterPushArgs(masm, ecx);
584
585 // Call the target.
586 __ Push(edx); // Re-push return address.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100587 __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
588 tail_call_mode),
589 RelocInfo::CODE_TARGET);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000590}
591
592
593// static
594void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
595 // ----------- S t a t e -------------
596 // -- eax : the number of arguments (not including the receiver)
597 // -- edx : the new target
598 // -- edi : the constructor
599 // -- ebx : the address of the first argument to be pushed. Subsequent
600 // arguments should be consecutive above this, in the same order as
601 // they are to be pushed onto the stack.
602 // -----------------------------------
603
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000604 // Pop return address to allow tail-call after pushing arguments.
605 __ Pop(ecx);
606
Ben Murdochda12d292016-06-02 14:46:10 +0100607 // Push edi in the slot meant for receiver. We need an extra register
608 // so store edi temporarily on stack.
609 __ Push(edi);
610
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000611 // Find the address of the last argument.
Ben Murdochda12d292016-06-02 14:46:10 +0100612 __ mov(edi, eax);
613 __ neg(edi);
614 __ shl(edi, kPointerSizeLog2);
615 __ add(edi, ebx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000616
Ben Murdochda12d292016-06-02 14:46:10 +0100617 Generate_InterpreterPushArgs(masm, edi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000618
Ben Murdochda12d292016-06-02 14:46:10 +0100619 // Restore the constructor from slot on stack. It was pushed at the slot
620 // meant for receiver.
621 __ mov(edi, Operand(esp, eax, times_pointer_size, 0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000622
623 // Re-push return address.
624 __ Push(ecx);
625
626 // Call the constructor with unmodified eax, edi, ebi values.
627 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
628}
629
630
Ben Murdoch097c5b22016-05-18 11:27:45 +0100631static void Generate_EnterBytecodeDispatch(MacroAssembler* masm) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000632 // Initialize register file register.
633 __ mov(kInterpreterRegisterFileRegister, ebp);
634 __ add(kInterpreterRegisterFileRegister,
635 Immediate(InterpreterFrameConstants::kRegisterFilePointerFromFp));
636
637 // Get the bytecode array pointer from the frame.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000638 __ mov(kInterpreterBytecodeArrayRegister,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100639 Operand(kInterpreterRegisterFileRegister,
640 InterpreterFrameConstants::kBytecodeArrayFromRegisterPointer));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000641
642 if (FLAG_debug_code) {
643 // Check function data field is actually a BytecodeArray object.
644 __ AssertNotSmi(kInterpreterBytecodeArrayRegister);
645 __ CmpObjectType(kInterpreterBytecodeArrayRegister, BYTECODE_ARRAY_TYPE,
646 ebx);
647 __ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
648 }
649
650 // Get the target bytecode offset from the frame.
651 __ mov(
652 kInterpreterBytecodeOffsetRegister,
653 Operand(kInterpreterRegisterFileRegister,
654 InterpreterFrameConstants::kBytecodeOffsetFromRegisterPointer));
655 __ SmiUntag(kInterpreterBytecodeOffsetRegister);
656
Ben Murdoch097c5b22016-05-18 11:27:45 +0100657 // Push dispatch table as a stack located parameter to the bytecode handler.
658 __ mov(ebx, Immediate(ExternalReference::interpreter_dispatch_table_address(
659 masm->isolate())));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000660 DCHECK_EQ(-1, kInterpreterDispatchTableSpillSlot);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100661 __ Pop(esi);
662 __ Push(ebx);
663 __ Push(esi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000664
665 // Dispatch to the target bytecode.
666 __ movzx_b(esi, Operand(kInterpreterBytecodeArrayRegister,
667 kInterpreterBytecodeOffsetRegister, times_1, 0));
668 __ mov(ebx, Operand(ebx, esi, times_pointer_size, 0));
669
670 // Get the context from the frame.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000671 __ mov(kContextRegister,
672 Operand(kInterpreterRegisterFileRegister,
673 InterpreterFrameConstants::kContextFromRegisterPointer));
674
675 // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
676 // and header removal.
677 __ add(ebx, Immediate(Code::kHeaderSize - kHeapObjectTag));
678 __ jmp(ebx);
679}
680
681
Ben Murdoch097c5b22016-05-18 11:27:45 +0100682static void Generate_InterpreterNotifyDeoptimizedHelper(
683 MacroAssembler* masm, Deoptimizer::BailoutType type) {
684 // Enter an internal frame.
685 {
686 FrameScope scope(masm, StackFrame::INTERNAL);
687
688 // Pass the deoptimization type to the runtime system.
689 __ Push(Smi::FromInt(static_cast<int>(type)));
690 __ CallRuntime(Runtime::kNotifyDeoptimized);
691 // Tear down internal frame.
692 }
693
694 // Drop state (we don't use these for interpreter deopts) and and pop the
695 // accumulator value into the accumulator register and push PC at top
696 // of stack (to simulate initial call to bytecode handler in interpreter entry
697 // trampoline).
698 __ Pop(ebx);
699 __ Drop(1);
700 __ Pop(kInterpreterAccumulatorRegister);
701 __ Push(ebx);
702
703 // Enter the bytecode dispatch.
704 Generate_EnterBytecodeDispatch(masm);
705}
706
707
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000708void Builtins::Generate_InterpreterNotifyDeoptimized(MacroAssembler* masm) {
709 Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
710}
711
712
713void Builtins::Generate_InterpreterNotifySoftDeoptimized(MacroAssembler* masm) {
714 Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
715}
716
717
718void Builtins::Generate_InterpreterNotifyLazyDeoptimized(MacroAssembler* masm) {
719 Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
720}
721
Ben Murdoch097c5b22016-05-18 11:27:45 +0100722void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
723 // Set the address of the interpreter entry trampoline as a return address.
724 // This simulates the initial call to bytecode handlers in interpreter entry
725 // trampoline. The return will never actually be taken, but our stack walker
726 // uses this address to determine whether a frame is interpreted.
727 __ Push(masm->isolate()->builtins()->InterpreterEntryTrampoline());
728
729 Generate_EnterBytecodeDispatch(masm);
730}
731
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000732
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000733void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100734 GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy);
Iain Merrick75681382010-08-19 15:07:18 +0100735}
736
737
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000738void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100739 GenerateTailCallToReturnedCode(masm,
740 Runtime::kCompileOptimized_NotConcurrent);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000741}
742
743
744void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100745 GenerateTailCallToReturnedCode(masm, Runtime::kCompileOptimized_Concurrent);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000746}
747
748
749static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
750 // For now, we are relying on the fact that make_code_young doesn't do any
751 // garbage collection which allows us to save/restore the registers without
752 // worrying about which of them contain pointers. We also don't build an
753 // internal frame to make the code faster, since we shouldn't have to do stack
754 // crawls in MakeCodeYoung. This seems a bit fragile.
755
756 // Re-execute the code that was patched back to the young age when
757 // the stub returns.
758 __ sub(Operand(esp, 0), Immediate(5));
759 __ pushad();
760 __ mov(eax, Operand(esp, 8 * kPointerSize));
761 {
762 FrameScope scope(masm, StackFrame::MANUAL);
763 __ PrepareCallCFunction(2, ebx);
764 __ mov(Operand(esp, 1 * kPointerSize),
765 Immediate(ExternalReference::isolate_address(masm->isolate())));
766 __ mov(Operand(esp, 0), eax);
767 __ CallCFunction(
768 ExternalReference::get_make_code_young_function(masm->isolate()), 2);
769 }
770 __ popad();
771 __ ret(0);
772}
773
774#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \
775void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \
776 MacroAssembler* masm) { \
777 GenerateMakeCodeYoungAgainCommon(masm); \
778} \
779void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \
780 MacroAssembler* masm) { \
781 GenerateMakeCodeYoungAgainCommon(masm); \
782}
783CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
784#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
785
786
787void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
788 // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact
789 // that make_code_young doesn't do any garbage collection which allows us to
790 // save/restore the registers without worrying about which of them contain
791 // pointers.
792 __ pushad();
793 __ mov(eax, Operand(esp, 8 * kPointerSize));
794 __ sub(eax, Immediate(Assembler::kCallInstructionLength));
795 { // NOLINT
796 FrameScope scope(masm, StackFrame::MANUAL);
797 __ PrepareCallCFunction(2, ebx);
798 __ mov(Operand(esp, 1 * kPointerSize),
799 Immediate(ExternalReference::isolate_address(masm->isolate())));
800 __ mov(Operand(esp, 0), eax);
801 __ CallCFunction(
802 ExternalReference::get_mark_code_as_executed_function(masm->isolate()),
803 2);
804 }
805 __ popad();
806
807 // Perform prologue operations usually performed by the young code stub.
808 __ pop(eax); // Pop return address into scratch register.
809 __ push(ebp); // Caller's frame pointer.
810 __ mov(ebp, esp);
811 __ push(esi); // Callee's context.
812 __ push(edi); // Callee's JS Function.
813 __ push(eax); // Push return address after frame prologue.
814
815 // Jump to point after the code-age stub.
816 __ ret(0);
817}
818
819
820void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
821 GenerateMakeCodeYoungAgainCommon(masm);
822}
823
824
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000825void Builtins::Generate_MarkCodeAsToBeExecutedOnce(MacroAssembler* masm) {
826 Generate_MarkCodeAsExecutedOnce(masm);
827}
828
829
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000830static void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
831 SaveFPRegsMode save_doubles) {
832 // Enter an internal frame.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100833 {
834 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100835
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000836 // Preserve registers across notification, this is important for compiled
837 // stubs that tail call the runtime on deopts passing their parameters in
838 // registers.
839 __ pushad();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000840 __ CallRuntime(Runtime::kNotifyStubFailure, save_doubles);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000841 __ popad();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100842 // Tear down internal frame.
843 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100844
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000845 __ pop(MemOperand(esp, 0)); // Ignore state offset
846 __ ret(0); // Return to IC Miss stub, continuation still on stack.
847}
848
849
850void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
851 Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
852}
853
854
855void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
856 Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100857}
858
859
860static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
861 Deoptimizer::BailoutType type) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100862 {
863 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100864
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100865 // Pass deoptimization type to the runtime system.
866 __ push(Immediate(Smi::FromInt(static_cast<int>(type))));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000867 __ CallRuntime(Runtime::kNotifyDeoptimized);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100868
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100869 // Tear down internal frame.
870 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100871
872 // Get the full codegen state from the stack and untag it.
873 __ mov(ecx, Operand(esp, 1 * kPointerSize));
874 __ SmiUntag(ecx);
875
876 // Switch on the state.
Ben Murdoch257744e2011-11-30 15:57:28 +0000877 Label not_no_registers, not_tos_eax;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100878 __ cmp(ecx, FullCodeGenerator::NO_REGISTERS);
Ben Murdoch257744e2011-11-30 15:57:28 +0000879 __ j(not_equal, &not_no_registers, Label::kNear);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100880 __ ret(1 * kPointerSize); // Remove state.
881
882 __ bind(&not_no_registers);
883 __ mov(eax, Operand(esp, 2 * kPointerSize));
884 __ cmp(ecx, FullCodeGenerator::TOS_REG);
Ben Murdoch257744e2011-11-30 15:57:28 +0000885 __ j(not_equal, &not_tos_eax, Label::kNear);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100886 __ ret(2 * kPointerSize); // Remove state, eax.
887
888 __ bind(&not_tos_eax);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000889 __ Abort(kNoCasesLeft);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100890}
891
892
893void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
894 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
895}
896
897
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000898void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
899 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100900}
901
902
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000903void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
904 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100905}
906
907
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000908// static
909void Builtins::Generate_DatePrototype_GetField(MacroAssembler* masm,
910 int field_index) {
911 // ----------- S t a t e -------------
912 // -- esp[0] : return address
913 // -- esp[4] : receiver
914 // -----------------------------------
Steve Block44f0eee2011-05-26 01:26:41 +0100915
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000916 // 1. Load receiver into eax and check that it's actually a JSDate object.
917 Label receiver_not_date;
918 {
919 __ mov(eax, Operand(esp, kPointerSize));
920 __ JumpIfSmi(eax, &receiver_not_date);
921 __ CmpObjectType(eax, JS_DATE_TYPE, ebx);
922 __ j(not_equal, &receiver_not_date);
923 }
924
925 // 2. Load the specified date field, falling back to the runtime as necessary.
926 if (field_index == JSDate::kDateValue) {
927 __ mov(eax, FieldOperand(eax, JSDate::kValueOffset));
928 } else {
929 if (field_index < JSDate::kFirstUncachedField) {
930 Label stamp_mismatch;
931 __ mov(edx, Operand::StaticVariable(
932 ExternalReference::date_cache_stamp(masm->isolate())));
933 __ cmp(edx, FieldOperand(eax, JSDate::kCacheStampOffset));
934 __ j(not_equal, &stamp_mismatch, Label::kNear);
935 __ mov(eax, FieldOperand(
936 eax, JSDate::kValueOffset + field_index * kPointerSize));
937 __ ret(1 * kPointerSize);
938 __ bind(&stamp_mismatch);
939 }
940 FrameScope scope(masm, StackFrame::INTERNAL);
941 __ PrepareCallCFunction(2, ebx);
942 __ mov(Operand(esp, 0), eax);
943 __ mov(Operand(esp, 1 * kPointerSize),
944 Immediate(Smi::FromInt(field_index)));
945 __ CallCFunction(
946 ExternalReference::get_date_field_function(masm->isolate()), 2);
947 }
948 __ ret(1 * kPointerSize);
949
950 // 3. Raise a TypeError if the receiver is not a date.
951 __ bind(&receiver_not_date);
952 {
953 FrameScope scope(masm, StackFrame::MANUAL);
954 __ EnterFrame(StackFrame::INTERNAL);
955 __ CallRuntime(Runtime::kThrowNotDateError);
956 }
957}
958
Ben Murdochda12d292016-06-02 14:46:10 +0100959// static
960void Builtins::Generate_FunctionHasInstance(MacroAssembler* masm) {
961 // ----------- S t a t e -------------
962 // -- eax : argc
963 // -- esp[0] : return address
964 // -- esp[4] : first argument (left-hand side)
965 // -- esp[8] : receiver (right-hand side)
966 // -----------------------------------
967
968 {
969 FrameScope scope(masm, StackFrame::INTERNAL);
970 __ mov(InstanceOfDescriptor::LeftRegister(),
971 Operand(ebp, 2 * kPointerSize)); // Load left-hand side.
972 __ mov(InstanceOfDescriptor::RightRegister(),
973 Operand(ebp, 3 * kPointerSize)); // Load right-hand side.
974 InstanceOfStub stub(masm->isolate(), true);
975 __ CallStub(&stub);
976 }
977
978 // Pop the argument and the receiver.
979 __ ret(2 * kPointerSize);
980}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000981
982// static
983void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
984 // ----------- S t a t e -------------
985 // -- eax : argc
986 // -- esp[0] : return address
987 // -- esp[4] : argArray
988 // -- esp[8] : thisArg
989 // -- esp[12] : receiver
990 // -----------------------------------
991
992 // 1. Load receiver into edi, argArray into eax (if present), remove all
993 // arguments from the stack (including the receiver), and push thisArg (if
994 // present) instead.
995 {
996 Label no_arg_array, no_this_arg;
997 __ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
998 __ mov(ebx, edx);
999 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001000 __ test(eax, eax);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001001 __ j(zero, &no_this_arg, Label::kNear);
1002 {
1003 __ mov(edx, Operand(esp, eax, times_pointer_size, 0));
1004 __ cmp(eax, Immediate(1));
1005 __ j(equal, &no_arg_array, Label::kNear);
1006 __ mov(ebx, Operand(esp, eax, times_pointer_size, -kPointerSize));
1007 __ bind(&no_arg_array);
1008 }
1009 __ bind(&no_this_arg);
1010 __ PopReturnAddressTo(ecx);
1011 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1012 __ Push(edx);
1013 __ PushReturnAddressFrom(ecx);
1014 __ Move(eax, ebx);
1015 }
1016
1017 // ----------- S t a t e -------------
1018 // -- eax : argArray
1019 // -- edi : receiver
1020 // -- esp[0] : return address
1021 // -- esp[4] : thisArg
1022 // -----------------------------------
1023
1024 // 2. Make sure the receiver is actually callable.
1025 Label receiver_not_callable;
1026 __ JumpIfSmi(edi, &receiver_not_callable, Label::kNear);
1027 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
Ben Murdochda12d292016-06-02 14:46:10 +01001028 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
1029 Immediate(1 << Map::kIsCallable));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001030 __ j(zero, &receiver_not_callable, Label::kNear);
1031
1032 // 3. Tail call with no arguments if argArray is null or undefined.
1033 Label no_arguments;
1034 __ JumpIfRoot(eax, Heap::kNullValueRootIndex, &no_arguments, Label::kNear);
1035 __ JumpIfRoot(eax, Heap::kUndefinedValueRootIndex, &no_arguments,
1036 Label::kNear);
1037
1038 // 4a. Apply the receiver to the given argArray (passing undefined for
1039 // new.target).
1040 __ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
1041 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1042
1043 // 4b. The argArray is either null or undefined, so we tail call without any
1044 // arguments to the receiver.
1045 __ bind(&no_arguments);
1046 {
1047 __ Set(eax, 0);
1048 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1049 }
1050
1051 // 4c. The receiver is not callable, throw an appropriate TypeError.
1052 __ bind(&receiver_not_callable);
1053 {
1054 __ mov(Operand(esp, kPointerSize), edi);
1055 __ TailCallRuntime(Runtime::kThrowApplyNonFunction);
1056 }
1057}
1058
1059
1060// static
1061void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) {
1062 // Stack Layout:
1063 // esp[0] : Return address
1064 // esp[8] : Argument n
1065 // esp[16] : Argument n-1
1066 // ...
1067 // esp[8 * n] : Argument 1
1068 // esp[8 * (n + 1)] : Receiver (callable to call)
1069 //
1070 // eax contains the number of arguments, n, not counting the receiver.
1071 //
1072 // 1. Make sure we have at least one argument.
1073 {
1074 Label done;
1075 __ test(eax, eax);
1076 __ j(not_zero, &done, Label::kNear);
1077 __ PopReturnAddressTo(ebx);
1078 __ PushRoot(Heap::kUndefinedValueRootIndex);
1079 __ PushReturnAddressFrom(ebx);
Steve Blocka7e24c12009-10-30 11:49:00 +00001080 __ inc(eax);
1081 __ bind(&done);
1082 }
1083
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001084 // 2. Get the callable to call (passed as receiver) from the stack.
1085 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize));
Steve Blocka7e24c12009-10-30 11:49:00 +00001086
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001087 // 3. Shift arguments and return address one slot down on the stack
Andrei Popescu402d9372010-02-26 13:31:12 +00001088 // (overwriting the original receiver). Adjust argument count to make
1089 // the original first argument the new receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001090 {
1091 Label loop;
Leon Clarkee46be812010-01-19 14:06:41 +00001092 __ mov(ecx, eax);
Steve Blocka7e24c12009-10-30 11:49:00 +00001093 __ bind(&loop);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001094 __ mov(ebx, Operand(esp, ecx, times_pointer_size, 0));
1095 __ mov(Operand(esp, ecx, times_pointer_size, kPointerSize), ebx);
Steve Blocka7e24c12009-10-30 11:49:00 +00001096 __ dec(ecx);
Andrei Popescu402d9372010-02-26 13:31:12 +00001097 __ j(not_sign, &loop); // While non-negative (to copy return address).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001098 __ pop(ebx); // Discard copy of return address.
Leon Clarkee46be812010-01-19 14:06:41 +00001099 __ dec(eax); // One fewer argument (first argument is new receiver).
Steve Blocka7e24c12009-10-30 11:49:00 +00001100 }
1101
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001102 // 4. Call the callable.
1103 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
Steve Blocka7e24c12009-10-30 11:49:00 +00001104}
1105
1106
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001107void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
1108 // ----------- S t a t e -------------
1109 // -- eax : argc
1110 // -- esp[0] : return address
1111 // -- esp[4] : argumentsList
1112 // -- esp[8] : thisArgument
1113 // -- esp[12] : target
1114 // -- esp[16] : receiver
1115 // -----------------------------------
1116
1117 // 1. Load target into edi (if present), argumentsList into eax (if present),
1118 // remove all arguments from the stack (including the receiver), and push
1119 // thisArgument (if present) instead.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001120 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001121 Label done;
1122 __ LoadRoot(edi, Heap::kUndefinedValueRootIndex);
1123 __ mov(edx, edi);
1124 __ mov(ebx, edi);
1125 __ cmp(eax, Immediate(1));
1126 __ j(below, &done, Label::kNear);
1127 __ mov(edi, Operand(esp, eax, times_pointer_size, -0 * kPointerSize));
1128 __ j(equal, &done, Label::kNear);
1129 __ mov(edx, Operand(esp, eax, times_pointer_size, -1 * kPointerSize));
1130 __ cmp(eax, Immediate(3));
1131 __ j(below, &done, Label::kNear);
1132 __ mov(ebx, Operand(esp, eax, times_pointer_size, -2 * kPointerSize));
1133 __ bind(&done);
1134 __ PopReturnAddressTo(ecx);
1135 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1136 __ Push(edx);
1137 __ PushReturnAddressFrom(ecx);
1138 __ Move(eax, ebx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001139 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001140
1141 // ----------- S t a t e -------------
1142 // -- eax : argumentsList
1143 // -- edi : target
1144 // -- esp[0] : return address
1145 // -- esp[4] : thisArgument
1146 // -----------------------------------
1147
1148 // 2. Make sure the target is actually callable.
1149 Label target_not_callable;
1150 __ JumpIfSmi(edi, &target_not_callable, Label::kNear);
1151 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
Ben Murdochda12d292016-06-02 14:46:10 +01001152 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
1153 Immediate(1 << Map::kIsCallable));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001154 __ j(zero, &target_not_callable, Label::kNear);
1155
1156 // 3a. Apply the target to the given argumentsList (passing undefined for
1157 // new.target).
1158 __ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
1159 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1160
1161 // 3b. The target is not callable, throw an appropriate TypeError.
1162 __ bind(&target_not_callable);
1163 {
1164 __ mov(Operand(esp, kPointerSize), edi);
1165 __ TailCallRuntime(Runtime::kThrowApplyNonFunction);
1166 }
1167}
1168
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001169void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
1170 // ----------- S t a t e -------------
1171 // -- eax : argc
1172 // -- esp[0] : return address
1173 // -- esp[4] : new.target (optional)
1174 // -- esp[8] : argumentsList
1175 // -- esp[12] : target
1176 // -- esp[16] : receiver
1177 // -----------------------------------
1178
1179 // 1. Load target into edi (if present), argumentsList into eax (if present),
1180 // new.target into edx (if present, otherwise use target), remove all
1181 // arguments from the stack (including the receiver), and push thisArgument
1182 // (if present) instead.
1183 {
1184 Label done;
1185 __ LoadRoot(edi, Heap::kUndefinedValueRootIndex);
1186 __ mov(edx, edi);
1187 __ mov(ebx, edi);
1188 __ cmp(eax, Immediate(1));
1189 __ j(below, &done, Label::kNear);
1190 __ mov(edi, Operand(esp, eax, times_pointer_size, -0 * kPointerSize));
1191 __ mov(edx, edi);
1192 __ j(equal, &done, Label::kNear);
1193 __ mov(ebx, Operand(esp, eax, times_pointer_size, -1 * kPointerSize));
1194 __ cmp(eax, Immediate(3));
1195 __ j(below, &done, Label::kNear);
1196 __ mov(edx, Operand(esp, eax, times_pointer_size, -2 * kPointerSize));
1197 __ bind(&done);
1198 __ PopReturnAddressTo(ecx);
1199 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1200 __ PushRoot(Heap::kUndefinedValueRootIndex);
1201 __ PushReturnAddressFrom(ecx);
1202 __ Move(eax, ebx);
1203 }
1204
1205 // ----------- S t a t e -------------
1206 // -- eax : argumentsList
1207 // -- edx : new.target
1208 // -- edi : target
1209 // -- esp[0] : return address
1210 // -- esp[4] : receiver (undefined)
1211 // -----------------------------------
1212
1213 // 2. Make sure the target is actually a constructor.
1214 Label target_not_constructor;
1215 __ JumpIfSmi(edi, &target_not_constructor, Label::kNear);
1216 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
Ben Murdochda12d292016-06-02 14:46:10 +01001217 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
1218 Immediate(1 << Map::kIsConstructor));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001219 __ j(zero, &target_not_constructor, Label::kNear);
1220
1221 // 3. Make sure the target is actually a constructor.
1222 Label new_target_not_constructor;
1223 __ JumpIfSmi(edx, &new_target_not_constructor, Label::kNear);
1224 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
Ben Murdochda12d292016-06-02 14:46:10 +01001225 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
1226 Immediate(1 << Map::kIsConstructor));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001227 __ j(zero, &new_target_not_constructor, Label::kNear);
1228
1229 // 4a. Construct the target with the given new.target and argumentsList.
1230 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1231
1232 // 4b. The target is not a constructor, throw an appropriate TypeError.
1233 __ bind(&target_not_constructor);
1234 {
1235 __ mov(Operand(esp, kPointerSize), edi);
1236 __ TailCallRuntime(Runtime::kThrowCalledNonCallable);
1237 }
1238
1239 // 4c. The new.target is not a constructor, throw an appropriate TypeError.
1240 __ bind(&new_target_not_constructor);
1241 {
1242 __ mov(Operand(esp, kPointerSize), edx);
1243 __ TailCallRuntime(Runtime::kThrowCalledNonCallable);
1244 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001245}
1246
1247
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001248void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
1249 // ----------- S t a t e -------------
1250 // -- eax : argc
1251 // -- esp[0] : return address
1252 // -- esp[4] : last argument
1253 // -----------------------------------
1254 Label generic_array_code;
1255
1256 // Get the InternalArray function.
1257 __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi);
1258
1259 if (FLAG_debug_code) {
1260 // Initial map for the builtin InternalArray function should be a map.
1261 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1262 // Will both indicate a NULL and a Smi.
1263 __ test(ebx, Immediate(kSmiTagMask));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001264 __ Assert(not_zero, kUnexpectedInitialMapForInternalArrayFunction);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001265 __ CmpObjectType(ebx, MAP_TYPE, ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001266 __ Assert(equal, kUnexpectedInitialMapForInternalArrayFunction);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001267 }
1268
1269 // Run the native code for the InternalArray function called as a normal
1270 // function.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001271 // tail call a stub
1272 InternalArrayConstructorStub stub(masm->isolate());
1273 __ TailCallStub(&stub);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001274}
1275
1276
Steve Blocka7e24c12009-10-30 11:49:00 +00001277void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
1278 // ----------- S t a t e -------------
1279 // -- eax : argc
1280 // -- esp[0] : return address
1281 // -- esp[4] : last argument
1282 // -----------------------------------
Kristian Monsen25f61362010-05-21 11:50:48 +01001283 Label generic_array_code;
Steve Blocka7e24c12009-10-30 11:49:00 +00001284
1285 // Get the Array function.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001286 __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001287 __ mov(edx, edi);
Steve Blocka7e24c12009-10-30 11:49:00 +00001288
1289 if (FLAG_debug_code) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001290 // Initial map for the builtin Array function should be a map.
Steve Blocka7e24c12009-10-30 11:49:00 +00001291 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1292 // Will both indicate a NULL and a Smi.
1293 __ test(ebx, Immediate(kSmiTagMask));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001294 __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction);
Steve Blocka7e24c12009-10-30 11:49:00 +00001295 __ CmpObjectType(ebx, MAP_TYPE, ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001296 __ Assert(equal, kUnexpectedInitialMapForArrayFunction);
Steve Blocka7e24c12009-10-30 11:49:00 +00001297 }
1298
1299 // Run the native code for the Array function called as a normal function.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001300 // tail call a stub
1301 __ mov(ebx, masm->isolate()->factory()->undefined_value());
1302 ArrayConstructorStub stub(masm->isolate());
1303 __ TailCallStub(&stub);
Steve Blocka7e24c12009-10-30 11:49:00 +00001304}
1305
1306
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001307// static
Ben Murdoch097c5b22016-05-18 11:27:45 +01001308void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
1309 // ----------- S t a t e -------------
1310 // -- eax : number of arguments
1311 // -- esp[0] : return address
1312 // -- esp[(argc - n) * 8] : arg[n] (zero-based)
1313 // -- esp[(argc + 1) * 8] : receiver
1314 // -----------------------------------
1315 Condition const cc = (kind == MathMaxMinKind::kMin) ? below : above;
1316 Heap::RootListIndex const root_index =
1317 (kind == MathMaxMinKind::kMin) ? Heap::kInfinityValueRootIndex
1318 : Heap::kMinusInfinityValueRootIndex;
1319 XMMRegister const reg = (kind == MathMaxMinKind::kMin) ? xmm1 : xmm0;
1320
1321 // Load the accumulator with the default return value (either -Infinity or
1322 // +Infinity), with the tagged value in edx and the double value in xmm0.
1323 __ LoadRoot(edx, root_index);
1324 __ movsd(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
1325 __ Move(ecx, eax);
1326
1327 Label done_loop, loop;
1328 __ bind(&loop);
1329 {
1330 // Check if all parameters done.
1331 __ test(ecx, ecx);
1332 __ j(zero, &done_loop);
1333
1334 // Load the next parameter tagged value into ebx.
1335 __ mov(ebx, Operand(esp, ecx, times_pointer_size, 0));
1336
1337 // Load the double value of the parameter into xmm1, maybe converting the
1338 // parameter to a number first using the ToNumberStub if necessary.
1339 Label convert, convert_smi, convert_number, done_convert;
1340 __ bind(&convert);
1341 __ JumpIfSmi(ebx, &convert_smi);
1342 __ JumpIfRoot(FieldOperand(ebx, HeapObject::kMapOffset),
1343 Heap::kHeapNumberMapRootIndex, &convert_number);
1344 {
1345 // Parameter is not a Number, use the ToNumberStub to convert it.
1346 FrameScope scope(masm, StackFrame::INTERNAL);
1347 __ SmiTag(eax);
1348 __ SmiTag(ecx);
1349 __ Push(eax);
1350 __ Push(ecx);
1351 __ Push(edx);
1352 __ mov(eax, ebx);
1353 ToNumberStub stub(masm->isolate());
1354 __ CallStub(&stub);
1355 __ mov(ebx, eax);
1356 __ Pop(edx);
1357 __ Pop(ecx);
1358 __ Pop(eax);
1359 {
1360 // Restore the double accumulator value (xmm0).
1361 Label restore_smi, done_restore;
1362 __ JumpIfSmi(edx, &restore_smi, Label::kNear);
1363 __ movsd(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
1364 __ jmp(&done_restore, Label::kNear);
1365 __ bind(&restore_smi);
1366 __ SmiUntag(edx);
1367 __ Cvtsi2sd(xmm0, edx);
1368 __ SmiTag(edx);
1369 __ bind(&done_restore);
1370 }
1371 __ SmiUntag(ecx);
1372 __ SmiUntag(eax);
1373 }
1374 __ jmp(&convert);
1375 __ bind(&convert_number);
1376 __ movsd(xmm1, FieldOperand(ebx, HeapNumber::kValueOffset));
1377 __ jmp(&done_convert, Label::kNear);
1378 __ bind(&convert_smi);
1379 __ SmiUntag(ebx);
1380 __ Cvtsi2sd(xmm1, ebx);
1381 __ SmiTag(ebx);
1382 __ bind(&done_convert);
1383
1384 // Perform the actual comparison with the accumulator value on the left hand
1385 // side (xmm0) and the next parameter value on the right hand side (xmm1).
1386 Label compare_equal, compare_nan, compare_swap, done_compare;
1387 __ ucomisd(xmm0, xmm1);
1388 __ j(parity_even, &compare_nan, Label::kNear);
1389 __ j(cc, &done_compare, Label::kNear);
1390 __ j(equal, &compare_equal, Label::kNear);
1391
1392 // Result is on the right hand side.
1393 __ bind(&compare_swap);
1394 __ movaps(xmm0, xmm1);
1395 __ mov(edx, ebx);
1396 __ jmp(&done_compare, Label::kNear);
1397
1398 // At least one side is NaN, which means that the result will be NaN too.
1399 __ bind(&compare_nan);
1400 __ LoadRoot(edx, Heap::kNanValueRootIndex);
1401 __ movsd(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
1402 __ jmp(&done_compare, Label::kNear);
1403
1404 // Left and right hand side are equal, check for -0 vs. +0.
1405 __ bind(&compare_equal);
1406 __ movmskpd(edi, reg);
1407 __ test(edi, Immediate(1));
1408 __ j(not_zero, &compare_swap);
1409
1410 __ bind(&done_compare);
1411 __ dec(ecx);
1412 __ jmp(&loop);
1413 }
1414
1415 __ bind(&done_loop);
1416 __ PopReturnAddressTo(ecx);
1417 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1418 __ PushReturnAddressFrom(ecx);
1419 __ mov(eax, edx);
1420 __ Ret();
1421}
1422
1423// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001424void Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001425 // ----------- S t a t e -------------
1426 // -- eax : number of arguments
1427 // -- edi : constructor function
1428 // -- esp[0] : return address
1429 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1430 // -- esp[(argc + 1) * 4] : receiver
1431 // -----------------------------------
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001432
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001433 // 1. Load the first argument into eax and get rid of the rest (including the
1434 // receiver).
1435 Label no_arguments;
1436 {
1437 __ test(eax, eax);
1438 __ j(zero, &no_arguments, Label::kNear);
1439 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1440 __ PopReturnAddressTo(ecx);
1441 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1442 __ PushReturnAddressFrom(ecx);
1443 __ mov(eax, ebx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001444 }
1445
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001446 // 2a. Convert the first argument to a number.
1447 ToNumberStub stub(masm->isolate());
1448 __ TailCallStub(&stub);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001449
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001450 // 2b. No arguments, return +0 (already in eax).
1451 __ bind(&no_arguments);
1452 __ ret(1 * kPointerSize);
1453}
1454
1455
1456// static
1457void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001458 // ----------- S t a t e -------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001459 // -- eax : number of arguments
1460 // -- edi : constructor function
1461 // -- edx : new target
1462 // -- esp[0] : return address
1463 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1464 // -- esp[(argc + 1) * 4] : receiver
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001465 // -----------------------------------
1466
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001467 // 1. Make sure we operate in the context of the called function.
1468 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001469
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001470 // 2. Load the first argument into ebx and get rid of the rest (including the
1471 // receiver).
1472 {
1473 Label no_arguments, done;
1474 __ test(eax, eax);
1475 __ j(zero, &no_arguments, Label::kNear);
1476 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1477 __ jmp(&done, Label::kNear);
1478 __ bind(&no_arguments);
1479 __ Move(ebx, Smi::FromInt(0));
1480 __ bind(&done);
1481 __ PopReturnAddressTo(ecx);
1482 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1483 __ PushReturnAddressFrom(ecx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001484 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001485
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001486 // 3. Make sure ebx is a number.
1487 {
1488 Label done_convert;
1489 __ JumpIfSmi(ebx, &done_convert);
1490 __ CompareRoot(FieldOperand(ebx, HeapObject::kMapOffset),
1491 Heap::kHeapNumberMapRootIndex);
1492 __ j(equal, &done_convert);
1493 {
1494 FrameScope scope(masm, StackFrame::INTERNAL);
1495 __ Push(edi);
1496 __ Push(edx);
1497 __ Move(eax, ebx);
1498 ToNumberStub stub(masm->isolate());
1499 __ CallStub(&stub);
1500 __ Move(ebx, eax);
1501 __ Pop(edx);
1502 __ Pop(edi);
1503 }
1504 __ bind(&done_convert);
1505 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001506
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001507 // 4. Check if new target and constructor differ.
1508 Label new_object;
1509 __ cmp(edx, edi);
1510 __ j(not_equal, &new_object);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001511
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001512 // 5. Allocate a JSValue wrapper for the number.
1513 __ AllocateJSValue(eax, edi, ebx, ecx, &new_object);
1514 __ Ret();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001515
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001516 // 6. Fallback to the runtime to create new object.
1517 __ bind(&new_object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001518 {
1519 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001520 __ Push(ebx); // the first argument
Ben Murdoch097c5b22016-05-18 11:27:45 +01001521 FastNewObjectStub stub(masm->isolate());
1522 __ CallStub(&stub);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001523 __ Pop(FieldOperand(eax, JSValue::kValueOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001524 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001525 __ Ret();
1526}
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001527
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001528
1529// static
1530void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
1531 // ----------- S t a t e -------------
1532 // -- eax : number of arguments
1533 // -- edi : constructor function
1534 // -- esp[0] : return address
1535 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1536 // -- esp[(argc + 1) * 4] : receiver
1537 // -----------------------------------
1538
1539 // 1. Load the first argument into eax and get rid of the rest (including the
1540 // receiver).
1541 Label no_arguments;
1542 {
1543 __ test(eax, eax);
1544 __ j(zero, &no_arguments, Label::kNear);
1545 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1546 __ PopReturnAddressTo(ecx);
1547 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1548 __ PushReturnAddressFrom(ecx);
1549 __ mov(eax, ebx);
1550 }
1551
1552 // 2a. At least one argument, return eax if it's a string, otherwise
1553 // dispatch to appropriate conversion.
1554 Label to_string, symbol_descriptive_string;
1555 {
1556 __ JumpIfSmi(eax, &to_string, Label::kNear);
1557 STATIC_ASSERT(FIRST_NONSTRING_TYPE == SYMBOL_TYPE);
1558 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
1559 __ j(above, &to_string, Label::kNear);
1560 __ j(equal, &symbol_descriptive_string, Label::kNear);
1561 __ Ret();
1562 }
1563
1564 // 2b. No arguments, return the empty string (and pop the receiver).
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001565 __ bind(&no_arguments);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001566 {
1567 __ LoadRoot(eax, Heap::kempty_stringRootIndex);
1568 __ ret(1 * kPointerSize);
1569 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001570
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001571 // 3a. Convert eax to a string.
1572 __ bind(&to_string);
1573 {
1574 ToStringStub stub(masm->isolate());
1575 __ TailCallStub(&stub);
1576 }
1577
1578 // 3b. Convert symbol in eax to a string.
1579 __ bind(&symbol_descriptive_string);
1580 {
1581 __ PopReturnAddressTo(ecx);
1582 __ Push(eax);
1583 __ PushReturnAddressFrom(ecx);
1584 __ TailCallRuntime(Runtime::kSymbolDescriptiveString);
1585 }
1586}
1587
1588
1589// static
1590void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
1591 // ----------- S t a t e -------------
1592 // -- eax : number of arguments
1593 // -- edi : constructor function
1594 // -- edx : new target
1595 // -- esp[0] : return address
1596 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1597 // -- esp[(argc + 1) * 4] : receiver
1598 // -----------------------------------
1599
1600 // 1. Make sure we operate in the context of the called function.
1601 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1602
1603 // 2. Load the first argument into ebx and get rid of the rest (including the
1604 // receiver).
1605 {
1606 Label no_arguments, done;
1607 __ test(eax, eax);
1608 __ j(zero, &no_arguments, Label::kNear);
1609 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1610 __ jmp(&done, Label::kNear);
1611 __ bind(&no_arguments);
1612 __ LoadRoot(ebx, Heap::kempty_stringRootIndex);
1613 __ bind(&done);
1614 __ PopReturnAddressTo(ecx);
1615 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1616 __ PushReturnAddressFrom(ecx);
1617 }
1618
1619 // 3. Make sure ebx is a string.
1620 {
1621 Label convert, done_convert;
1622 __ JumpIfSmi(ebx, &convert, Label::kNear);
1623 __ CmpObjectType(ebx, FIRST_NONSTRING_TYPE, ecx);
1624 __ j(below, &done_convert);
1625 __ bind(&convert);
1626 {
1627 FrameScope scope(masm, StackFrame::INTERNAL);
1628 ToStringStub stub(masm->isolate());
1629 __ Push(edi);
1630 __ Push(edx);
1631 __ Move(eax, ebx);
1632 __ CallStub(&stub);
1633 __ Move(ebx, eax);
1634 __ Pop(edx);
1635 __ Pop(edi);
1636 }
1637 __ bind(&done_convert);
1638 }
1639
1640 // 4. Check if new target and constructor differ.
1641 Label new_object;
1642 __ cmp(edx, edi);
1643 __ j(not_equal, &new_object);
1644
1645 // 5. Allocate a JSValue wrapper for the string.
1646 __ AllocateJSValue(eax, edi, ebx, ecx, &new_object);
1647 __ Ret();
1648
1649 // 6. Fallback to the runtime to create new object.
1650 __ bind(&new_object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001651 {
1652 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001653 __ Push(ebx); // the first argument
Ben Murdoch097c5b22016-05-18 11:27:45 +01001654 FastNewObjectStub stub(masm->isolate());
1655 __ CallStub(&stub);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001656 __ Pop(FieldOperand(eax, JSValue::kValueOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001657 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001658 __ Ret();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001659}
1660
1661
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001662static void ArgumentsAdaptorStackCheck(MacroAssembler* masm,
1663 Label* stack_overflow) {
1664 // ----------- S t a t e -------------
1665 // -- eax : actual number of arguments
1666 // -- ebx : expected number of arguments
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001667 // -- edx : new target (passed through to callee)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001668 // -----------------------------------
1669 // Check the stack for overflow. We are not trying to catch
1670 // interruptions (e.g. debug break and preemption) here, so the "real stack
1671 // limit" is checked.
1672 ExternalReference real_stack_limit =
1673 ExternalReference::address_of_real_stack_limit(masm->isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001674 __ mov(edi, Operand::StaticVariable(real_stack_limit));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001675 // Make ecx the space we have left. The stack might already be overflowed
1676 // here which will cause ecx to become negative.
1677 __ mov(ecx, esp);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001678 __ sub(ecx, edi);
1679 // Make edi the space we need for the array when it is unrolled onto the
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001680 // stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001681 __ mov(edi, ebx);
1682 __ shl(edi, kPointerSizeLog2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001683 // Check if the arguments will overflow the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001684 __ cmp(ecx, edi);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001685 __ j(less_equal, stack_overflow); // Signed comparison.
1686}
1687
1688
Steve Blocka7e24c12009-10-30 11:49:00 +00001689static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1690 __ push(ebp);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001691 __ mov(ebp, esp);
Steve Blocka7e24c12009-10-30 11:49:00 +00001692
1693 // Store the arguments adaptor context sentinel.
1694 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
1695
1696 // Push the function on the stack.
1697 __ push(edi);
1698
Ben Murdoch257744e2011-11-30 15:57:28 +00001699 // Preserve the number of arguments on the stack. Must preserve eax,
1700 // ebx and ecx because these registers are used when copying the
Steve Blocka7e24c12009-10-30 11:49:00 +00001701 // arguments and the receiver.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001702 STATIC_ASSERT(kSmiTagSize == 1);
Ben Murdoch257744e2011-11-30 15:57:28 +00001703 __ lea(edi, Operand(eax, eax, times_1, kSmiTag));
1704 __ push(edi);
Steve Blocka7e24c12009-10-30 11:49:00 +00001705}
1706
1707
1708static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1709 // Retrieve the number of arguments from the stack.
1710 __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1711
1712 // Leave the frame.
1713 __ leave();
1714
1715 // Remove caller arguments from the stack.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001716 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001717 __ pop(ecx);
1718 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
1719 __ push(ecx);
1720}
1721
1722
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001723// static
1724void Builtins::Generate_Apply(MacroAssembler* masm) {
1725 // ----------- S t a t e -------------
1726 // -- eax : argumentsList
1727 // -- edi : target
1728 // -- edx : new.target (checked to be constructor or undefined)
1729 // -- esp[0] : return address.
1730 // -- esp[4] : thisArgument
1731 // -----------------------------------
1732
1733 // Create the list of arguments from the array-like argumentsList.
1734 {
1735 Label create_arguments, create_array, create_runtime, done_create;
1736 __ JumpIfSmi(eax, &create_runtime);
1737
1738 // Load the map of argumentsList into ecx.
1739 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
1740
1741 // Load native context into ebx.
1742 __ mov(ebx, NativeContextOperand());
1743
1744 // Check if argumentsList is an (unmodified) arguments object.
1745 __ cmp(ecx, ContextOperand(ebx, Context::SLOPPY_ARGUMENTS_MAP_INDEX));
1746 __ j(equal, &create_arguments);
1747 __ cmp(ecx, ContextOperand(ebx, Context::STRICT_ARGUMENTS_MAP_INDEX));
1748 __ j(equal, &create_arguments);
1749
1750 // Check if argumentsList is a fast JSArray.
1751 __ CmpInstanceType(ecx, JS_ARRAY_TYPE);
1752 __ j(equal, &create_array);
1753
1754 // Ask the runtime to create the list (actually a FixedArray).
1755 __ bind(&create_runtime);
1756 {
1757 FrameScope scope(masm, StackFrame::INTERNAL);
1758 __ Push(edi);
1759 __ Push(edx);
1760 __ Push(eax);
1761 __ CallRuntime(Runtime::kCreateListFromArrayLike);
1762 __ Pop(edx);
1763 __ Pop(edi);
1764 __ mov(ebx, FieldOperand(eax, FixedArray::kLengthOffset));
1765 __ SmiUntag(ebx);
1766 }
1767 __ jmp(&done_create);
1768
1769 // Try to create the list from an arguments object.
1770 __ bind(&create_arguments);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001771 __ mov(ebx, FieldOperand(eax, JSArgumentsObject::kLengthOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001772 __ mov(ecx, FieldOperand(eax, JSObject::kElementsOffset));
1773 __ cmp(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
1774 __ j(not_equal, &create_runtime);
1775 __ SmiUntag(ebx);
1776 __ mov(eax, ecx);
1777 __ jmp(&done_create);
1778
1779 // Try to create the list from a JSArray object.
1780 __ bind(&create_array);
1781 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
1782 __ DecodeField<Map::ElementsKindBits>(ecx);
1783 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
1784 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
1785 STATIC_ASSERT(FAST_ELEMENTS == 2);
1786 __ cmp(ecx, Immediate(FAST_ELEMENTS));
1787 __ j(above, &create_runtime);
1788 __ cmp(ecx, Immediate(FAST_HOLEY_SMI_ELEMENTS));
1789 __ j(equal, &create_runtime);
1790 __ mov(ebx, FieldOperand(eax, JSArray::kLengthOffset));
1791 __ SmiUntag(ebx);
1792 __ mov(eax, FieldOperand(eax, JSArray::kElementsOffset));
1793
1794 __ bind(&done_create);
1795 }
1796
1797 // Check for stack overflow.
1798 {
1799 // Check the stack for overflow. We are not trying to catch interruptions
1800 // (i.e. debug break and preemption) here, so check the "real stack limit".
1801 Label done;
1802 ExternalReference real_stack_limit =
1803 ExternalReference::address_of_real_stack_limit(masm->isolate());
1804 __ mov(ecx, Operand::StaticVariable(real_stack_limit));
1805 // Make ecx the space we have left. The stack might already be overflowed
1806 // here which will cause ecx to become negative.
1807 __ neg(ecx);
1808 __ add(ecx, esp);
1809 __ sar(ecx, kPointerSizeLog2);
1810 // Check if the arguments will overflow the stack.
1811 __ cmp(ecx, ebx);
1812 __ j(greater, &done, Label::kNear); // Signed comparison.
1813 __ TailCallRuntime(Runtime::kThrowStackOverflow);
1814 __ bind(&done);
1815 }
1816
1817 // ----------- S t a t e -------------
1818 // -- edi : target
1819 // -- eax : args (a FixedArray built from argumentsList)
1820 // -- ebx : len (number of elements to push from args)
1821 // -- edx : new.target (checked to be constructor or undefined)
1822 // -- esp[0] : return address.
1823 // -- esp[4] : thisArgument
1824 // -----------------------------------
1825
1826 // Push arguments onto the stack (thisArgument is already on the stack).
1827 {
1828 __ movd(xmm0, edx);
1829 __ PopReturnAddressTo(edx);
1830 __ Move(ecx, Immediate(0));
1831 Label done, loop;
1832 __ bind(&loop);
1833 __ cmp(ecx, ebx);
1834 __ j(equal, &done, Label::kNear);
1835 __ Push(
1836 FieldOperand(eax, ecx, times_pointer_size, FixedArray::kHeaderSize));
1837 __ inc(ecx);
1838 __ jmp(&loop);
1839 __ bind(&done);
1840 __ PushReturnAddressFrom(edx);
1841 __ movd(edx, xmm0);
1842 __ Move(eax, ebx);
1843 }
1844
1845 // Dispatch to Call or Construct depending on whether new.target is undefined.
1846 {
1847 __ CompareRoot(edx, Heap::kUndefinedValueRootIndex);
1848 __ j(equal, masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1849 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
1850 }
1851}
1852
Ben Murdoch097c5b22016-05-18 11:27:45 +01001853namespace {
1854
1855// Drops top JavaScript frame and an arguments adaptor frame below it (if
1856// present) preserving all the arguments prepared for current call.
1857// Does nothing if debugger is currently active.
1858// ES6 14.6.3. PrepareForTailCall
1859//
1860// Stack structure for the function g() tail calling f():
1861//
1862// ------- Caller frame: -------
1863// | ...
1864// | g()'s arg M
1865// | ...
1866// | g()'s arg 1
1867// | g()'s receiver arg
1868// | g()'s caller pc
1869// ------- g()'s frame: -------
1870// | g()'s caller fp <- fp
1871// | g()'s context
1872// | function pointer: g
1873// | -------------------------
1874// | ...
1875// | ...
1876// | f()'s arg N
1877// | ...
1878// | f()'s arg 1
1879// | f()'s receiver arg
1880// | f()'s caller pc <- sp
1881// ----------------------
1882//
1883void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
1884 Register scratch1, Register scratch2,
1885 Register scratch3) {
1886 DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
1887 Comment cmnt(masm, "[ PrepareForTailCall");
1888
Ben Murdochda12d292016-06-02 14:46:10 +01001889 // Prepare for tail call only if ES2015 tail call elimination is enabled.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001890 Label done;
Ben Murdochda12d292016-06-02 14:46:10 +01001891 ExternalReference is_tail_call_elimination_enabled =
1892 ExternalReference::is_tail_call_elimination_enabled_address(
1893 masm->isolate());
1894 __ movzx_b(scratch1,
1895 Operand::StaticVariable(is_tail_call_elimination_enabled));
Ben Murdoch097c5b22016-05-18 11:27:45 +01001896 __ cmp(scratch1, Immediate(0));
Ben Murdochda12d292016-06-02 14:46:10 +01001897 __ j(equal, &done, Label::kNear);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001898
1899 // Drop possible interpreter handler/stub frame.
1900 {
1901 Label no_interpreter_frame;
Ben Murdochda12d292016-06-02 14:46:10 +01001902 __ cmp(Operand(ebp, CommonFrameConstants::kContextOrFrameTypeOffset),
Ben Murdoch097c5b22016-05-18 11:27:45 +01001903 Immediate(Smi::FromInt(StackFrame::STUB)));
1904 __ j(not_equal, &no_interpreter_frame, Label::kNear);
1905 __ mov(ebp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
1906 __ bind(&no_interpreter_frame);
1907 }
1908
1909 // Check if next frame is an arguments adaptor frame.
Ben Murdochda12d292016-06-02 14:46:10 +01001910 Register caller_args_count_reg = scratch1;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001911 Label no_arguments_adaptor, formal_parameter_count_loaded;
1912 __ mov(scratch2, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
Ben Murdochda12d292016-06-02 14:46:10 +01001913 __ cmp(Operand(scratch2, CommonFrameConstants::kContextOrFrameTypeOffset),
Ben Murdoch097c5b22016-05-18 11:27:45 +01001914 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
1915 __ j(not_equal, &no_arguments_adaptor, Label::kNear);
1916
Ben Murdochda12d292016-06-02 14:46:10 +01001917 // Drop current frame and load arguments count from arguments adaptor frame.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001918 __ mov(ebp, scratch2);
Ben Murdochda12d292016-06-02 14:46:10 +01001919 __ mov(caller_args_count_reg,
1920 Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1921 __ SmiUntag(caller_args_count_reg);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001922 __ jmp(&formal_parameter_count_loaded, Label::kNear);
1923
1924 __ bind(&no_arguments_adaptor);
1925 // Load caller's formal parameter count
1926 __ mov(scratch1, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1927 __ mov(scratch1,
1928 FieldOperand(scratch1, JSFunction::kSharedFunctionInfoOffset));
1929 __ mov(
Ben Murdochda12d292016-06-02 14:46:10 +01001930 caller_args_count_reg,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001931 FieldOperand(scratch1, SharedFunctionInfo::kFormalParameterCountOffset));
Ben Murdochda12d292016-06-02 14:46:10 +01001932 __ SmiUntag(caller_args_count_reg);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001933
1934 __ bind(&formal_parameter_count_loaded);
1935
Ben Murdochda12d292016-06-02 14:46:10 +01001936 ParameterCount callee_args_count(args_reg);
1937 __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
1938 scratch3, ReturnAddressState::kOnStack, 0);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001939 __ bind(&done);
1940}
1941} // namespace
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001942
1943// static
1944void Builtins::Generate_CallFunction(MacroAssembler* masm,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001945 ConvertReceiverMode mode,
1946 TailCallMode tail_call_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001947 // ----------- S t a t e -------------
1948 // -- eax : the number of arguments (not including the receiver)
1949 // -- edi : the function to call (checked to be a JSFunction)
1950 // -----------------------------------
1951 __ AssertFunction(edi);
1952
1953 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
1954 // Check that the function is not a "classConstructor".
1955 Label class_constructor;
1956 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1957 __ test_b(FieldOperand(edx, SharedFunctionInfo::kFunctionKindByteOffset),
Ben Murdochda12d292016-06-02 14:46:10 +01001958 Immediate(SharedFunctionInfo::kClassConstructorBitsWithinByte));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001959 __ j(not_zero, &class_constructor);
1960
1961 // Enter the context of the function; ToObject has to run in the function
1962 // context, and we also need to take the global proxy from the function
1963 // context in case of conversion.
1964 STATIC_ASSERT(SharedFunctionInfo::kNativeByteOffset ==
1965 SharedFunctionInfo::kStrictModeByteOffset);
1966 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1967 // We need to convert the receiver for non-native sloppy mode functions.
1968 Label done_convert;
1969 __ test_b(FieldOperand(edx, SharedFunctionInfo::kNativeByteOffset),
Ben Murdochda12d292016-06-02 14:46:10 +01001970 Immediate((1 << SharedFunctionInfo::kNativeBitWithinByte) |
1971 (1 << SharedFunctionInfo::kStrictModeBitWithinByte)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001972 __ j(not_zero, &done_convert);
1973 {
1974 // ----------- S t a t e -------------
1975 // -- eax : the number of arguments (not including the receiver)
1976 // -- edx : the shared function info.
1977 // -- edi : the function to call (checked to be a JSFunction)
1978 // -- esi : the function context.
1979 // -----------------------------------
1980
1981 if (mode == ConvertReceiverMode::kNullOrUndefined) {
1982 // Patch receiver to global proxy.
1983 __ LoadGlobalProxy(ecx);
1984 } else {
1985 Label convert_to_object, convert_receiver;
1986 __ mov(ecx, Operand(esp, eax, times_pointer_size, kPointerSize));
1987 __ JumpIfSmi(ecx, &convert_to_object, Label::kNear);
1988 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
1989 __ CmpObjectType(ecx, FIRST_JS_RECEIVER_TYPE, ebx);
1990 __ j(above_equal, &done_convert);
1991 if (mode != ConvertReceiverMode::kNotNullOrUndefined) {
1992 Label convert_global_proxy;
1993 __ JumpIfRoot(ecx, Heap::kUndefinedValueRootIndex,
1994 &convert_global_proxy, Label::kNear);
1995 __ JumpIfNotRoot(ecx, Heap::kNullValueRootIndex, &convert_to_object,
1996 Label::kNear);
1997 __ bind(&convert_global_proxy);
1998 {
1999 // Patch receiver to global proxy.
2000 __ LoadGlobalProxy(ecx);
2001 }
2002 __ jmp(&convert_receiver);
2003 }
2004 __ bind(&convert_to_object);
2005 {
2006 // Convert receiver using ToObject.
2007 // TODO(bmeurer): Inline the allocation here to avoid building the frame
2008 // in the fast case? (fall back to AllocateInNewSpace?)
2009 FrameScope scope(masm, StackFrame::INTERNAL);
2010 __ SmiTag(eax);
2011 __ Push(eax);
2012 __ Push(edi);
2013 __ mov(eax, ecx);
2014 ToObjectStub stub(masm->isolate());
2015 __ CallStub(&stub);
2016 __ mov(ecx, eax);
2017 __ Pop(edi);
2018 __ Pop(eax);
2019 __ SmiUntag(eax);
2020 }
2021 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2022 __ bind(&convert_receiver);
2023 }
2024 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ecx);
2025 }
2026 __ bind(&done_convert);
2027
2028 // ----------- S t a t e -------------
2029 // -- eax : the number of arguments (not including the receiver)
2030 // -- edx : the shared function info.
2031 // -- edi : the function to call (checked to be a JSFunction)
2032 // -- esi : the function context.
2033 // -----------------------------------
2034
Ben Murdoch097c5b22016-05-18 11:27:45 +01002035 if (tail_call_mode == TailCallMode::kAllow) {
2036 PrepareForTailCall(masm, eax, ebx, ecx, edx);
2037 // Reload shared function info.
2038 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2039 }
2040
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002041 __ mov(ebx,
2042 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
2043 __ SmiUntag(ebx);
2044 ParameterCount actual(eax);
2045 ParameterCount expected(ebx);
2046 __ InvokeFunctionCode(edi, no_reg, expected, actual, JUMP_FUNCTION,
2047 CheckDebugStepCallWrapper());
2048 // The function is a "classConstructor", need to raise an exception.
2049 __ bind(&class_constructor);
2050 {
2051 FrameScope frame(masm, StackFrame::INTERNAL);
2052 __ push(edi);
2053 __ CallRuntime(Runtime::kThrowConstructorNonCallableError);
2054 }
2055}
2056
2057
2058namespace {
2059
2060void Generate_PushBoundArguments(MacroAssembler* masm) {
2061 // ----------- S t a t e -------------
2062 // -- eax : the number of arguments (not including the receiver)
2063 // -- edx : new.target (only in case of [[Construct]])
2064 // -- edi : target (checked to be a JSBoundFunction)
2065 // -----------------------------------
2066
2067 // Load [[BoundArguments]] into ecx and length of that into ebx.
2068 Label no_bound_arguments;
2069 __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset));
2070 __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
2071 __ SmiUntag(ebx);
2072 __ test(ebx, ebx);
2073 __ j(zero, &no_bound_arguments);
2074 {
2075 // ----------- S t a t e -------------
2076 // -- eax : the number of arguments (not including the receiver)
2077 // -- edx : new.target (only in case of [[Construct]])
2078 // -- edi : target (checked to be a JSBoundFunction)
2079 // -- ecx : the [[BoundArguments]] (implemented as FixedArray)
2080 // -- ebx : the number of [[BoundArguments]]
2081 // -----------------------------------
2082
2083 // Reserve stack space for the [[BoundArguments]].
2084 {
2085 Label done;
2086 __ lea(ecx, Operand(ebx, times_pointer_size, 0));
2087 __ sub(esp, ecx);
2088 // Check the stack for overflow. We are not trying to catch interruptions
2089 // (i.e. debug break and preemption) here, so check the "real stack
2090 // limit".
2091 __ CompareRoot(esp, ecx, Heap::kRealStackLimitRootIndex);
2092 __ j(greater, &done, Label::kNear); // Signed comparison.
2093 // Restore the stack pointer.
2094 __ lea(esp, Operand(esp, ebx, times_pointer_size, 0));
2095 {
2096 FrameScope scope(masm, StackFrame::MANUAL);
2097 __ EnterFrame(StackFrame::INTERNAL);
2098 __ CallRuntime(Runtime::kThrowStackOverflow);
2099 }
2100 __ bind(&done);
2101 }
2102
2103 // Adjust effective number of arguments to include return address.
2104 __ inc(eax);
2105
2106 // Relocate arguments and return address down the stack.
2107 {
2108 Label loop;
2109 __ Set(ecx, 0);
2110 __ lea(ebx, Operand(esp, ebx, times_pointer_size, 0));
2111 __ bind(&loop);
2112 __ movd(xmm0, Operand(ebx, ecx, times_pointer_size, 0));
2113 __ movd(Operand(esp, ecx, times_pointer_size, 0), xmm0);
2114 __ inc(ecx);
2115 __ cmp(ecx, eax);
2116 __ j(less, &loop);
2117 }
2118
2119 // Copy [[BoundArguments]] to the stack (below the arguments).
2120 {
2121 Label loop;
2122 __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset));
2123 __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
2124 __ SmiUntag(ebx);
2125 __ bind(&loop);
2126 __ dec(ebx);
2127 __ movd(xmm0, FieldOperand(ecx, ebx, times_pointer_size,
2128 FixedArray::kHeaderSize));
2129 __ movd(Operand(esp, eax, times_pointer_size, 0), xmm0);
2130 __ lea(eax, Operand(eax, 1));
2131 __ j(greater, &loop);
2132 }
2133
2134 // Adjust effective number of arguments (eax contains the number of
2135 // arguments from the call plus return address plus the number of
2136 // [[BoundArguments]]), so we need to subtract one for the return address.
2137 __ dec(eax);
2138 }
2139 __ bind(&no_bound_arguments);
2140}
2141
2142} // namespace
2143
2144
2145// static
Ben Murdoch097c5b22016-05-18 11:27:45 +01002146void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm,
2147 TailCallMode tail_call_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002148 // ----------- S t a t e -------------
2149 // -- eax : the number of arguments (not including the receiver)
2150 // -- edi : the function to call (checked to be a JSBoundFunction)
2151 // -----------------------------------
2152 __ AssertBoundFunction(edi);
2153
Ben Murdoch097c5b22016-05-18 11:27:45 +01002154 if (tail_call_mode == TailCallMode::kAllow) {
2155 PrepareForTailCall(masm, eax, ebx, ecx, edx);
2156 }
2157
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002158 // Patch the receiver to [[BoundThis]].
2159 __ mov(ebx, FieldOperand(edi, JSBoundFunction::kBoundThisOffset));
2160 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ebx);
2161
2162 // Push the [[BoundArguments]] onto the stack.
2163 Generate_PushBoundArguments(masm);
2164
2165 // Call the [[BoundTargetFunction]] via the Call builtin.
2166 __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2167 __ mov(ecx, Operand::StaticVariable(ExternalReference(
2168 Builtins::kCall_ReceiverIsAny, masm->isolate())));
2169 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2170 __ jmp(ecx);
2171}
2172
2173
2174// static
Ben Murdoch097c5b22016-05-18 11:27:45 +01002175void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
2176 TailCallMode tail_call_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002177 // ----------- S t a t e -------------
2178 // -- eax : the number of arguments (not including the receiver)
2179 // -- edi : the target to call (can be any Object).
2180 // -----------------------------------
2181
2182 Label non_callable, non_function, non_smi;
2183 __ JumpIfSmi(edi, &non_callable);
2184 __ bind(&non_smi);
2185 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002186 __ j(equal, masm->isolate()->builtins()->CallFunction(mode, tail_call_mode),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002187 RelocInfo::CODE_TARGET);
2188 __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002189 __ j(equal, masm->isolate()->builtins()->CallBoundFunction(tail_call_mode),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002190 RelocInfo::CODE_TARGET);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002191
2192 // Check if target has a [[Call]] internal method.
Ben Murdochda12d292016-06-02 14:46:10 +01002193 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
2194 Immediate(1 << Map::kIsCallable));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002195 __ j(zero, &non_callable);
2196
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002197 __ CmpInstanceType(ecx, JS_PROXY_TYPE);
2198 __ j(not_equal, &non_function);
2199
Ben Murdoch097c5b22016-05-18 11:27:45 +01002200 // 0. Prepare for tail call if necessary.
2201 if (tail_call_mode == TailCallMode::kAllow) {
2202 PrepareForTailCall(masm, eax, ebx, ecx, edx);
2203 }
2204
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002205 // 1. Runtime fallback for Proxy [[Call]].
2206 __ PopReturnAddressTo(ecx);
2207 __ Push(edi);
2208 __ PushReturnAddressFrom(ecx);
2209 // Increase the arguments size to include the pushed function and the
2210 // existing receiver on the stack.
2211 __ add(eax, Immediate(2));
2212 // Tail-call to the runtime.
2213 __ JumpToExternalReference(
2214 ExternalReference(Runtime::kJSProxyCall, masm->isolate()));
2215
2216 // 2. Call to something else, which might have a [[Call]] internal method (if
2217 // not we raise an exception).
2218 __ bind(&non_function);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002219 // Overwrite the original receiver with the (original) target.
2220 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
2221 // Let the "call_as_function_delegate" take care of the rest.
2222 __ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, edi);
2223 __ Jump(masm->isolate()->builtins()->CallFunction(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002224 ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002225 RelocInfo::CODE_TARGET);
2226
2227 // 3. Call to something that is not callable.
2228 __ bind(&non_callable);
2229 {
2230 FrameScope scope(masm, StackFrame::INTERNAL);
2231 __ Push(edi);
2232 __ CallRuntime(Runtime::kThrowCalledNonCallable);
2233 }
2234}
2235
2236
2237// static
2238void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
2239 // ----------- S t a t e -------------
2240 // -- eax : the number of arguments (not including the receiver)
2241 // -- edx : the new target (checked to be a constructor)
2242 // -- edi : the constructor to call (checked to be a JSFunction)
2243 // -----------------------------------
2244 __ AssertFunction(edi);
2245
2246 // Calling convention for function specific ConstructStubs require
2247 // ebx to contain either an AllocationSite or undefined.
2248 __ LoadRoot(ebx, Heap::kUndefinedValueRootIndex);
2249
2250 // Tail call to the function-specific construct stub (still in the caller
2251 // context at this point).
2252 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2253 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset));
2254 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2255 __ jmp(ecx);
2256}
2257
2258
2259// static
2260void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) {
2261 // ----------- S t a t e -------------
2262 // -- eax : the number of arguments (not including the receiver)
2263 // -- edx : the new target (checked to be a constructor)
2264 // -- edi : the constructor to call (checked to be a JSBoundFunction)
2265 // -----------------------------------
2266 __ AssertBoundFunction(edi);
2267
2268 // Push the [[BoundArguments]] onto the stack.
2269 Generate_PushBoundArguments(masm);
2270
2271 // Patch new.target to [[BoundTargetFunction]] if new.target equals target.
2272 {
2273 Label done;
2274 __ cmp(edi, edx);
2275 __ j(not_equal, &done, Label::kNear);
2276 __ mov(edx, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2277 __ bind(&done);
2278 }
2279
2280 // Construct the [[BoundTargetFunction]] via the Construct builtin.
2281 __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2282 __ mov(ecx, Operand::StaticVariable(
2283 ExternalReference(Builtins::kConstruct, masm->isolate())));
2284 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2285 __ jmp(ecx);
2286}
2287
2288
2289// static
2290void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
2291 // ----------- S t a t e -------------
2292 // -- eax : the number of arguments (not including the receiver)
2293 // -- edi : the constructor to call (checked to be a JSProxy)
2294 // -- edx : the new target (either the same as the constructor or
2295 // the JSFunction on which new was invoked initially)
2296 // -----------------------------------
2297
2298 // Call into the Runtime for Proxy [[Construct]].
2299 __ PopReturnAddressTo(ecx);
2300 __ Push(edi);
2301 __ Push(edx);
2302 __ PushReturnAddressFrom(ecx);
2303 // Include the pushed new_target, constructor and the receiver.
2304 __ add(eax, Immediate(3));
2305 // Tail-call to the runtime.
2306 __ JumpToExternalReference(
2307 ExternalReference(Runtime::kJSProxyConstruct, masm->isolate()));
2308}
2309
2310
2311// static
2312void Builtins::Generate_Construct(MacroAssembler* masm) {
2313 // ----------- S t a t e -------------
2314 // -- eax : the number of arguments (not including the receiver)
2315 // -- edx : the new target (either the same as the constructor or
2316 // the JSFunction on which new was invoked initially)
2317 // -- edi : the constructor to call (can be any Object)
2318 // -----------------------------------
2319
2320 // Check if target is a Smi.
2321 Label non_constructor;
2322 __ JumpIfSmi(edi, &non_constructor, Label::kNear);
2323
2324 // Dispatch based on instance type.
2325 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
2326 __ j(equal, masm->isolate()->builtins()->ConstructFunction(),
2327 RelocInfo::CODE_TARGET);
2328
2329 // Check if target has a [[Construct]] internal method.
Ben Murdochda12d292016-06-02 14:46:10 +01002330 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
2331 Immediate(1 << Map::kIsConstructor));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002332 __ j(zero, &non_constructor, Label::kNear);
2333
2334 // Only dispatch to bound functions after checking whether they are
2335 // constructors.
2336 __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE);
2337 __ j(equal, masm->isolate()->builtins()->ConstructBoundFunction(),
2338 RelocInfo::CODE_TARGET);
2339
2340 // Only dispatch to proxies after checking whether they are constructors.
2341 __ CmpInstanceType(ecx, JS_PROXY_TYPE);
2342 __ j(equal, masm->isolate()->builtins()->ConstructProxy(),
2343 RelocInfo::CODE_TARGET);
2344
2345 // Called Construct on an exotic Object with a [[Construct]] internal method.
2346 {
2347 // Overwrite the original receiver with the (original) target.
2348 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
2349 // Let the "call_as_constructor_delegate" take care of the rest.
2350 __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, edi);
2351 __ Jump(masm->isolate()->builtins()->CallFunction(),
2352 RelocInfo::CODE_TARGET);
2353 }
2354
2355 // Called Construct on an Object that doesn't have a [[Construct]] internal
2356 // method.
2357 __ bind(&non_constructor);
2358 __ Jump(masm->isolate()->builtins()->ConstructedNonConstructable(),
2359 RelocInfo::CODE_TARGET);
2360}
2361
2362
Steve Blocka7e24c12009-10-30 11:49:00 +00002363void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
2364 // ----------- S t a t e -------------
2365 // -- eax : actual number of arguments
2366 // -- ebx : expected number of arguments
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002367 // -- edx : new target (passed through to callee)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002368 // -- edi : function (passed through to callee)
Steve Blocka7e24c12009-10-30 11:49:00 +00002369 // -----------------------------------
2370
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002371 Label invoke, dont_adapt_arguments, stack_overflow;
Steve Block44f0eee2011-05-26 01:26:41 +01002372 __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00002373
2374 Label enough, too_few;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002375 __ cmp(eax, ebx);
Steve Blocka7e24c12009-10-30 11:49:00 +00002376 __ j(less, &too_few);
2377 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
2378 __ j(equal, &dont_adapt_arguments);
2379
2380 { // Enough parameters: Actual >= expected.
2381 __ bind(&enough);
2382 EnterArgumentsAdaptorFrame(masm);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002383 ArgumentsAdaptorStackCheck(masm, &stack_overflow);
Steve Blocka7e24c12009-10-30 11:49:00 +00002384
2385 // Copy receiver and all expected arguments.
2386 const int offset = StandardFrameConstants::kCallerSPOffset;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002387 __ lea(edi, Operand(ebp, eax, times_4, offset));
2388 __ mov(eax, -1); // account for receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002389
2390 Label copy;
2391 __ bind(&copy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002392 __ inc(eax);
2393 __ push(Operand(edi, 0));
2394 __ sub(edi, Immediate(kPointerSize));
2395 __ cmp(eax, ebx);
Steve Blocka7e24c12009-10-30 11:49:00 +00002396 __ j(less, &copy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002397 // eax now contains the expected number of arguments.
Steve Blocka7e24c12009-10-30 11:49:00 +00002398 __ jmp(&invoke);
2399 }
2400
2401 { // Too few parameters: Actual < expected.
2402 __ bind(&too_few);
2403 EnterArgumentsAdaptorFrame(masm);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002404 ArgumentsAdaptorStackCheck(masm, &stack_overflow);
2405
2406 // Remember expected arguments in ecx.
2407 __ mov(ecx, ebx);
Steve Blocka7e24c12009-10-30 11:49:00 +00002408
2409 // Copy receiver and all actual arguments.
2410 const int offset = StandardFrameConstants::kCallerSPOffset;
2411 __ lea(edi, Operand(ebp, eax, times_4, offset));
Ben Murdoch257744e2011-11-30 15:57:28 +00002412 // ebx = expected - actual.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002413 __ sub(ebx, eax);
Ben Murdoch257744e2011-11-30 15:57:28 +00002414 // eax = -actual - 1
2415 __ neg(eax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002416 __ sub(eax, Immediate(1));
Steve Blocka7e24c12009-10-30 11:49:00 +00002417
2418 Label copy;
2419 __ bind(&copy);
Ben Murdoch257744e2011-11-30 15:57:28 +00002420 __ inc(eax);
Steve Blocka7e24c12009-10-30 11:49:00 +00002421 __ push(Operand(edi, 0));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002422 __ sub(edi, Immediate(kPointerSize));
2423 __ test(eax, eax);
Ben Murdoch257744e2011-11-30 15:57:28 +00002424 __ j(not_zero, &copy);
Steve Blocka7e24c12009-10-30 11:49:00 +00002425
2426 // Fill remaining expected arguments with undefined values.
2427 Label fill;
2428 __ bind(&fill);
Ben Murdoch257744e2011-11-30 15:57:28 +00002429 __ inc(eax);
Steve Block44f0eee2011-05-26 01:26:41 +01002430 __ push(Immediate(masm->isolate()->factory()->undefined_value()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002431 __ cmp(eax, ebx);
Steve Blocka7e24c12009-10-30 11:49:00 +00002432 __ j(less, &fill);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002433
2434 // Restore expected arguments.
2435 __ mov(eax, ecx);
Steve Blocka7e24c12009-10-30 11:49:00 +00002436 }
2437
2438 // Call the entry point.
2439 __ bind(&invoke);
Ben Murdoch257744e2011-11-30 15:57:28 +00002440 // Restore function pointer.
Ben Murdochda12d292016-06-02 14:46:10 +01002441 __ mov(edi, Operand(ebp, ArgumentsAdaptorFrameConstants::kFunctionOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002442 // eax : expected number of arguments
2443 // edx : new target (passed through to callee)
2444 // edi : function (passed through to callee)
2445 __ mov(ecx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
2446 __ call(ecx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002447
2448 // Store offset of return address for deoptimizer.
2449 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01002450
Steve Blocka7e24c12009-10-30 11:49:00 +00002451 // Leave frame and return.
2452 LeaveArgumentsAdaptorFrame(masm);
2453 __ ret(0);
2454
2455 // -------------------------------------------
2456 // Dont adapt arguments.
2457 // -------------------------------------------
2458 __ bind(&dont_adapt_arguments);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002459 __ mov(ecx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
2460 __ jmp(ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002461
2462 __ bind(&stack_overflow);
2463 {
2464 FrameScope frame(masm, StackFrame::MANUAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002465 __ CallRuntime(Runtime::kThrowStackOverflow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002466 __ int3();
2467 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002468}
2469
2470
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002471static void CompatibleReceiverCheck(MacroAssembler* masm, Register receiver,
2472 Register function_template_info,
2473 Register scratch0, Register scratch1,
2474 Label* receiver_check_failed) {
2475 // If there is no signature, return the holder.
2476 __ CompareRoot(FieldOperand(function_template_info,
2477 FunctionTemplateInfo::kSignatureOffset),
2478 Heap::kUndefinedValueRootIndex);
2479 Label receiver_check_passed;
2480 __ j(equal, &receiver_check_passed, Label::kNear);
2481
2482 // Walk the prototype chain.
2483 __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
2484 Label prototype_loop_start;
2485 __ bind(&prototype_loop_start);
2486
2487 // Get the constructor, if any.
2488 __ GetMapConstructor(scratch0, scratch0, scratch1);
2489 __ CmpInstanceType(scratch1, JS_FUNCTION_TYPE);
2490 Label next_prototype;
2491 __ j(not_equal, &next_prototype, Label::kNear);
2492
2493 // Get the constructor's signature.
2494 __ mov(scratch0,
2495 FieldOperand(scratch0, JSFunction::kSharedFunctionInfoOffset));
2496 __ mov(scratch0,
2497 FieldOperand(scratch0, SharedFunctionInfo::kFunctionDataOffset));
2498
2499 // Loop through the chain of inheriting function templates.
2500 Label function_template_loop;
2501 __ bind(&function_template_loop);
2502
2503 // If the signatures match, we have a compatible receiver.
2504 __ cmp(scratch0, FieldOperand(function_template_info,
2505 FunctionTemplateInfo::kSignatureOffset));
2506 __ j(equal, &receiver_check_passed, Label::kNear);
2507
2508 // If the current type is not a FunctionTemplateInfo, load the next prototype
2509 // in the chain.
2510 __ JumpIfSmi(scratch0, &next_prototype, Label::kNear);
2511 __ CmpObjectType(scratch0, FUNCTION_TEMPLATE_INFO_TYPE, scratch1);
2512 __ j(not_equal, &next_prototype, Label::kNear);
2513
2514 // Otherwise load the parent function template and iterate.
2515 __ mov(scratch0,
2516 FieldOperand(scratch0, FunctionTemplateInfo::kParentTemplateOffset));
2517 __ jmp(&function_template_loop, Label::kNear);
2518
2519 // Load the next prototype.
2520 __ bind(&next_prototype);
2521 __ mov(receiver, FieldOperand(receiver, HeapObject::kMapOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002522 __ test(FieldOperand(receiver, Map::kBitField3Offset),
2523 Immediate(Map::HasHiddenPrototype::kMask));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002524 __ j(zero, receiver_check_failed);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002525
2526 __ mov(receiver, FieldOperand(receiver, Map::kPrototypeOffset));
2527 __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002528 // Iterate.
2529 __ jmp(&prototype_loop_start, Label::kNear);
2530
2531 __ bind(&receiver_check_passed);
2532}
2533
2534
2535void Builtins::Generate_HandleFastApiCall(MacroAssembler* masm) {
2536 // ----------- S t a t e -------------
2537 // -- eax : number of arguments (not including the receiver)
2538 // -- edi : callee
2539 // -- esi : context
2540 // -- esp[0] : return address
2541 // -- esp[4] : last argument
2542 // -- ...
2543 // -- esp[eax * 4] : first argument
2544 // -- esp[(eax + 1) * 4] : receiver
2545 // -----------------------------------
2546
2547 // Load the FunctionTemplateInfo.
2548 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2549 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kFunctionDataOffset));
2550
2551 // Do the compatible receiver check.
2552 Label receiver_check_failed;
2553 __ mov(ecx, Operand(esp, eax, times_pointer_size, kPCOnStackSize));
2554 __ Push(eax);
2555 CompatibleReceiverCheck(masm, ecx, ebx, edx, eax, &receiver_check_failed);
2556 __ Pop(eax);
2557 // Get the callback offset from the FunctionTemplateInfo, and jump to the
2558 // beginning of the code.
2559 __ mov(edx, FieldOperand(ebx, FunctionTemplateInfo::kCallCodeOffset));
2560 __ mov(edx, FieldOperand(edx, CallHandlerInfo::kFastHandlerOffset));
2561 __ add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag));
2562 __ jmp(edx);
2563
2564 // Compatible receiver check failed: pop return address, arguments and
2565 // receiver and throw an Illegal Invocation exception.
2566 __ bind(&receiver_check_failed);
2567 __ Pop(eax);
2568 __ PopReturnAddressTo(ebx);
2569 __ lea(eax, Operand(eax, times_pointer_size, 1 * kPointerSize));
2570 __ add(esp, eax);
2571 __ PushReturnAddressFrom(ebx);
2572 {
2573 FrameScope scope(masm, StackFrame::INTERNAL);
2574 __ TailCallRuntime(Runtime::kThrowIllegalInvocation);
2575 }
2576}
2577
2578
Ben Murdochb0fe1622011-05-05 13:52:32 +01002579void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002580 // Lookup the function in the JavaScript frame.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002581 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002582 {
2583 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002584 // Pass function as argument.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002585 __ push(eax);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002586 __ CallRuntime(Runtime::kCompileForOnStackReplacement);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002587 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01002588
Ben Murdoch257744e2011-11-30 15:57:28 +00002589 Label skip;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002590 // If the code object is null, just return to the unoptimized code.
2591 __ cmp(eax, Immediate(0));
Ben Murdoch257744e2011-11-30 15:57:28 +00002592 __ j(not_equal, &skip, Label::kNear);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002593 __ ret(0);
2594
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002595 __ bind(&skip);
2596
2597 // Load deoptimization data from the code object.
2598 __ mov(ebx, Operand(eax, Code::kDeoptimizationDataOffset - kHeapObjectTag));
2599
2600 // Load the OSR entrypoint offset from the deoptimization data.
2601 __ mov(ebx, Operand(ebx, FixedArray::OffsetOfElementAt(
2602 DeoptimizationInputData::kOsrPcOffsetIndex) - kHeapObjectTag));
2603 __ SmiUntag(ebx);
2604
2605 // Compute the target address = code_obj + header_size + osr_offset
2606 __ lea(eax, Operand(eax, ebx, times_1, Code::kHeaderSize - kHeapObjectTag));
2607
2608 // Overwrite the return address on the stack.
2609 __ mov(Operand(esp, 0), eax);
2610
2611 // And "return" to the OSR entry point of the function.
2612 __ ret(0);
2613}
2614
2615
Steve Blocka7e24c12009-10-30 11:49:00 +00002616#undef __
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002617} // namespace internal
2618} // namespace v8
Leon Clarkef7060e22010-06-03 12:02:55 +01002619
2620#endif // V8_TARGET_ARCH_IA32