blob: c48c74abad92f7246bc578c82f604a5c8dc60c17 [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
126 // -- edi: constructor function
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000127 // -- ebx: allocation site or undefined
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000128 // -- edx: new target
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100129 // -----------------------------------
130
Steve Blocka7e24c12009-10-30 11:49:00 +0000131 // Enter a construct frame.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100132 {
133 FrameScope scope(masm, StackFrame::CONSTRUCT);
Steve Blocka7e24c12009-10-30 11:49:00 +0000134
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000135 // Preserve the incoming parameters on the stack.
136 __ AssertUndefinedOrAllocationSite(ebx);
137 __ push(ebx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100138 __ SmiTag(eax);
139 __ push(eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000140
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000141 if (create_implicit_receiver) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100142 // Allocate the new receiver object.
143 __ Push(edi);
144 __ Push(edx);
145 FastNewObjectStub stub(masm->isolate());
146 __ CallStub(&stub);
147 __ mov(ebx, eax);
148 __ Pop(edx);
149 __ Pop(edi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000150
Ben Murdoch097c5b22016-05-18 11:27:45 +0100151 // ----------- S t a t e -------------
152 // -- edi: constructor function
153 // -- ebx: newly allocated object
154 // -- edx: new target
155 // -----------------------------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000156
157 // Retrieve smi-tagged arguments count from the stack.
158 __ mov(eax, Operand(esp, 0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000159 }
160
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100161 __ SmiUntag(eax);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000162
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000163 if (create_implicit_receiver) {
164 // Push the allocated receiver to the stack. We need two copies
165 // because we may have to return the original one and the calling
166 // conventions dictate that the called function pops the receiver.
167 __ push(ebx);
168 __ push(ebx);
169 } else {
170 __ PushRoot(Heap::kTheHoleValueRootIndex);
171 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100172
173 // Set up pointer to last argument.
174 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
175
176 // Copy arguments and receiver to the expression stack.
177 Label loop, entry;
178 __ mov(ecx, eax);
179 __ jmp(&entry);
180 __ bind(&loop);
181 __ push(Operand(ebx, ecx, times_4, 0));
182 __ bind(&entry);
183 __ dec(ecx);
184 __ j(greater_equal, &loop);
185
186 // Call the function.
187 if (is_api_function) {
188 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
189 Handle<Code> code =
190 masm->isolate()->builtins()->HandleApiCallConstruct();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000191 __ call(code, RelocInfo::CODE_TARGET);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100192 } else {
193 ParameterCount actual(eax);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000194 __ InvokeFunction(edi, edx, actual, CALL_FUNCTION,
195 CheckDebugStepCallWrapper());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100196 }
197
198 // Store offset of return address for deoptimizer.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000199 if (create_implicit_receiver && !is_api_function) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100200 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
201 }
202
203 // Restore context from the frame.
204 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
205
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000206 if (create_implicit_receiver) {
207 // If the result is an object (in the ECMA sense), we should get rid
Ben Murdoch097c5b22016-05-18 11:27:45 +0100208 // of the receiver and use the result.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000209 Label use_receiver, exit;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100210
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000211 // If the result is a smi, it is *not* an object in the ECMA sense.
212 __ JumpIfSmi(eax, &use_receiver);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100213
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000214 // If the type of the result (stored in its map) is less than
215 // FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense.
216 __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ecx);
217 __ j(above_equal, &exit);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100218
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000219 // Throw away the result of the constructor invocation and use the
220 // on-stack receiver as the result.
221 __ bind(&use_receiver);
222 __ mov(eax, Operand(esp, 0));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100223
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000224 // Restore the arguments count and leave the construct frame. The
225 // arguments count is stored below the receiver.
226 __ bind(&exit);
227 __ mov(ebx, Operand(esp, 1 * kPointerSize));
228 } else {
229 __ mov(ebx, Operand(esp, 0));
230 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100231
232 // Leave construct frame.
Steve Blocka7e24c12009-10-30 11:49:00 +0000233 }
234
Ben Murdoch097c5b22016-05-18 11:27:45 +0100235 // ES6 9.2.2. Step 13+
236 // Check that the result is not a Smi, indicating that the constructor result
237 // from a derived class is neither undefined nor an Object.
238 if (check_derived_construct) {
239 Label dont_throw;
240 __ JumpIfNotSmi(eax, &dont_throw);
241 {
242 FrameScope scope(masm, StackFrame::INTERNAL);
243 __ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject);
244 }
245 __ bind(&dont_throw);
246 }
247
Steve Blocka7e24c12009-10-30 11:49:00 +0000248 // Remove caller arguments from the stack and return.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000249 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000250 __ pop(ecx);
251 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
252 __ push(ecx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000253 if (create_implicit_receiver) {
254 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);
255 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000256 __ ret(0);
257}
258
259
Leon Clarkee46be812010-01-19 14:06:41 +0000260void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100261 Generate_JSConstructStubHelper(masm, false, true, false);
Leon Clarkee46be812010-01-19 14:06:41 +0000262}
263
264
265void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100266 Generate_JSConstructStubHelper(masm, true, false, false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000267}
268
269
270void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100271 Generate_JSConstructStubHelper(masm, false, false, false);
272}
273
274
275void Builtins::Generate_JSBuiltinsConstructStubForDerived(
276 MacroAssembler* masm) {
277 Generate_JSConstructStubHelper(masm, false, false, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000278}
279
280
281void Builtins::Generate_ConstructedNonConstructable(MacroAssembler* masm) {
282 FrameScope scope(masm, StackFrame::INTERNAL);
283 __ push(edi);
284 __ CallRuntime(Runtime::kThrowConstructedNonConstructable);
285}
286
287
288enum IsTagged { kEaxIsSmiTagged, kEaxIsUntaggedInt };
289
290
291// Clobbers ecx, edx, edi; preserves all other registers.
292static void Generate_CheckStackOverflow(MacroAssembler* masm,
293 IsTagged eax_is_tagged) {
294 // eax : the number of items to be pushed to the stack
295 //
296 // Check the stack for overflow. We are not trying to catch
297 // interruptions (e.g. debug break and preemption) here, so the "real stack
298 // limit" is checked.
299 Label okay;
300 ExternalReference real_stack_limit =
301 ExternalReference::address_of_real_stack_limit(masm->isolate());
302 __ mov(edi, Operand::StaticVariable(real_stack_limit));
303 // Make ecx the space we have left. The stack might already be overflowed
304 // here which will cause ecx to become negative.
305 __ mov(ecx, esp);
306 __ sub(ecx, edi);
307 // Make edx the space we need for the array when it is unrolled onto the
308 // stack.
309 __ mov(edx, eax);
310 int smi_tag = eax_is_tagged == kEaxIsSmiTagged ? kSmiTagSize : 0;
311 __ shl(edx, kPointerSizeLog2 - smi_tag);
312 // Check if the arguments will overflow the stack.
313 __ cmp(ecx, edx);
314 __ j(greater, &okay); // Signed comparison.
315
316 // Out of stack space.
317 __ CallRuntime(Runtime::kThrowStackOverflow);
318
319 __ bind(&okay);
Leon Clarkee46be812010-01-19 14:06:41 +0000320}
321
322
Steve Blocka7e24c12009-10-30 11:49:00 +0000323static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
324 bool is_construct) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000325 ProfileEntryHookStub::MaybeCallEntryHook(masm);
326
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100327 // Clear the context before we push it when entering the internal frame.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000328 __ Move(esi, Immediate(0));
Steve Blocka7e24c12009-10-30 11:49:00 +0000329
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100330 {
331 FrameScope scope(masm, StackFrame::INTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000332
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000333 // Setup the context (we need to use the caller context from the isolate).
334 ExternalReference context_address(Isolate::kContextAddress,
335 masm->isolate());
336 __ mov(esi, Operand::StaticVariable(context_address));
337
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100338 // Load the previous frame pointer (ebx) to access C arguments
339 __ mov(ebx, Operand(ebp, 0));
Steve Blocka7e24c12009-10-30 11:49:00 +0000340
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100341 // Push the function and the receiver onto the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000342 __ push(Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100343 __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000344
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100345 // Load the number of arguments and setup pointer to the arguments.
346 __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset));
347 __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000348
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000349 // Check if we have enough stack space to push all arguments.
350 // Expects argument count in eax. Clobbers ecx, edx, edi.
351 Generate_CheckStackOverflow(masm, kEaxIsUntaggedInt);
352
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100353 // Copy arguments to the stack in a loop.
354 Label loop, entry;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000355 __ Move(ecx, Immediate(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000356 __ jmp(&entry, Label::kNear);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100357 __ bind(&loop);
358 __ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv
359 __ push(Operand(edx, 0)); // dereference handle
360 __ inc(ecx);
361 __ bind(&entry);
362 __ cmp(ecx, eax);
363 __ j(not_equal, &loop);
Steve Blocka7e24c12009-10-30 11:49:00 +0000364
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000365 // Load the previous frame pointer (ebx) to access C arguments
366 __ mov(ebx, Operand(ebp, 0));
367
368 // Get the new.target and function from the frame.
369 __ mov(edx, Operand(ebx, EntryFrameConstants::kNewTargetArgOffset));
370 __ mov(edi, Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000371
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100372 // Invoke the code.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000373 Handle<Code> builtin = is_construct
374 ? masm->isolate()->builtins()->Construct()
375 : masm->isolate()->builtins()->Call();
376 __ Call(builtin, RelocInfo::CODE_TARGET);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100377
378 // Exit the internal frame. Notice that this also removes the empty.
379 // context and the function left on the stack by the code
380 // invocation.
Steve Blocka7e24c12009-10-30 11:49:00 +0000381 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100382 __ ret(kPointerSize); // Remove receiver.
Steve Blocka7e24c12009-10-30 11:49:00 +0000383}
384
385
386void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
387 Generate_JSEntryTrampolineHelper(masm, false);
388}
389
390
391void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
392 Generate_JSEntryTrampolineHelper(masm, true);
393}
394
395
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000396// Generate code for entering a JS function with the interpreter.
397// On entry to the function the receiver and arguments have been pushed on the
398// stack left to right. The actual argument count matches the formal parameter
399// count expected by the function.
400//
401// The live registers are:
402// o edi: the JS function object being called
403// o edx: the new target
404// o esi: our context
405// o ebp: the caller's frame pointer
406// o esp: stack pointer (pointing to return address)
407//
Ben Murdoch097c5b22016-05-18 11:27:45 +0100408// The function builds an interpreter frame. See InterpreterFrameConstants in
409// frames.h for its layout.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000410void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
411 // Open a frame scope to indicate that there is a frame on the stack. The
412 // MANUAL indicates that the scope shouldn't actually generate code to set up
413 // the frame (that is done below).
414 FrameScope frame_scope(masm, StackFrame::MANUAL);
415 __ push(ebp); // Caller's frame pointer.
416 __ mov(ebp, esp);
417 __ push(esi); // Callee's context.
418 __ push(edi); // Callee's JS function.
419 __ push(edx); // Callee's new target.
420
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000421 // Get the bytecode array from the function object and load the pointer to the
422 // first entry into edi (InterpreterBytecodeRegister).
423 __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100424
425 Label load_debug_bytecode_array, bytecode_array_loaded;
426 __ cmp(FieldOperand(eax, SharedFunctionInfo::kDebugInfoOffset),
427 Immediate(DebugInfo::uninitialized()));
428 __ j(not_equal, &load_debug_bytecode_array);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000429 __ mov(kInterpreterBytecodeArrayRegister,
430 FieldOperand(eax, SharedFunctionInfo::kFunctionDataOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100431 __ bind(&bytecode_array_loaded);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000432
433 if (FLAG_debug_code) {
434 // Check function data field is actually a BytecodeArray object.
435 __ AssertNotSmi(kInterpreterBytecodeArrayRegister);
436 __ CmpObjectType(kInterpreterBytecodeArrayRegister, BYTECODE_ARRAY_TYPE,
437 eax);
438 __ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
439 }
440
Ben Murdoch097c5b22016-05-18 11:27:45 +0100441 // Push bytecode array.
442 __ push(kInterpreterBytecodeArrayRegister);
443 // Push zero for bytecode array offset.
444 __ push(Immediate(0));
445
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000446 // Allocate the local and temporary register file on the stack.
447 {
448 // Load frame size from the BytecodeArray object.
449 __ mov(ebx, FieldOperand(kInterpreterBytecodeArrayRegister,
450 BytecodeArray::kFrameSizeOffset));
451
452 // Do a stack check to ensure we don't go over the limit.
453 Label ok;
454 __ mov(ecx, esp);
455 __ sub(ecx, ebx);
456 ExternalReference stack_limit =
457 ExternalReference::address_of_real_stack_limit(masm->isolate());
458 __ cmp(ecx, Operand::StaticVariable(stack_limit));
459 __ j(above_equal, &ok);
460 __ CallRuntime(Runtime::kThrowStackOverflow);
461 __ bind(&ok);
462
463 // If ok, push undefined as the initial value for all register file entries.
464 Label loop_header;
465 Label loop_check;
466 __ mov(eax, Immediate(masm->isolate()->factory()->undefined_value()));
467 __ jmp(&loop_check);
468 __ bind(&loop_header);
469 // TODO(rmcilroy): Consider doing more than one push per loop iteration.
470 __ push(eax);
471 // Continue loop if not done.
472 __ bind(&loop_check);
473 __ sub(ebx, Immediate(kPointerSize));
474 __ j(greater_equal, &loop_header);
475 }
476
477 // TODO(rmcilroy): List of things not currently dealt with here but done in
478 // fullcodegen's prologue:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000479 // - Call ProfileEntryHookStub when isolate has a function_entry_hook.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000480 // - Code aging of the BytecodeArray object.
481
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000482 // Load accumulator, register file, bytecode offset, dispatch table into
483 // registers.
484 __ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
485 __ mov(kInterpreterRegisterFileRegister, ebp);
486 __ add(kInterpreterRegisterFileRegister,
487 Immediate(InterpreterFrameConstants::kRegisterFilePointerFromFp));
488 __ mov(kInterpreterBytecodeOffsetRegister,
489 Immediate(BytecodeArray::kHeaderSize - kHeapObjectTag));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100490 __ mov(ebx, Immediate(ExternalReference::interpreter_dispatch_table_address(
491 masm->isolate())));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000492
493 // Push dispatch table as a stack located parameter to the bytecode handler.
494 DCHECK_EQ(-1, kInterpreterDispatchTableSpillSlot);
495 __ push(ebx);
496
497 // Dispatch to the first bytecode handler for the function.
498 __ movzx_b(eax, Operand(kInterpreterBytecodeArrayRegister,
499 kInterpreterBytecodeOffsetRegister, times_1, 0));
500 __ mov(ebx, Operand(ebx, eax, times_pointer_size, 0));
501 // Restore undefined_value in accumulator (eax)
502 // TODO(rmcilroy): Remove this once we move the dispatch table back into a
503 // register.
504 __ mov(eax, Immediate(masm->isolate()->factory()->undefined_value()));
505 // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
506 // and header removal.
507 __ add(ebx, Immediate(Code::kHeaderSize - kHeapObjectTag));
508 __ call(ebx);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100509
510 // Even though the first bytecode handler was called, we will never return.
511 __ Abort(kUnexpectedReturnFromBytecodeHandler);
512
513 // Load debug copy of the bytecode array.
514 __ bind(&load_debug_bytecode_array);
515 Register debug_info = kInterpreterBytecodeArrayRegister;
516 __ mov(debug_info, FieldOperand(eax, SharedFunctionInfo::kDebugInfoOffset));
517 __ mov(kInterpreterBytecodeArrayRegister,
518 FieldOperand(debug_info, DebugInfo::kAbstractCodeIndex));
519 __ jmp(&bytecode_array_loaded);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000520}
521
522
523void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
524 // TODO(rmcilroy): List of things not currently dealt with here but done in
525 // fullcodegen's EmitReturnSequence.
526 // - Supporting FLAG_trace for Runtime::TraceExit.
527 // - Support profiler (specifically decrementing profiling_counter
528 // appropriately and calling out to HandleInterrupts if necessary).
529
530 // The return value is in accumulator, which is already in rax.
531
532 // Leave the frame (also dropping the register file).
533 __ leave();
534
535 // Drop receiver + arguments and return.
536 __ mov(ebx, FieldOperand(kInterpreterBytecodeArrayRegister,
537 BytecodeArray::kParameterSizeOffset));
538 __ pop(ecx);
539 __ add(esp, ebx);
540 __ push(ecx);
541 __ ret(0);
542}
543
544
545static void Generate_InterpreterPushArgs(MacroAssembler* masm,
546 Register array_limit) {
547 // ----------- S t a t e -------------
548 // -- ebx : Pointer to the last argument in the args array.
549 // -- array_limit : Pointer to one before the first argument in the
550 // args array.
551 // -----------------------------------
552 Label loop_header, loop_check;
553 __ jmp(&loop_check);
554 __ bind(&loop_header);
555 __ Push(Operand(ebx, 0));
556 __ sub(ebx, Immediate(kPointerSize));
557 __ bind(&loop_check);
558 __ cmp(ebx, array_limit);
559 __ j(greater, &loop_header, Label::kNear);
560}
561
562
563// static
Ben Murdoch097c5b22016-05-18 11:27:45 +0100564void Builtins::Generate_InterpreterPushArgsAndCallImpl(
565 MacroAssembler* masm, TailCallMode tail_call_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000566 // ----------- S t a t e -------------
567 // -- eax : the number of arguments (not including the receiver)
568 // -- ebx : the address of the first argument to be pushed. Subsequent
569 // arguments should be consecutive above this, in the same order as
570 // they are to be pushed onto the stack.
571 // -- edi : the target to call (can be any Object).
572 // -----------------------------------
573
574 // Pop return address to allow tail-call after pushing arguments.
575 __ Pop(edx);
576
577 // Find the address of the last argument.
578 __ mov(ecx, eax);
579 __ add(ecx, Immediate(1)); // Add one for receiver.
580 __ shl(ecx, kPointerSizeLog2);
581 __ neg(ecx);
582 __ add(ecx, ebx);
583
584 Generate_InterpreterPushArgs(masm, ecx);
585
586 // Call the target.
587 __ Push(edx); // Re-push return address.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100588 __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
589 tail_call_mode),
590 RelocInfo::CODE_TARGET);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000591}
592
593
594// static
595void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
596 // ----------- S t a t e -------------
597 // -- eax : the number of arguments (not including the receiver)
598 // -- edx : the new target
599 // -- edi : the constructor
600 // -- ebx : the address of the first argument to be pushed. Subsequent
601 // arguments should be consecutive above this, in the same order as
602 // they are to be pushed onto the stack.
603 // -----------------------------------
604
605 // Save number of arguments on the stack below where arguments are going
606 // to be pushed.
607 __ mov(ecx, eax);
608 __ neg(ecx);
609 __ mov(Operand(esp, ecx, times_pointer_size, -kPointerSize), eax);
610 __ mov(eax, ecx);
611
612 // Pop return address to allow tail-call after pushing arguments.
613 __ Pop(ecx);
614
615 // Find the address of the last argument.
616 __ shl(eax, kPointerSizeLog2);
617 __ add(eax, ebx);
618
619 // Push padding for receiver.
620 __ Push(Immediate(0));
621
622 Generate_InterpreterPushArgs(masm, eax);
623
624 // Restore number of arguments from slot on stack.
625 __ mov(eax, Operand(esp, -kPointerSize));
626
627 // Re-push return address.
628 __ Push(ecx);
629
630 // Call the constructor with unmodified eax, edi, ebi values.
631 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
632}
633
634
Ben Murdoch097c5b22016-05-18 11:27:45 +0100635static void Generate_EnterBytecodeDispatch(MacroAssembler* masm) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000636 // Initialize register file register.
637 __ mov(kInterpreterRegisterFileRegister, ebp);
638 __ add(kInterpreterRegisterFileRegister,
639 Immediate(InterpreterFrameConstants::kRegisterFilePointerFromFp));
640
641 // Get the bytecode array pointer from the frame.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000642 __ mov(kInterpreterBytecodeArrayRegister,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100643 Operand(kInterpreterRegisterFileRegister,
644 InterpreterFrameConstants::kBytecodeArrayFromRegisterPointer));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000645
646 if (FLAG_debug_code) {
647 // Check function data field is actually a BytecodeArray object.
648 __ AssertNotSmi(kInterpreterBytecodeArrayRegister);
649 __ CmpObjectType(kInterpreterBytecodeArrayRegister, BYTECODE_ARRAY_TYPE,
650 ebx);
651 __ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
652 }
653
654 // Get the target bytecode offset from the frame.
655 __ mov(
656 kInterpreterBytecodeOffsetRegister,
657 Operand(kInterpreterRegisterFileRegister,
658 InterpreterFrameConstants::kBytecodeOffsetFromRegisterPointer));
659 __ SmiUntag(kInterpreterBytecodeOffsetRegister);
660
Ben Murdoch097c5b22016-05-18 11:27:45 +0100661 // Push dispatch table as a stack located parameter to the bytecode handler.
662 __ mov(ebx, Immediate(ExternalReference::interpreter_dispatch_table_address(
663 masm->isolate())));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000664 DCHECK_EQ(-1, kInterpreterDispatchTableSpillSlot);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100665 __ Pop(esi);
666 __ Push(ebx);
667 __ Push(esi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000668
669 // Dispatch to the target bytecode.
670 __ movzx_b(esi, Operand(kInterpreterBytecodeArrayRegister,
671 kInterpreterBytecodeOffsetRegister, times_1, 0));
672 __ mov(ebx, Operand(ebx, esi, times_pointer_size, 0));
673
674 // Get the context from the frame.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000675 __ mov(kContextRegister,
676 Operand(kInterpreterRegisterFileRegister,
677 InterpreterFrameConstants::kContextFromRegisterPointer));
678
679 // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
680 // and header removal.
681 __ add(ebx, Immediate(Code::kHeaderSize - kHeapObjectTag));
682 __ jmp(ebx);
683}
684
685
Ben Murdoch097c5b22016-05-18 11:27:45 +0100686static void Generate_InterpreterNotifyDeoptimizedHelper(
687 MacroAssembler* masm, Deoptimizer::BailoutType type) {
688 // Enter an internal frame.
689 {
690 FrameScope scope(masm, StackFrame::INTERNAL);
691
692 // Pass the deoptimization type to the runtime system.
693 __ Push(Smi::FromInt(static_cast<int>(type)));
694 __ CallRuntime(Runtime::kNotifyDeoptimized);
695 // Tear down internal frame.
696 }
697
698 // Drop state (we don't use these for interpreter deopts) and and pop the
699 // accumulator value into the accumulator register and push PC at top
700 // of stack (to simulate initial call to bytecode handler in interpreter entry
701 // trampoline).
702 __ Pop(ebx);
703 __ Drop(1);
704 __ Pop(kInterpreterAccumulatorRegister);
705 __ Push(ebx);
706
707 // Enter the bytecode dispatch.
708 Generate_EnterBytecodeDispatch(masm);
709}
710
711
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000712void Builtins::Generate_InterpreterNotifyDeoptimized(MacroAssembler* masm) {
713 Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
714}
715
716
717void Builtins::Generate_InterpreterNotifySoftDeoptimized(MacroAssembler* masm) {
718 Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
719}
720
721
722void Builtins::Generate_InterpreterNotifyLazyDeoptimized(MacroAssembler* masm) {
723 Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
724}
725
Ben Murdoch097c5b22016-05-18 11:27:45 +0100726void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
727 // Set the address of the interpreter entry trampoline as a return address.
728 // This simulates the initial call to bytecode handlers in interpreter entry
729 // trampoline. The return will never actually be taken, but our stack walker
730 // uses this address to determine whether a frame is interpreted.
731 __ Push(masm->isolate()->builtins()->InterpreterEntryTrampoline());
732
733 Generate_EnterBytecodeDispatch(masm);
734}
735
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000736
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000737void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100738 GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy);
Iain Merrick75681382010-08-19 15:07:18 +0100739}
740
741
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000742void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100743 GenerateTailCallToReturnedCode(masm,
744 Runtime::kCompileOptimized_NotConcurrent);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000745}
746
747
748void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100749 GenerateTailCallToReturnedCode(masm, Runtime::kCompileOptimized_Concurrent);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000750}
751
752
753static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
754 // For now, we are relying on the fact that make_code_young doesn't do any
755 // garbage collection which allows us to save/restore the registers without
756 // worrying about which of them contain pointers. We also don't build an
757 // internal frame to make the code faster, since we shouldn't have to do stack
758 // crawls in MakeCodeYoung. This seems a bit fragile.
759
760 // Re-execute the code that was patched back to the young age when
761 // the stub returns.
762 __ sub(Operand(esp, 0), Immediate(5));
763 __ pushad();
764 __ mov(eax, Operand(esp, 8 * kPointerSize));
765 {
766 FrameScope scope(masm, StackFrame::MANUAL);
767 __ PrepareCallCFunction(2, ebx);
768 __ mov(Operand(esp, 1 * kPointerSize),
769 Immediate(ExternalReference::isolate_address(masm->isolate())));
770 __ mov(Operand(esp, 0), eax);
771 __ CallCFunction(
772 ExternalReference::get_make_code_young_function(masm->isolate()), 2);
773 }
774 __ popad();
775 __ ret(0);
776}
777
778#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \
779void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \
780 MacroAssembler* masm) { \
781 GenerateMakeCodeYoungAgainCommon(masm); \
782} \
783void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \
784 MacroAssembler* masm) { \
785 GenerateMakeCodeYoungAgainCommon(masm); \
786}
787CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
788#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
789
790
791void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
792 // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact
793 // that make_code_young doesn't do any garbage collection which allows us to
794 // save/restore the registers without worrying about which of them contain
795 // pointers.
796 __ pushad();
797 __ mov(eax, Operand(esp, 8 * kPointerSize));
798 __ sub(eax, Immediate(Assembler::kCallInstructionLength));
799 { // NOLINT
800 FrameScope scope(masm, StackFrame::MANUAL);
801 __ PrepareCallCFunction(2, ebx);
802 __ mov(Operand(esp, 1 * kPointerSize),
803 Immediate(ExternalReference::isolate_address(masm->isolate())));
804 __ mov(Operand(esp, 0), eax);
805 __ CallCFunction(
806 ExternalReference::get_mark_code_as_executed_function(masm->isolate()),
807 2);
808 }
809 __ popad();
810
811 // Perform prologue operations usually performed by the young code stub.
812 __ pop(eax); // Pop return address into scratch register.
813 __ push(ebp); // Caller's frame pointer.
814 __ mov(ebp, esp);
815 __ push(esi); // Callee's context.
816 __ push(edi); // Callee's JS Function.
817 __ push(eax); // Push return address after frame prologue.
818
819 // Jump to point after the code-age stub.
820 __ ret(0);
821}
822
823
824void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
825 GenerateMakeCodeYoungAgainCommon(masm);
826}
827
828
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000829void Builtins::Generate_MarkCodeAsToBeExecutedOnce(MacroAssembler* masm) {
830 Generate_MarkCodeAsExecutedOnce(masm);
831}
832
833
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000834static void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
835 SaveFPRegsMode save_doubles) {
836 // Enter an internal frame.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100837 {
838 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100839
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000840 // Preserve registers across notification, this is important for compiled
841 // stubs that tail call the runtime on deopts passing their parameters in
842 // registers.
843 __ pushad();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000844 __ CallRuntime(Runtime::kNotifyStubFailure, save_doubles);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000845 __ popad();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100846 // Tear down internal frame.
847 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100848
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000849 __ pop(MemOperand(esp, 0)); // Ignore state offset
850 __ ret(0); // Return to IC Miss stub, continuation still on stack.
851}
852
853
854void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
855 Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
856}
857
858
859void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
860 Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100861}
862
863
864static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
865 Deoptimizer::BailoutType type) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100866 {
867 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100868
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100869 // Pass deoptimization type to the runtime system.
870 __ push(Immediate(Smi::FromInt(static_cast<int>(type))));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000871 __ CallRuntime(Runtime::kNotifyDeoptimized);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100872
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100873 // Tear down internal frame.
874 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100875
876 // Get the full codegen state from the stack and untag it.
877 __ mov(ecx, Operand(esp, 1 * kPointerSize));
878 __ SmiUntag(ecx);
879
880 // Switch on the state.
Ben Murdoch257744e2011-11-30 15:57:28 +0000881 Label not_no_registers, not_tos_eax;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100882 __ cmp(ecx, FullCodeGenerator::NO_REGISTERS);
Ben Murdoch257744e2011-11-30 15:57:28 +0000883 __ j(not_equal, &not_no_registers, Label::kNear);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100884 __ ret(1 * kPointerSize); // Remove state.
885
886 __ bind(&not_no_registers);
887 __ mov(eax, Operand(esp, 2 * kPointerSize));
888 __ cmp(ecx, FullCodeGenerator::TOS_REG);
Ben Murdoch257744e2011-11-30 15:57:28 +0000889 __ j(not_equal, &not_tos_eax, Label::kNear);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100890 __ ret(2 * kPointerSize); // Remove state, eax.
891
892 __ bind(&not_tos_eax);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000893 __ Abort(kNoCasesLeft);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100894}
895
896
897void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
898 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
899}
900
901
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000902void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
903 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100904}
905
906
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000907void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
908 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100909}
910
911
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000912// static
913void Builtins::Generate_DatePrototype_GetField(MacroAssembler* masm,
914 int field_index) {
915 // ----------- S t a t e -------------
916 // -- esp[0] : return address
917 // -- esp[4] : receiver
918 // -----------------------------------
Steve Block44f0eee2011-05-26 01:26:41 +0100919
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000920 // 1. Load receiver into eax and check that it's actually a JSDate object.
921 Label receiver_not_date;
922 {
923 __ mov(eax, Operand(esp, kPointerSize));
924 __ JumpIfSmi(eax, &receiver_not_date);
925 __ CmpObjectType(eax, JS_DATE_TYPE, ebx);
926 __ j(not_equal, &receiver_not_date);
927 }
928
929 // 2. Load the specified date field, falling back to the runtime as necessary.
930 if (field_index == JSDate::kDateValue) {
931 __ mov(eax, FieldOperand(eax, JSDate::kValueOffset));
932 } else {
933 if (field_index < JSDate::kFirstUncachedField) {
934 Label stamp_mismatch;
935 __ mov(edx, Operand::StaticVariable(
936 ExternalReference::date_cache_stamp(masm->isolate())));
937 __ cmp(edx, FieldOperand(eax, JSDate::kCacheStampOffset));
938 __ j(not_equal, &stamp_mismatch, Label::kNear);
939 __ mov(eax, FieldOperand(
940 eax, JSDate::kValueOffset + field_index * kPointerSize));
941 __ ret(1 * kPointerSize);
942 __ bind(&stamp_mismatch);
943 }
944 FrameScope scope(masm, StackFrame::INTERNAL);
945 __ PrepareCallCFunction(2, ebx);
946 __ mov(Operand(esp, 0), eax);
947 __ mov(Operand(esp, 1 * kPointerSize),
948 Immediate(Smi::FromInt(field_index)));
949 __ CallCFunction(
950 ExternalReference::get_date_field_function(masm->isolate()), 2);
951 }
952 __ ret(1 * kPointerSize);
953
954 // 3. Raise a TypeError if the receiver is not a date.
955 __ bind(&receiver_not_date);
956 {
957 FrameScope scope(masm, StackFrame::MANUAL);
958 __ EnterFrame(StackFrame::INTERNAL);
959 __ CallRuntime(Runtime::kThrowNotDateError);
960 }
961}
962
963
964// static
965void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
966 // ----------- S t a t e -------------
967 // -- eax : argc
968 // -- esp[0] : return address
969 // -- esp[4] : argArray
970 // -- esp[8] : thisArg
971 // -- esp[12] : receiver
972 // -----------------------------------
973
974 // 1. Load receiver into edi, argArray into eax (if present), remove all
975 // arguments from the stack (including the receiver), and push thisArg (if
976 // present) instead.
977 {
978 Label no_arg_array, no_this_arg;
979 __ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
980 __ mov(ebx, edx);
981 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100982 __ test(eax, eax);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000983 __ j(zero, &no_this_arg, Label::kNear);
984 {
985 __ mov(edx, Operand(esp, eax, times_pointer_size, 0));
986 __ cmp(eax, Immediate(1));
987 __ j(equal, &no_arg_array, Label::kNear);
988 __ mov(ebx, Operand(esp, eax, times_pointer_size, -kPointerSize));
989 __ bind(&no_arg_array);
990 }
991 __ bind(&no_this_arg);
992 __ PopReturnAddressTo(ecx);
993 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
994 __ Push(edx);
995 __ PushReturnAddressFrom(ecx);
996 __ Move(eax, ebx);
997 }
998
999 // ----------- S t a t e -------------
1000 // -- eax : argArray
1001 // -- edi : receiver
1002 // -- esp[0] : return address
1003 // -- esp[4] : thisArg
1004 // -----------------------------------
1005
1006 // 2. Make sure the receiver is actually callable.
1007 Label receiver_not_callable;
1008 __ JumpIfSmi(edi, &receiver_not_callable, Label::kNear);
1009 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
1010 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsCallable);
1011 __ j(zero, &receiver_not_callable, Label::kNear);
1012
1013 // 3. Tail call with no arguments if argArray is null or undefined.
1014 Label no_arguments;
1015 __ JumpIfRoot(eax, Heap::kNullValueRootIndex, &no_arguments, Label::kNear);
1016 __ JumpIfRoot(eax, Heap::kUndefinedValueRootIndex, &no_arguments,
1017 Label::kNear);
1018
1019 // 4a. Apply the receiver to the given argArray (passing undefined for
1020 // new.target).
1021 __ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
1022 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1023
1024 // 4b. The argArray is either null or undefined, so we tail call without any
1025 // arguments to the receiver.
1026 __ bind(&no_arguments);
1027 {
1028 __ Set(eax, 0);
1029 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1030 }
1031
1032 // 4c. The receiver is not callable, throw an appropriate TypeError.
1033 __ bind(&receiver_not_callable);
1034 {
1035 __ mov(Operand(esp, kPointerSize), edi);
1036 __ TailCallRuntime(Runtime::kThrowApplyNonFunction);
1037 }
1038}
1039
1040
1041// static
1042void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) {
1043 // Stack Layout:
1044 // esp[0] : Return address
1045 // esp[8] : Argument n
1046 // esp[16] : Argument n-1
1047 // ...
1048 // esp[8 * n] : Argument 1
1049 // esp[8 * (n + 1)] : Receiver (callable to call)
1050 //
1051 // eax contains the number of arguments, n, not counting the receiver.
1052 //
1053 // 1. Make sure we have at least one argument.
1054 {
1055 Label done;
1056 __ test(eax, eax);
1057 __ j(not_zero, &done, Label::kNear);
1058 __ PopReturnAddressTo(ebx);
1059 __ PushRoot(Heap::kUndefinedValueRootIndex);
1060 __ PushReturnAddressFrom(ebx);
Steve Blocka7e24c12009-10-30 11:49:00 +00001061 __ inc(eax);
1062 __ bind(&done);
1063 }
1064
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001065 // 2. Get the callable to call (passed as receiver) from the stack.
1066 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize));
Steve Blocka7e24c12009-10-30 11:49:00 +00001067
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001068 // 3. Shift arguments and return address one slot down on the stack
Andrei Popescu402d9372010-02-26 13:31:12 +00001069 // (overwriting the original receiver). Adjust argument count to make
1070 // the original first argument the new receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001071 {
1072 Label loop;
Leon Clarkee46be812010-01-19 14:06:41 +00001073 __ mov(ecx, eax);
Steve Blocka7e24c12009-10-30 11:49:00 +00001074 __ bind(&loop);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001075 __ mov(ebx, Operand(esp, ecx, times_pointer_size, 0));
1076 __ mov(Operand(esp, ecx, times_pointer_size, kPointerSize), ebx);
Steve Blocka7e24c12009-10-30 11:49:00 +00001077 __ dec(ecx);
Andrei Popescu402d9372010-02-26 13:31:12 +00001078 __ j(not_sign, &loop); // While non-negative (to copy return address).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001079 __ pop(ebx); // Discard copy of return address.
Leon Clarkee46be812010-01-19 14:06:41 +00001080 __ dec(eax); // One fewer argument (first argument is new receiver).
Steve Blocka7e24c12009-10-30 11:49:00 +00001081 }
1082
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001083 // 4. Call the callable.
1084 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
Steve Blocka7e24c12009-10-30 11:49:00 +00001085}
1086
1087
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001088void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
1089 // ----------- S t a t e -------------
1090 // -- eax : argc
1091 // -- esp[0] : return address
1092 // -- esp[4] : argumentsList
1093 // -- esp[8] : thisArgument
1094 // -- esp[12] : target
1095 // -- esp[16] : receiver
1096 // -----------------------------------
1097
1098 // 1. Load target into edi (if present), argumentsList into eax (if present),
1099 // remove all arguments from the stack (including the receiver), and push
1100 // thisArgument (if present) instead.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001101 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001102 Label done;
1103 __ LoadRoot(edi, Heap::kUndefinedValueRootIndex);
1104 __ mov(edx, edi);
1105 __ mov(ebx, edi);
1106 __ cmp(eax, Immediate(1));
1107 __ j(below, &done, Label::kNear);
1108 __ mov(edi, Operand(esp, eax, times_pointer_size, -0 * kPointerSize));
1109 __ j(equal, &done, Label::kNear);
1110 __ mov(edx, Operand(esp, eax, times_pointer_size, -1 * kPointerSize));
1111 __ cmp(eax, Immediate(3));
1112 __ j(below, &done, Label::kNear);
1113 __ mov(ebx, Operand(esp, eax, times_pointer_size, -2 * kPointerSize));
1114 __ bind(&done);
1115 __ PopReturnAddressTo(ecx);
1116 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1117 __ Push(edx);
1118 __ PushReturnAddressFrom(ecx);
1119 __ Move(eax, ebx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001120 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001121
1122 // ----------- S t a t e -------------
1123 // -- eax : argumentsList
1124 // -- edi : target
1125 // -- esp[0] : return address
1126 // -- esp[4] : thisArgument
1127 // -----------------------------------
1128
1129 // 2. Make sure the target is actually callable.
1130 Label target_not_callable;
1131 __ JumpIfSmi(edi, &target_not_callable, Label::kNear);
1132 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
1133 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsCallable);
1134 __ j(zero, &target_not_callable, Label::kNear);
1135
1136 // 3a. Apply the target to the given argumentsList (passing undefined for
1137 // new.target).
1138 __ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
1139 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1140
1141 // 3b. The target is not callable, throw an appropriate TypeError.
1142 __ bind(&target_not_callable);
1143 {
1144 __ mov(Operand(esp, kPointerSize), edi);
1145 __ TailCallRuntime(Runtime::kThrowApplyNonFunction);
1146 }
1147}
1148
1149
1150void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
1151 // ----------- S t a t e -------------
1152 // -- eax : argc
1153 // -- esp[0] : return address
1154 // -- esp[4] : new.target (optional)
1155 // -- esp[8] : argumentsList
1156 // -- esp[12] : target
1157 // -- esp[16] : receiver
1158 // -----------------------------------
1159
1160 // 1. Load target into edi (if present), argumentsList into eax (if present),
1161 // new.target into edx (if present, otherwise use target), remove all
1162 // arguments from the stack (including the receiver), and push thisArgument
1163 // (if present) instead.
1164 {
1165 Label done;
1166 __ LoadRoot(edi, Heap::kUndefinedValueRootIndex);
1167 __ mov(edx, edi);
1168 __ mov(ebx, edi);
1169 __ cmp(eax, Immediate(1));
1170 __ j(below, &done, Label::kNear);
1171 __ mov(edi, Operand(esp, eax, times_pointer_size, -0 * kPointerSize));
1172 __ mov(edx, edi);
1173 __ j(equal, &done, Label::kNear);
1174 __ mov(ebx, Operand(esp, eax, times_pointer_size, -1 * kPointerSize));
1175 __ cmp(eax, Immediate(3));
1176 __ j(below, &done, Label::kNear);
1177 __ mov(edx, Operand(esp, eax, times_pointer_size, -2 * kPointerSize));
1178 __ bind(&done);
1179 __ PopReturnAddressTo(ecx);
1180 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1181 __ PushRoot(Heap::kUndefinedValueRootIndex);
1182 __ PushReturnAddressFrom(ecx);
1183 __ Move(eax, ebx);
1184 }
1185
1186 // ----------- S t a t e -------------
1187 // -- eax : argumentsList
1188 // -- edx : new.target
1189 // -- edi : target
1190 // -- esp[0] : return address
1191 // -- esp[4] : receiver (undefined)
1192 // -----------------------------------
1193
1194 // 2. Make sure the target is actually a constructor.
1195 Label target_not_constructor;
1196 __ JumpIfSmi(edi, &target_not_constructor, Label::kNear);
1197 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
1198 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsConstructor);
1199 __ j(zero, &target_not_constructor, Label::kNear);
1200
1201 // 3. Make sure the target is actually a constructor.
1202 Label new_target_not_constructor;
1203 __ JumpIfSmi(edx, &new_target_not_constructor, Label::kNear);
1204 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
1205 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsConstructor);
1206 __ j(zero, &new_target_not_constructor, Label::kNear);
1207
1208 // 4a. Construct the target with the given new.target and argumentsList.
1209 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1210
1211 // 4b. The target is not a constructor, throw an appropriate TypeError.
1212 __ bind(&target_not_constructor);
1213 {
1214 __ mov(Operand(esp, kPointerSize), edi);
1215 __ TailCallRuntime(Runtime::kThrowCalledNonCallable);
1216 }
1217
1218 // 4c. The new.target is not a constructor, throw an appropriate TypeError.
1219 __ bind(&new_target_not_constructor);
1220 {
1221 __ mov(Operand(esp, kPointerSize), edx);
1222 __ TailCallRuntime(Runtime::kThrowCalledNonCallable);
1223 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001224}
1225
1226
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001227void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
1228 // ----------- S t a t e -------------
1229 // -- eax : argc
1230 // -- esp[0] : return address
1231 // -- esp[4] : last argument
1232 // -----------------------------------
1233 Label generic_array_code;
1234
1235 // Get the InternalArray function.
1236 __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi);
1237
1238 if (FLAG_debug_code) {
1239 // Initial map for the builtin InternalArray function should be a map.
1240 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1241 // Will both indicate a NULL and a Smi.
1242 __ test(ebx, Immediate(kSmiTagMask));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001243 __ Assert(not_zero, kUnexpectedInitialMapForInternalArrayFunction);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001244 __ CmpObjectType(ebx, MAP_TYPE, ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001245 __ Assert(equal, kUnexpectedInitialMapForInternalArrayFunction);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001246 }
1247
1248 // Run the native code for the InternalArray function called as a normal
1249 // function.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001250 // tail call a stub
1251 InternalArrayConstructorStub stub(masm->isolate());
1252 __ TailCallStub(&stub);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001253}
1254
1255
Steve Blocka7e24c12009-10-30 11:49:00 +00001256void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
1257 // ----------- S t a t e -------------
1258 // -- eax : argc
1259 // -- esp[0] : return address
1260 // -- esp[4] : last argument
1261 // -----------------------------------
Kristian Monsen25f61362010-05-21 11:50:48 +01001262 Label generic_array_code;
Steve Blocka7e24c12009-10-30 11:49:00 +00001263
1264 // Get the Array function.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001265 __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001266 __ mov(edx, edi);
Steve Blocka7e24c12009-10-30 11:49:00 +00001267
1268 if (FLAG_debug_code) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001269 // Initial map for the builtin Array function should be a map.
Steve Blocka7e24c12009-10-30 11:49:00 +00001270 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1271 // Will both indicate a NULL and a Smi.
1272 __ test(ebx, Immediate(kSmiTagMask));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001273 __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction);
Steve Blocka7e24c12009-10-30 11:49:00 +00001274 __ CmpObjectType(ebx, MAP_TYPE, ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001275 __ Assert(equal, kUnexpectedInitialMapForArrayFunction);
Steve Blocka7e24c12009-10-30 11:49:00 +00001276 }
1277
1278 // Run the native code for the Array function called as a normal function.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001279 // tail call a stub
1280 __ mov(ebx, masm->isolate()->factory()->undefined_value());
1281 ArrayConstructorStub stub(masm->isolate());
1282 __ TailCallStub(&stub);
Steve Blocka7e24c12009-10-30 11:49:00 +00001283}
1284
1285
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001286// static
Ben Murdoch097c5b22016-05-18 11:27:45 +01001287void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
1288 // ----------- S t a t e -------------
1289 // -- eax : number of arguments
1290 // -- esp[0] : return address
1291 // -- esp[(argc - n) * 8] : arg[n] (zero-based)
1292 // -- esp[(argc + 1) * 8] : receiver
1293 // -----------------------------------
1294 Condition const cc = (kind == MathMaxMinKind::kMin) ? below : above;
1295 Heap::RootListIndex const root_index =
1296 (kind == MathMaxMinKind::kMin) ? Heap::kInfinityValueRootIndex
1297 : Heap::kMinusInfinityValueRootIndex;
1298 XMMRegister const reg = (kind == MathMaxMinKind::kMin) ? xmm1 : xmm0;
1299
1300 // Load the accumulator with the default return value (either -Infinity or
1301 // +Infinity), with the tagged value in edx and the double value in xmm0.
1302 __ LoadRoot(edx, root_index);
1303 __ movsd(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
1304 __ Move(ecx, eax);
1305
1306 Label done_loop, loop;
1307 __ bind(&loop);
1308 {
1309 // Check if all parameters done.
1310 __ test(ecx, ecx);
1311 __ j(zero, &done_loop);
1312
1313 // Load the next parameter tagged value into ebx.
1314 __ mov(ebx, Operand(esp, ecx, times_pointer_size, 0));
1315
1316 // Load the double value of the parameter into xmm1, maybe converting the
1317 // parameter to a number first using the ToNumberStub if necessary.
1318 Label convert, convert_smi, convert_number, done_convert;
1319 __ bind(&convert);
1320 __ JumpIfSmi(ebx, &convert_smi);
1321 __ JumpIfRoot(FieldOperand(ebx, HeapObject::kMapOffset),
1322 Heap::kHeapNumberMapRootIndex, &convert_number);
1323 {
1324 // Parameter is not a Number, use the ToNumberStub to convert it.
1325 FrameScope scope(masm, StackFrame::INTERNAL);
1326 __ SmiTag(eax);
1327 __ SmiTag(ecx);
1328 __ Push(eax);
1329 __ Push(ecx);
1330 __ Push(edx);
1331 __ mov(eax, ebx);
1332 ToNumberStub stub(masm->isolate());
1333 __ CallStub(&stub);
1334 __ mov(ebx, eax);
1335 __ Pop(edx);
1336 __ Pop(ecx);
1337 __ Pop(eax);
1338 {
1339 // Restore the double accumulator value (xmm0).
1340 Label restore_smi, done_restore;
1341 __ JumpIfSmi(edx, &restore_smi, Label::kNear);
1342 __ movsd(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
1343 __ jmp(&done_restore, Label::kNear);
1344 __ bind(&restore_smi);
1345 __ SmiUntag(edx);
1346 __ Cvtsi2sd(xmm0, edx);
1347 __ SmiTag(edx);
1348 __ bind(&done_restore);
1349 }
1350 __ SmiUntag(ecx);
1351 __ SmiUntag(eax);
1352 }
1353 __ jmp(&convert);
1354 __ bind(&convert_number);
1355 __ movsd(xmm1, FieldOperand(ebx, HeapNumber::kValueOffset));
1356 __ jmp(&done_convert, Label::kNear);
1357 __ bind(&convert_smi);
1358 __ SmiUntag(ebx);
1359 __ Cvtsi2sd(xmm1, ebx);
1360 __ SmiTag(ebx);
1361 __ bind(&done_convert);
1362
1363 // Perform the actual comparison with the accumulator value on the left hand
1364 // side (xmm0) and the next parameter value on the right hand side (xmm1).
1365 Label compare_equal, compare_nan, compare_swap, done_compare;
1366 __ ucomisd(xmm0, xmm1);
1367 __ j(parity_even, &compare_nan, Label::kNear);
1368 __ j(cc, &done_compare, Label::kNear);
1369 __ j(equal, &compare_equal, Label::kNear);
1370
1371 // Result is on the right hand side.
1372 __ bind(&compare_swap);
1373 __ movaps(xmm0, xmm1);
1374 __ mov(edx, ebx);
1375 __ jmp(&done_compare, Label::kNear);
1376
1377 // At least one side is NaN, which means that the result will be NaN too.
1378 __ bind(&compare_nan);
1379 __ LoadRoot(edx, Heap::kNanValueRootIndex);
1380 __ movsd(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
1381 __ jmp(&done_compare, Label::kNear);
1382
1383 // Left and right hand side are equal, check for -0 vs. +0.
1384 __ bind(&compare_equal);
1385 __ movmskpd(edi, reg);
1386 __ test(edi, Immediate(1));
1387 __ j(not_zero, &compare_swap);
1388
1389 __ bind(&done_compare);
1390 __ dec(ecx);
1391 __ jmp(&loop);
1392 }
1393
1394 __ bind(&done_loop);
1395 __ PopReturnAddressTo(ecx);
1396 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1397 __ PushReturnAddressFrom(ecx);
1398 __ mov(eax, edx);
1399 __ Ret();
1400}
1401
1402// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001403void Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001404 // ----------- S t a t e -------------
1405 // -- eax : number of arguments
1406 // -- edi : constructor function
1407 // -- esp[0] : return address
1408 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1409 // -- esp[(argc + 1) * 4] : receiver
1410 // -----------------------------------
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001411
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001412 // 1. Load the first argument into eax and get rid of the rest (including the
1413 // receiver).
1414 Label no_arguments;
1415 {
1416 __ test(eax, eax);
1417 __ j(zero, &no_arguments, Label::kNear);
1418 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1419 __ PopReturnAddressTo(ecx);
1420 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1421 __ PushReturnAddressFrom(ecx);
1422 __ mov(eax, ebx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001423 }
1424
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001425 // 2a. Convert the first argument to a number.
1426 ToNumberStub stub(masm->isolate());
1427 __ TailCallStub(&stub);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001428
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001429 // 2b. No arguments, return +0 (already in eax).
1430 __ bind(&no_arguments);
1431 __ ret(1 * kPointerSize);
1432}
1433
1434
1435// static
1436void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001437 // ----------- S t a t e -------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001438 // -- eax : number of arguments
1439 // -- edi : constructor function
1440 // -- edx : new target
1441 // -- esp[0] : return address
1442 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1443 // -- esp[(argc + 1) * 4] : receiver
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001444 // -----------------------------------
1445
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001446 // 1. Make sure we operate in the context of the called function.
1447 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001448
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001449 // 2. Load the first argument into ebx and get rid of the rest (including the
1450 // receiver).
1451 {
1452 Label no_arguments, done;
1453 __ test(eax, eax);
1454 __ j(zero, &no_arguments, Label::kNear);
1455 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1456 __ jmp(&done, Label::kNear);
1457 __ bind(&no_arguments);
1458 __ Move(ebx, Smi::FromInt(0));
1459 __ bind(&done);
1460 __ PopReturnAddressTo(ecx);
1461 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1462 __ PushReturnAddressFrom(ecx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001463 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001464
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001465 // 3. Make sure ebx is a number.
1466 {
1467 Label done_convert;
1468 __ JumpIfSmi(ebx, &done_convert);
1469 __ CompareRoot(FieldOperand(ebx, HeapObject::kMapOffset),
1470 Heap::kHeapNumberMapRootIndex);
1471 __ j(equal, &done_convert);
1472 {
1473 FrameScope scope(masm, StackFrame::INTERNAL);
1474 __ Push(edi);
1475 __ Push(edx);
1476 __ Move(eax, ebx);
1477 ToNumberStub stub(masm->isolate());
1478 __ CallStub(&stub);
1479 __ Move(ebx, eax);
1480 __ Pop(edx);
1481 __ Pop(edi);
1482 }
1483 __ bind(&done_convert);
1484 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001485
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001486 // 4. Check if new target and constructor differ.
1487 Label new_object;
1488 __ cmp(edx, edi);
1489 __ j(not_equal, &new_object);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001490
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001491 // 5. Allocate a JSValue wrapper for the number.
1492 __ AllocateJSValue(eax, edi, ebx, ecx, &new_object);
1493 __ Ret();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001494
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001495 // 6. Fallback to the runtime to create new object.
1496 __ bind(&new_object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001497 {
1498 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001499 __ Push(ebx); // the first argument
Ben Murdoch097c5b22016-05-18 11:27:45 +01001500 FastNewObjectStub stub(masm->isolate());
1501 __ CallStub(&stub);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001502 __ Pop(FieldOperand(eax, JSValue::kValueOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001503 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001504 __ Ret();
1505}
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001506
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001507
1508// static
1509void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
1510 // ----------- S t a t e -------------
1511 // -- eax : number of arguments
1512 // -- edi : constructor function
1513 // -- esp[0] : return address
1514 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1515 // -- esp[(argc + 1) * 4] : receiver
1516 // -----------------------------------
1517
1518 // 1. Load the first argument into eax and get rid of the rest (including the
1519 // receiver).
1520 Label no_arguments;
1521 {
1522 __ test(eax, eax);
1523 __ j(zero, &no_arguments, Label::kNear);
1524 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1525 __ PopReturnAddressTo(ecx);
1526 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1527 __ PushReturnAddressFrom(ecx);
1528 __ mov(eax, ebx);
1529 }
1530
1531 // 2a. At least one argument, return eax if it's a string, otherwise
1532 // dispatch to appropriate conversion.
1533 Label to_string, symbol_descriptive_string;
1534 {
1535 __ JumpIfSmi(eax, &to_string, Label::kNear);
1536 STATIC_ASSERT(FIRST_NONSTRING_TYPE == SYMBOL_TYPE);
1537 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
1538 __ j(above, &to_string, Label::kNear);
1539 __ j(equal, &symbol_descriptive_string, Label::kNear);
1540 __ Ret();
1541 }
1542
1543 // 2b. No arguments, return the empty string (and pop the receiver).
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001544 __ bind(&no_arguments);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001545 {
1546 __ LoadRoot(eax, Heap::kempty_stringRootIndex);
1547 __ ret(1 * kPointerSize);
1548 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001549
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001550 // 3a. Convert eax to a string.
1551 __ bind(&to_string);
1552 {
1553 ToStringStub stub(masm->isolate());
1554 __ TailCallStub(&stub);
1555 }
1556
1557 // 3b. Convert symbol in eax to a string.
1558 __ bind(&symbol_descriptive_string);
1559 {
1560 __ PopReturnAddressTo(ecx);
1561 __ Push(eax);
1562 __ PushReturnAddressFrom(ecx);
1563 __ TailCallRuntime(Runtime::kSymbolDescriptiveString);
1564 }
1565}
1566
1567
1568// static
1569void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
1570 // ----------- S t a t e -------------
1571 // -- eax : number of arguments
1572 // -- edi : constructor function
1573 // -- edx : new target
1574 // -- esp[0] : return address
1575 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1576 // -- esp[(argc + 1) * 4] : receiver
1577 // -----------------------------------
1578
1579 // 1. Make sure we operate in the context of the called function.
1580 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1581
1582 // 2. Load the first argument into ebx and get rid of the rest (including the
1583 // receiver).
1584 {
1585 Label no_arguments, done;
1586 __ test(eax, eax);
1587 __ j(zero, &no_arguments, Label::kNear);
1588 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1589 __ jmp(&done, Label::kNear);
1590 __ bind(&no_arguments);
1591 __ LoadRoot(ebx, Heap::kempty_stringRootIndex);
1592 __ bind(&done);
1593 __ PopReturnAddressTo(ecx);
1594 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1595 __ PushReturnAddressFrom(ecx);
1596 }
1597
1598 // 3. Make sure ebx is a string.
1599 {
1600 Label convert, done_convert;
1601 __ JumpIfSmi(ebx, &convert, Label::kNear);
1602 __ CmpObjectType(ebx, FIRST_NONSTRING_TYPE, ecx);
1603 __ j(below, &done_convert);
1604 __ bind(&convert);
1605 {
1606 FrameScope scope(masm, StackFrame::INTERNAL);
1607 ToStringStub stub(masm->isolate());
1608 __ Push(edi);
1609 __ Push(edx);
1610 __ Move(eax, ebx);
1611 __ CallStub(&stub);
1612 __ Move(ebx, eax);
1613 __ Pop(edx);
1614 __ Pop(edi);
1615 }
1616 __ bind(&done_convert);
1617 }
1618
1619 // 4. Check if new target and constructor differ.
1620 Label new_object;
1621 __ cmp(edx, edi);
1622 __ j(not_equal, &new_object);
1623
1624 // 5. Allocate a JSValue wrapper for the string.
1625 __ AllocateJSValue(eax, edi, ebx, ecx, &new_object);
1626 __ Ret();
1627
1628 // 6. Fallback to the runtime to create new object.
1629 __ bind(&new_object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001630 {
1631 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001632 __ Push(ebx); // the first argument
Ben Murdoch097c5b22016-05-18 11:27:45 +01001633 FastNewObjectStub stub(masm->isolate());
1634 __ CallStub(&stub);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001635 __ Pop(FieldOperand(eax, JSValue::kValueOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001636 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001637 __ Ret();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001638}
1639
1640
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001641static void ArgumentsAdaptorStackCheck(MacroAssembler* masm,
1642 Label* stack_overflow) {
1643 // ----------- S t a t e -------------
1644 // -- eax : actual number of arguments
1645 // -- ebx : expected number of arguments
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001646 // -- edx : new target (passed through to callee)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001647 // -----------------------------------
1648 // Check the stack for overflow. We are not trying to catch
1649 // interruptions (e.g. debug break and preemption) here, so the "real stack
1650 // limit" is checked.
1651 ExternalReference real_stack_limit =
1652 ExternalReference::address_of_real_stack_limit(masm->isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001653 __ mov(edi, Operand::StaticVariable(real_stack_limit));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001654 // Make ecx the space we have left. The stack might already be overflowed
1655 // here which will cause ecx to become negative.
1656 __ mov(ecx, esp);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001657 __ sub(ecx, edi);
1658 // Make edi the space we need for the array when it is unrolled onto the
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001659 // stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001660 __ mov(edi, ebx);
1661 __ shl(edi, kPointerSizeLog2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001662 // Check if the arguments will overflow the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001663 __ cmp(ecx, edi);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001664 __ j(less_equal, stack_overflow); // Signed comparison.
1665}
1666
1667
Steve Blocka7e24c12009-10-30 11:49:00 +00001668static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1669 __ push(ebp);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001670 __ mov(ebp, esp);
Steve Blocka7e24c12009-10-30 11:49:00 +00001671
1672 // Store the arguments adaptor context sentinel.
1673 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
1674
1675 // Push the function on the stack.
1676 __ push(edi);
1677
Ben Murdoch257744e2011-11-30 15:57:28 +00001678 // Preserve the number of arguments on the stack. Must preserve eax,
1679 // ebx and ecx because these registers are used when copying the
Steve Blocka7e24c12009-10-30 11:49:00 +00001680 // arguments and the receiver.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001681 STATIC_ASSERT(kSmiTagSize == 1);
Ben Murdoch257744e2011-11-30 15:57:28 +00001682 __ lea(edi, Operand(eax, eax, times_1, kSmiTag));
1683 __ push(edi);
Steve Blocka7e24c12009-10-30 11:49:00 +00001684}
1685
1686
1687static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1688 // Retrieve the number of arguments from the stack.
1689 __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1690
1691 // Leave the frame.
1692 __ leave();
1693
1694 // Remove caller arguments from the stack.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001695 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001696 __ pop(ecx);
1697 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
1698 __ push(ecx);
1699}
1700
1701
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001702// static
1703void Builtins::Generate_Apply(MacroAssembler* masm) {
1704 // ----------- S t a t e -------------
1705 // -- eax : argumentsList
1706 // -- edi : target
1707 // -- edx : new.target (checked to be constructor or undefined)
1708 // -- esp[0] : return address.
1709 // -- esp[4] : thisArgument
1710 // -----------------------------------
1711
1712 // Create the list of arguments from the array-like argumentsList.
1713 {
1714 Label create_arguments, create_array, create_runtime, done_create;
1715 __ JumpIfSmi(eax, &create_runtime);
1716
1717 // Load the map of argumentsList into ecx.
1718 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
1719
1720 // Load native context into ebx.
1721 __ mov(ebx, NativeContextOperand());
1722
1723 // Check if argumentsList is an (unmodified) arguments object.
1724 __ cmp(ecx, ContextOperand(ebx, Context::SLOPPY_ARGUMENTS_MAP_INDEX));
1725 __ j(equal, &create_arguments);
1726 __ cmp(ecx, ContextOperand(ebx, Context::STRICT_ARGUMENTS_MAP_INDEX));
1727 __ j(equal, &create_arguments);
1728
1729 // Check if argumentsList is a fast JSArray.
1730 __ CmpInstanceType(ecx, JS_ARRAY_TYPE);
1731 __ j(equal, &create_array);
1732
1733 // Ask the runtime to create the list (actually a FixedArray).
1734 __ bind(&create_runtime);
1735 {
1736 FrameScope scope(masm, StackFrame::INTERNAL);
1737 __ Push(edi);
1738 __ Push(edx);
1739 __ Push(eax);
1740 __ CallRuntime(Runtime::kCreateListFromArrayLike);
1741 __ Pop(edx);
1742 __ Pop(edi);
1743 __ mov(ebx, FieldOperand(eax, FixedArray::kLengthOffset));
1744 __ SmiUntag(ebx);
1745 }
1746 __ jmp(&done_create);
1747
1748 // Try to create the list from an arguments object.
1749 __ bind(&create_arguments);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001750 __ mov(ebx, FieldOperand(eax, JSArgumentsObject::kLengthOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001751 __ mov(ecx, FieldOperand(eax, JSObject::kElementsOffset));
1752 __ cmp(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
1753 __ j(not_equal, &create_runtime);
1754 __ SmiUntag(ebx);
1755 __ mov(eax, ecx);
1756 __ jmp(&done_create);
1757
1758 // Try to create the list from a JSArray object.
1759 __ bind(&create_array);
1760 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
1761 __ DecodeField<Map::ElementsKindBits>(ecx);
1762 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
1763 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
1764 STATIC_ASSERT(FAST_ELEMENTS == 2);
1765 __ cmp(ecx, Immediate(FAST_ELEMENTS));
1766 __ j(above, &create_runtime);
1767 __ cmp(ecx, Immediate(FAST_HOLEY_SMI_ELEMENTS));
1768 __ j(equal, &create_runtime);
1769 __ mov(ebx, FieldOperand(eax, JSArray::kLengthOffset));
1770 __ SmiUntag(ebx);
1771 __ mov(eax, FieldOperand(eax, JSArray::kElementsOffset));
1772
1773 __ bind(&done_create);
1774 }
1775
1776 // Check for stack overflow.
1777 {
1778 // Check the stack for overflow. We are not trying to catch interruptions
1779 // (i.e. debug break and preemption) here, so check the "real stack limit".
1780 Label done;
1781 ExternalReference real_stack_limit =
1782 ExternalReference::address_of_real_stack_limit(masm->isolate());
1783 __ mov(ecx, Operand::StaticVariable(real_stack_limit));
1784 // Make ecx the space we have left. The stack might already be overflowed
1785 // here which will cause ecx to become negative.
1786 __ neg(ecx);
1787 __ add(ecx, esp);
1788 __ sar(ecx, kPointerSizeLog2);
1789 // Check if the arguments will overflow the stack.
1790 __ cmp(ecx, ebx);
1791 __ j(greater, &done, Label::kNear); // Signed comparison.
1792 __ TailCallRuntime(Runtime::kThrowStackOverflow);
1793 __ bind(&done);
1794 }
1795
1796 // ----------- S t a t e -------------
1797 // -- edi : target
1798 // -- eax : args (a FixedArray built from argumentsList)
1799 // -- ebx : len (number of elements to push from args)
1800 // -- edx : new.target (checked to be constructor or undefined)
1801 // -- esp[0] : return address.
1802 // -- esp[4] : thisArgument
1803 // -----------------------------------
1804
1805 // Push arguments onto the stack (thisArgument is already on the stack).
1806 {
1807 __ movd(xmm0, edx);
1808 __ PopReturnAddressTo(edx);
1809 __ Move(ecx, Immediate(0));
1810 Label done, loop;
1811 __ bind(&loop);
1812 __ cmp(ecx, ebx);
1813 __ j(equal, &done, Label::kNear);
1814 __ Push(
1815 FieldOperand(eax, ecx, times_pointer_size, FixedArray::kHeaderSize));
1816 __ inc(ecx);
1817 __ jmp(&loop);
1818 __ bind(&done);
1819 __ PushReturnAddressFrom(edx);
1820 __ movd(edx, xmm0);
1821 __ Move(eax, ebx);
1822 }
1823
1824 // Dispatch to Call or Construct depending on whether new.target is undefined.
1825 {
1826 __ CompareRoot(edx, Heap::kUndefinedValueRootIndex);
1827 __ j(equal, masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1828 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
1829 }
1830}
1831
Ben Murdoch097c5b22016-05-18 11:27:45 +01001832namespace {
1833
1834// Drops top JavaScript frame and an arguments adaptor frame below it (if
1835// present) preserving all the arguments prepared for current call.
1836// Does nothing if debugger is currently active.
1837// ES6 14.6.3. PrepareForTailCall
1838//
1839// Stack structure for the function g() tail calling f():
1840//
1841// ------- Caller frame: -------
1842// | ...
1843// | g()'s arg M
1844// | ...
1845// | g()'s arg 1
1846// | g()'s receiver arg
1847// | g()'s caller pc
1848// ------- g()'s frame: -------
1849// | g()'s caller fp <- fp
1850// | g()'s context
1851// | function pointer: g
1852// | -------------------------
1853// | ...
1854// | ...
1855// | f()'s arg N
1856// | ...
1857// | f()'s arg 1
1858// | f()'s receiver arg
1859// | f()'s caller pc <- sp
1860// ----------------------
1861//
1862void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
1863 Register scratch1, Register scratch2,
1864 Register scratch3) {
1865 DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
1866 Comment cmnt(masm, "[ PrepareForTailCall");
1867
1868 // Prepare for tail call only if the debugger is not active.
1869 Label done;
1870 ExternalReference debug_is_active =
1871 ExternalReference::debug_is_active_address(masm->isolate());
1872 __ movzx_b(scratch1, Operand::StaticVariable(debug_is_active));
1873 __ cmp(scratch1, Immediate(0));
1874 __ j(not_equal, &done, Label::kNear);
1875
1876 // Drop possible interpreter handler/stub frame.
1877 {
1878 Label no_interpreter_frame;
1879 __ cmp(Operand(ebp, StandardFrameConstants::kMarkerOffset),
1880 Immediate(Smi::FromInt(StackFrame::STUB)));
1881 __ j(not_equal, &no_interpreter_frame, Label::kNear);
1882 __ mov(ebp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
1883 __ bind(&no_interpreter_frame);
1884 }
1885
1886 // Check if next frame is an arguments adaptor frame.
1887 Label no_arguments_adaptor, formal_parameter_count_loaded;
1888 __ mov(scratch2, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
1889 __ cmp(Operand(scratch2, StandardFrameConstants::kContextOffset),
1890 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
1891 __ j(not_equal, &no_arguments_adaptor, Label::kNear);
1892
1893 // Drop arguments adaptor frame and load arguments count.
1894 __ mov(ebp, scratch2);
1895 __ mov(scratch1, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1896 __ SmiUntag(scratch1);
1897 __ jmp(&formal_parameter_count_loaded, Label::kNear);
1898
1899 __ bind(&no_arguments_adaptor);
1900 // Load caller's formal parameter count
1901 __ mov(scratch1, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1902 __ mov(scratch1,
1903 FieldOperand(scratch1, JSFunction::kSharedFunctionInfoOffset));
1904 __ mov(
1905 scratch1,
1906 FieldOperand(scratch1, SharedFunctionInfo::kFormalParameterCountOffset));
1907 __ SmiUntag(scratch1);
1908
1909 __ bind(&formal_parameter_count_loaded);
1910
1911 // Calculate the destination address where we will put the return address
1912 // after we drop current frame.
1913 Register new_sp_reg = scratch2;
1914 __ sub(scratch1, args_reg);
1915 __ lea(new_sp_reg, Operand(ebp, scratch1, times_pointer_size,
1916 StandardFrameConstants::kCallerPCOffset));
1917
1918 if (FLAG_debug_code) {
1919 __ cmp(esp, new_sp_reg);
1920 __ Check(below, kStackAccessBelowStackPointer);
1921 }
1922
1923 // Copy receiver and return address as well.
1924 Register count_reg = scratch1;
1925 __ lea(count_reg, Operand(args_reg, 2));
1926
1927 // Copy return address from caller's frame to current frame's return address
1928 // to avoid its trashing and let the following loop copy it to the right
1929 // place.
1930 Register tmp_reg = scratch3;
1931 __ mov(tmp_reg, Operand(ebp, StandardFrameConstants::kCallerPCOffset));
1932 __ mov(Operand(esp, 0), tmp_reg);
1933
1934 // Restore caller's frame pointer now as it could be overwritten by
1935 // the copying loop.
1936 __ mov(ebp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
1937
1938 Operand src(esp, count_reg, times_pointer_size, 0);
1939 Operand dst(new_sp_reg, count_reg, times_pointer_size, 0);
1940
1941 // Now copy callee arguments to the caller frame going backwards to avoid
1942 // callee arguments corruption (source and destination areas could overlap).
1943 Label loop, entry;
1944 __ jmp(&entry, Label::kNear);
1945 __ bind(&loop);
1946 __ dec(count_reg);
1947 __ mov(tmp_reg, src);
1948 __ mov(dst, tmp_reg);
1949 __ bind(&entry);
1950 __ cmp(count_reg, Immediate(0));
1951 __ j(not_equal, &loop, Label::kNear);
1952
1953 // Leave current frame.
1954 __ mov(esp, new_sp_reg);
1955
1956 __ bind(&done);
1957}
1958} // namespace
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001959
1960// static
1961void Builtins::Generate_CallFunction(MacroAssembler* masm,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001962 ConvertReceiverMode mode,
1963 TailCallMode tail_call_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001964 // ----------- S t a t e -------------
1965 // -- eax : the number of arguments (not including the receiver)
1966 // -- edi : the function to call (checked to be a JSFunction)
1967 // -----------------------------------
1968 __ AssertFunction(edi);
1969
1970 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
1971 // Check that the function is not a "classConstructor".
1972 Label class_constructor;
1973 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1974 __ test_b(FieldOperand(edx, SharedFunctionInfo::kFunctionKindByteOffset),
1975 SharedFunctionInfo::kClassConstructorBitsWithinByte);
1976 __ j(not_zero, &class_constructor);
1977
1978 // Enter the context of the function; ToObject has to run in the function
1979 // context, and we also need to take the global proxy from the function
1980 // context in case of conversion.
1981 STATIC_ASSERT(SharedFunctionInfo::kNativeByteOffset ==
1982 SharedFunctionInfo::kStrictModeByteOffset);
1983 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1984 // We need to convert the receiver for non-native sloppy mode functions.
1985 Label done_convert;
1986 __ test_b(FieldOperand(edx, SharedFunctionInfo::kNativeByteOffset),
1987 (1 << SharedFunctionInfo::kNativeBitWithinByte) |
1988 (1 << SharedFunctionInfo::kStrictModeBitWithinByte));
1989 __ j(not_zero, &done_convert);
1990 {
1991 // ----------- S t a t e -------------
1992 // -- eax : the number of arguments (not including the receiver)
1993 // -- edx : the shared function info.
1994 // -- edi : the function to call (checked to be a JSFunction)
1995 // -- esi : the function context.
1996 // -----------------------------------
1997
1998 if (mode == ConvertReceiverMode::kNullOrUndefined) {
1999 // Patch receiver to global proxy.
2000 __ LoadGlobalProxy(ecx);
2001 } else {
2002 Label convert_to_object, convert_receiver;
2003 __ mov(ecx, Operand(esp, eax, times_pointer_size, kPointerSize));
2004 __ JumpIfSmi(ecx, &convert_to_object, Label::kNear);
2005 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
2006 __ CmpObjectType(ecx, FIRST_JS_RECEIVER_TYPE, ebx);
2007 __ j(above_equal, &done_convert);
2008 if (mode != ConvertReceiverMode::kNotNullOrUndefined) {
2009 Label convert_global_proxy;
2010 __ JumpIfRoot(ecx, Heap::kUndefinedValueRootIndex,
2011 &convert_global_proxy, Label::kNear);
2012 __ JumpIfNotRoot(ecx, Heap::kNullValueRootIndex, &convert_to_object,
2013 Label::kNear);
2014 __ bind(&convert_global_proxy);
2015 {
2016 // Patch receiver to global proxy.
2017 __ LoadGlobalProxy(ecx);
2018 }
2019 __ jmp(&convert_receiver);
2020 }
2021 __ bind(&convert_to_object);
2022 {
2023 // Convert receiver using ToObject.
2024 // TODO(bmeurer): Inline the allocation here to avoid building the frame
2025 // in the fast case? (fall back to AllocateInNewSpace?)
2026 FrameScope scope(masm, StackFrame::INTERNAL);
2027 __ SmiTag(eax);
2028 __ Push(eax);
2029 __ Push(edi);
2030 __ mov(eax, ecx);
2031 ToObjectStub stub(masm->isolate());
2032 __ CallStub(&stub);
2033 __ mov(ecx, eax);
2034 __ Pop(edi);
2035 __ Pop(eax);
2036 __ SmiUntag(eax);
2037 }
2038 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2039 __ bind(&convert_receiver);
2040 }
2041 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ecx);
2042 }
2043 __ bind(&done_convert);
2044
2045 // ----------- S t a t e -------------
2046 // -- eax : the number of arguments (not including the receiver)
2047 // -- edx : the shared function info.
2048 // -- edi : the function to call (checked to be a JSFunction)
2049 // -- esi : the function context.
2050 // -----------------------------------
2051
Ben Murdoch097c5b22016-05-18 11:27:45 +01002052 if (tail_call_mode == TailCallMode::kAllow) {
2053 PrepareForTailCall(masm, eax, ebx, ecx, edx);
2054 // Reload shared function info.
2055 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2056 }
2057
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002058 __ mov(ebx,
2059 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
2060 __ SmiUntag(ebx);
2061 ParameterCount actual(eax);
2062 ParameterCount expected(ebx);
2063 __ InvokeFunctionCode(edi, no_reg, expected, actual, JUMP_FUNCTION,
2064 CheckDebugStepCallWrapper());
2065 // The function is a "classConstructor", need to raise an exception.
2066 __ bind(&class_constructor);
2067 {
2068 FrameScope frame(masm, StackFrame::INTERNAL);
2069 __ push(edi);
2070 __ CallRuntime(Runtime::kThrowConstructorNonCallableError);
2071 }
2072}
2073
2074
2075namespace {
2076
2077void Generate_PushBoundArguments(MacroAssembler* masm) {
2078 // ----------- S t a t e -------------
2079 // -- eax : the number of arguments (not including the receiver)
2080 // -- edx : new.target (only in case of [[Construct]])
2081 // -- edi : target (checked to be a JSBoundFunction)
2082 // -----------------------------------
2083
2084 // Load [[BoundArguments]] into ecx and length of that into ebx.
2085 Label no_bound_arguments;
2086 __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset));
2087 __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
2088 __ SmiUntag(ebx);
2089 __ test(ebx, ebx);
2090 __ j(zero, &no_bound_arguments);
2091 {
2092 // ----------- S t a t e -------------
2093 // -- eax : the number of arguments (not including the receiver)
2094 // -- edx : new.target (only in case of [[Construct]])
2095 // -- edi : target (checked to be a JSBoundFunction)
2096 // -- ecx : the [[BoundArguments]] (implemented as FixedArray)
2097 // -- ebx : the number of [[BoundArguments]]
2098 // -----------------------------------
2099
2100 // Reserve stack space for the [[BoundArguments]].
2101 {
2102 Label done;
2103 __ lea(ecx, Operand(ebx, times_pointer_size, 0));
2104 __ sub(esp, ecx);
2105 // Check the stack for overflow. We are not trying to catch interruptions
2106 // (i.e. debug break and preemption) here, so check the "real stack
2107 // limit".
2108 __ CompareRoot(esp, ecx, Heap::kRealStackLimitRootIndex);
2109 __ j(greater, &done, Label::kNear); // Signed comparison.
2110 // Restore the stack pointer.
2111 __ lea(esp, Operand(esp, ebx, times_pointer_size, 0));
2112 {
2113 FrameScope scope(masm, StackFrame::MANUAL);
2114 __ EnterFrame(StackFrame::INTERNAL);
2115 __ CallRuntime(Runtime::kThrowStackOverflow);
2116 }
2117 __ bind(&done);
2118 }
2119
2120 // Adjust effective number of arguments to include return address.
2121 __ inc(eax);
2122
2123 // Relocate arguments and return address down the stack.
2124 {
2125 Label loop;
2126 __ Set(ecx, 0);
2127 __ lea(ebx, Operand(esp, ebx, times_pointer_size, 0));
2128 __ bind(&loop);
2129 __ movd(xmm0, Operand(ebx, ecx, times_pointer_size, 0));
2130 __ movd(Operand(esp, ecx, times_pointer_size, 0), xmm0);
2131 __ inc(ecx);
2132 __ cmp(ecx, eax);
2133 __ j(less, &loop);
2134 }
2135
2136 // Copy [[BoundArguments]] to the stack (below the arguments).
2137 {
2138 Label loop;
2139 __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset));
2140 __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
2141 __ SmiUntag(ebx);
2142 __ bind(&loop);
2143 __ dec(ebx);
2144 __ movd(xmm0, FieldOperand(ecx, ebx, times_pointer_size,
2145 FixedArray::kHeaderSize));
2146 __ movd(Operand(esp, eax, times_pointer_size, 0), xmm0);
2147 __ lea(eax, Operand(eax, 1));
2148 __ j(greater, &loop);
2149 }
2150
2151 // Adjust effective number of arguments (eax contains the number of
2152 // arguments from the call plus return address plus the number of
2153 // [[BoundArguments]]), so we need to subtract one for the return address.
2154 __ dec(eax);
2155 }
2156 __ bind(&no_bound_arguments);
2157}
2158
2159} // namespace
2160
2161
2162// static
Ben Murdoch097c5b22016-05-18 11:27:45 +01002163void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm,
2164 TailCallMode tail_call_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002165 // ----------- S t a t e -------------
2166 // -- eax : the number of arguments (not including the receiver)
2167 // -- edi : the function to call (checked to be a JSBoundFunction)
2168 // -----------------------------------
2169 __ AssertBoundFunction(edi);
2170
Ben Murdoch097c5b22016-05-18 11:27:45 +01002171 if (tail_call_mode == TailCallMode::kAllow) {
2172 PrepareForTailCall(masm, eax, ebx, ecx, edx);
2173 }
2174
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002175 // Patch the receiver to [[BoundThis]].
2176 __ mov(ebx, FieldOperand(edi, JSBoundFunction::kBoundThisOffset));
2177 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ebx);
2178
2179 // Push the [[BoundArguments]] onto the stack.
2180 Generate_PushBoundArguments(masm);
2181
2182 // Call the [[BoundTargetFunction]] via the Call builtin.
2183 __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2184 __ mov(ecx, Operand::StaticVariable(ExternalReference(
2185 Builtins::kCall_ReceiverIsAny, masm->isolate())));
2186 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2187 __ jmp(ecx);
2188}
2189
2190
2191// static
Ben Murdoch097c5b22016-05-18 11:27:45 +01002192void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
2193 TailCallMode tail_call_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002194 // ----------- S t a t e -------------
2195 // -- eax : the number of arguments (not including the receiver)
2196 // -- edi : the target to call (can be any Object).
2197 // -----------------------------------
2198
2199 Label non_callable, non_function, non_smi;
2200 __ JumpIfSmi(edi, &non_callable);
2201 __ bind(&non_smi);
2202 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002203 __ j(equal, masm->isolate()->builtins()->CallFunction(mode, tail_call_mode),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002204 RelocInfo::CODE_TARGET);
2205 __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002206 __ j(equal, masm->isolate()->builtins()->CallBoundFunction(tail_call_mode),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002207 RelocInfo::CODE_TARGET);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002208
2209 // Check if target has a [[Call]] internal method.
2210 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsCallable);
2211 __ j(zero, &non_callable);
2212
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002213 __ CmpInstanceType(ecx, JS_PROXY_TYPE);
2214 __ j(not_equal, &non_function);
2215
Ben Murdoch097c5b22016-05-18 11:27:45 +01002216 // 0. Prepare for tail call if necessary.
2217 if (tail_call_mode == TailCallMode::kAllow) {
2218 PrepareForTailCall(masm, eax, ebx, ecx, edx);
2219 }
2220
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002221 // 1. Runtime fallback for Proxy [[Call]].
2222 __ PopReturnAddressTo(ecx);
2223 __ Push(edi);
2224 __ PushReturnAddressFrom(ecx);
2225 // Increase the arguments size to include the pushed function and the
2226 // existing receiver on the stack.
2227 __ add(eax, Immediate(2));
2228 // Tail-call to the runtime.
2229 __ JumpToExternalReference(
2230 ExternalReference(Runtime::kJSProxyCall, masm->isolate()));
2231
2232 // 2. Call to something else, which might have a [[Call]] internal method (if
2233 // not we raise an exception).
2234 __ bind(&non_function);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002235 // Overwrite the original receiver with the (original) target.
2236 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
2237 // Let the "call_as_function_delegate" take care of the rest.
2238 __ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, edi);
2239 __ Jump(masm->isolate()->builtins()->CallFunction(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002240 ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002241 RelocInfo::CODE_TARGET);
2242
2243 // 3. Call to something that is not callable.
2244 __ bind(&non_callable);
2245 {
2246 FrameScope scope(masm, StackFrame::INTERNAL);
2247 __ Push(edi);
2248 __ CallRuntime(Runtime::kThrowCalledNonCallable);
2249 }
2250}
2251
2252
2253// static
2254void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
2255 // ----------- S t a t e -------------
2256 // -- eax : the number of arguments (not including the receiver)
2257 // -- edx : the new target (checked to be a constructor)
2258 // -- edi : the constructor to call (checked to be a JSFunction)
2259 // -----------------------------------
2260 __ AssertFunction(edi);
2261
2262 // Calling convention for function specific ConstructStubs require
2263 // ebx to contain either an AllocationSite or undefined.
2264 __ LoadRoot(ebx, Heap::kUndefinedValueRootIndex);
2265
2266 // Tail call to the function-specific construct stub (still in the caller
2267 // context at this point).
2268 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2269 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset));
2270 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2271 __ jmp(ecx);
2272}
2273
2274
2275// static
2276void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) {
2277 // ----------- S t a t e -------------
2278 // -- eax : the number of arguments (not including the receiver)
2279 // -- edx : the new target (checked to be a constructor)
2280 // -- edi : the constructor to call (checked to be a JSBoundFunction)
2281 // -----------------------------------
2282 __ AssertBoundFunction(edi);
2283
2284 // Push the [[BoundArguments]] onto the stack.
2285 Generate_PushBoundArguments(masm);
2286
2287 // Patch new.target to [[BoundTargetFunction]] if new.target equals target.
2288 {
2289 Label done;
2290 __ cmp(edi, edx);
2291 __ j(not_equal, &done, Label::kNear);
2292 __ mov(edx, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2293 __ bind(&done);
2294 }
2295
2296 // Construct the [[BoundTargetFunction]] via the Construct builtin.
2297 __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2298 __ mov(ecx, Operand::StaticVariable(
2299 ExternalReference(Builtins::kConstruct, masm->isolate())));
2300 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2301 __ jmp(ecx);
2302}
2303
2304
2305// static
2306void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
2307 // ----------- S t a t e -------------
2308 // -- eax : the number of arguments (not including the receiver)
2309 // -- edi : the constructor to call (checked to be a JSProxy)
2310 // -- edx : the new target (either the same as the constructor or
2311 // the JSFunction on which new was invoked initially)
2312 // -----------------------------------
2313
2314 // Call into the Runtime for Proxy [[Construct]].
2315 __ PopReturnAddressTo(ecx);
2316 __ Push(edi);
2317 __ Push(edx);
2318 __ PushReturnAddressFrom(ecx);
2319 // Include the pushed new_target, constructor and the receiver.
2320 __ add(eax, Immediate(3));
2321 // Tail-call to the runtime.
2322 __ JumpToExternalReference(
2323 ExternalReference(Runtime::kJSProxyConstruct, masm->isolate()));
2324}
2325
2326
2327// static
2328void Builtins::Generate_Construct(MacroAssembler* masm) {
2329 // ----------- S t a t e -------------
2330 // -- eax : the number of arguments (not including the receiver)
2331 // -- edx : the new target (either the same as the constructor or
2332 // the JSFunction on which new was invoked initially)
2333 // -- edi : the constructor to call (can be any Object)
2334 // -----------------------------------
2335
2336 // Check if target is a Smi.
2337 Label non_constructor;
2338 __ JumpIfSmi(edi, &non_constructor, Label::kNear);
2339
2340 // Dispatch based on instance type.
2341 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
2342 __ j(equal, masm->isolate()->builtins()->ConstructFunction(),
2343 RelocInfo::CODE_TARGET);
2344
2345 // Check if target has a [[Construct]] internal method.
2346 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsConstructor);
2347 __ j(zero, &non_constructor, Label::kNear);
2348
2349 // Only dispatch to bound functions after checking whether they are
2350 // constructors.
2351 __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE);
2352 __ j(equal, masm->isolate()->builtins()->ConstructBoundFunction(),
2353 RelocInfo::CODE_TARGET);
2354
2355 // Only dispatch to proxies after checking whether they are constructors.
2356 __ CmpInstanceType(ecx, JS_PROXY_TYPE);
2357 __ j(equal, masm->isolate()->builtins()->ConstructProxy(),
2358 RelocInfo::CODE_TARGET);
2359
2360 // Called Construct on an exotic Object with a [[Construct]] internal method.
2361 {
2362 // Overwrite the original receiver with the (original) target.
2363 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
2364 // Let the "call_as_constructor_delegate" take care of the rest.
2365 __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, edi);
2366 __ Jump(masm->isolate()->builtins()->CallFunction(),
2367 RelocInfo::CODE_TARGET);
2368 }
2369
2370 // Called Construct on an Object that doesn't have a [[Construct]] internal
2371 // method.
2372 __ bind(&non_constructor);
2373 __ Jump(masm->isolate()->builtins()->ConstructedNonConstructable(),
2374 RelocInfo::CODE_TARGET);
2375}
2376
2377
Steve Blocka7e24c12009-10-30 11:49:00 +00002378void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
2379 // ----------- S t a t e -------------
2380 // -- eax : actual number of arguments
2381 // -- ebx : expected number of arguments
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002382 // -- edx : new target (passed through to callee)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002383 // -- edi : function (passed through to callee)
Steve Blocka7e24c12009-10-30 11:49:00 +00002384 // -----------------------------------
2385
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002386 Label invoke, dont_adapt_arguments, stack_overflow;
Steve Block44f0eee2011-05-26 01:26:41 +01002387 __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00002388
2389 Label enough, too_few;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002390 __ cmp(eax, ebx);
Steve Blocka7e24c12009-10-30 11:49:00 +00002391 __ j(less, &too_few);
2392 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
2393 __ j(equal, &dont_adapt_arguments);
2394
2395 { // Enough parameters: Actual >= expected.
2396 __ bind(&enough);
2397 EnterArgumentsAdaptorFrame(masm);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002398 ArgumentsAdaptorStackCheck(masm, &stack_overflow);
Steve Blocka7e24c12009-10-30 11:49:00 +00002399
2400 // Copy receiver and all expected arguments.
2401 const int offset = StandardFrameConstants::kCallerSPOffset;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002402 __ lea(edi, Operand(ebp, eax, times_4, offset));
2403 __ mov(eax, -1); // account for receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002404
2405 Label copy;
2406 __ bind(&copy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002407 __ inc(eax);
2408 __ push(Operand(edi, 0));
2409 __ sub(edi, Immediate(kPointerSize));
2410 __ cmp(eax, ebx);
Steve Blocka7e24c12009-10-30 11:49:00 +00002411 __ j(less, &copy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002412 // eax now contains the expected number of arguments.
Steve Blocka7e24c12009-10-30 11:49:00 +00002413 __ jmp(&invoke);
2414 }
2415
2416 { // Too few parameters: Actual < expected.
2417 __ bind(&too_few);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002418
2419 // If the function is strong we need to throw an error.
2420 Label no_strong_error;
2421 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2422 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrongModeByteOffset),
2423 1 << SharedFunctionInfo::kStrongModeBitWithinByte);
2424 __ j(equal, &no_strong_error, Label::kNear);
2425
2426 // What we really care about is the required number of arguments.
2427 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kLengthOffset));
2428 __ SmiUntag(ecx);
2429 __ cmp(eax, ecx);
2430 __ j(greater_equal, &no_strong_error, Label::kNear);
2431
2432 {
2433 FrameScope frame(masm, StackFrame::MANUAL);
2434 EnterArgumentsAdaptorFrame(masm);
2435 __ CallRuntime(Runtime::kThrowStrongModeTooFewArguments);
2436 }
2437
2438 __ bind(&no_strong_error);
Steve Blocka7e24c12009-10-30 11:49:00 +00002439 EnterArgumentsAdaptorFrame(masm);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002440 ArgumentsAdaptorStackCheck(masm, &stack_overflow);
2441
2442 // Remember expected arguments in ecx.
2443 __ mov(ecx, ebx);
Steve Blocka7e24c12009-10-30 11:49:00 +00002444
2445 // Copy receiver and all actual arguments.
2446 const int offset = StandardFrameConstants::kCallerSPOffset;
2447 __ lea(edi, Operand(ebp, eax, times_4, offset));
Ben Murdoch257744e2011-11-30 15:57:28 +00002448 // ebx = expected - actual.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002449 __ sub(ebx, eax);
Ben Murdoch257744e2011-11-30 15:57:28 +00002450 // eax = -actual - 1
2451 __ neg(eax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002452 __ sub(eax, Immediate(1));
Steve Blocka7e24c12009-10-30 11:49:00 +00002453
2454 Label copy;
2455 __ bind(&copy);
Ben Murdoch257744e2011-11-30 15:57:28 +00002456 __ inc(eax);
Steve Blocka7e24c12009-10-30 11:49:00 +00002457 __ push(Operand(edi, 0));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002458 __ sub(edi, Immediate(kPointerSize));
2459 __ test(eax, eax);
Ben Murdoch257744e2011-11-30 15:57:28 +00002460 __ j(not_zero, &copy);
Steve Blocka7e24c12009-10-30 11:49:00 +00002461
2462 // Fill remaining expected arguments with undefined values.
2463 Label fill;
2464 __ bind(&fill);
Ben Murdoch257744e2011-11-30 15:57:28 +00002465 __ inc(eax);
Steve Block44f0eee2011-05-26 01:26:41 +01002466 __ push(Immediate(masm->isolate()->factory()->undefined_value()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002467 __ cmp(eax, ebx);
Steve Blocka7e24c12009-10-30 11:49:00 +00002468 __ j(less, &fill);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002469
2470 // Restore expected arguments.
2471 __ mov(eax, ecx);
Steve Blocka7e24c12009-10-30 11:49:00 +00002472 }
2473
2474 // Call the entry point.
2475 __ bind(&invoke);
Ben Murdoch257744e2011-11-30 15:57:28 +00002476 // Restore function pointer.
2477 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002478 // eax : expected number of arguments
2479 // edx : new target (passed through to callee)
2480 // edi : function (passed through to callee)
2481 __ mov(ecx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
2482 __ call(ecx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002483
2484 // Store offset of return address for deoptimizer.
2485 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01002486
Steve Blocka7e24c12009-10-30 11:49:00 +00002487 // Leave frame and return.
2488 LeaveArgumentsAdaptorFrame(masm);
2489 __ ret(0);
2490
2491 // -------------------------------------------
2492 // Dont adapt arguments.
2493 // -------------------------------------------
2494 __ bind(&dont_adapt_arguments);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002495 __ mov(ecx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
2496 __ jmp(ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002497
2498 __ bind(&stack_overflow);
2499 {
2500 FrameScope frame(masm, StackFrame::MANUAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002501 __ CallRuntime(Runtime::kThrowStackOverflow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002502 __ int3();
2503 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002504}
2505
2506
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002507static void CompatibleReceiverCheck(MacroAssembler* masm, Register receiver,
2508 Register function_template_info,
2509 Register scratch0, Register scratch1,
2510 Label* receiver_check_failed) {
2511 // If there is no signature, return the holder.
2512 __ CompareRoot(FieldOperand(function_template_info,
2513 FunctionTemplateInfo::kSignatureOffset),
2514 Heap::kUndefinedValueRootIndex);
2515 Label receiver_check_passed;
2516 __ j(equal, &receiver_check_passed, Label::kNear);
2517
2518 // Walk the prototype chain.
2519 __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
2520 Label prototype_loop_start;
2521 __ bind(&prototype_loop_start);
2522
2523 // Get the constructor, if any.
2524 __ GetMapConstructor(scratch0, scratch0, scratch1);
2525 __ CmpInstanceType(scratch1, JS_FUNCTION_TYPE);
2526 Label next_prototype;
2527 __ j(not_equal, &next_prototype, Label::kNear);
2528
2529 // Get the constructor's signature.
2530 __ mov(scratch0,
2531 FieldOperand(scratch0, JSFunction::kSharedFunctionInfoOffset));
2532 __ mov(scratch0,
2533 FieldOperand(scratch0, SharedFunctionInfo::kFunctionDataOffset));
2534
2535 // Loop through the chain of inheriting function templates.
2536 Label function_template_loop;
2537 __ bind(&function_template_loop);
2538
2539 // If the signatures match, we have a compatible receiver.
2540 __ cmp(scratch0, FieldOperand(function_template_info,
2541 FunctionTemplateInfo::kSignatureOffset));
2542 __ j(equal, &receiver_check_passed, Label::kNear);
2543
2544 // If the current type is not a FunctionTemplateInfo, load the next prototype
2545 // in the chain.
2546 __ JumpIfSmi(scratch0, &next_prototype, Label::kNear);
2547 __ CmpObjectType(scratch0, FUNCTION_TEMPLATE_INFO_TYPE, scratch1);
2548 __ j(not_equal, &next_prototype, Label::kNear);
2549
2550 // Otherwise load the parent function template and iterate.
2551 __ mov(scratch0,
2552 FieldOperand(scratch0, FunctionTemplateInfo::kParentTemplateOffset));
2553 __ jmp(&function_template_loop, Label::kNear);
2554
2555 // Load the next prototype.
2556 __ bind(&next_prototype);
2557 __ mov(receiver, FieldOperand(receiver, HeapObject::kMapOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002558 __ test(FieldOperand(receiver, Map::kBitField3Offset),
2559 Immediate(Map::HasHiddenPrototype::kMask));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002560 __ j(zero, receiver_check_failed);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002561
2562 __ mov(receiver, FieldOperand(receiver, Map::kPrototypeOffset));
2563 __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002564 // Iterate.
2565 __ jmp(&prototype_loop_start, Label::kNear);
2566
2567 __ bind(&receiver_check_passed);
2568}
2569
2570
2571void Builtins::Generate_HandleFastApiCall(MacroAssembler* masm) {
2572 // ----------- S t a t e -------------
2573 // -- eax : number of arguments (not including the receiver)
2574 // -- edi : callee
2575 // -- esi : context
2576 // -- esp[0] : return address
2577 // -- esp[4] : last argument
2578 // -- ...
2579 // -- esp[eax * 4] : first argument
2580 // -- esp[(eax + 1) * 4] : receiver
2581 // -----------------------------------
2582
2583 // Load the FunctionTemplateInfo.
2584 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2585 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kFunctionDataOffset));
2586
2587 // Do the compatible receiver check.
2588 Label receiver_check_failed;
2589 __ mov(ecx, Operand(esp, eax, times_pointer_size, kPCOnStackSize));
2590 __ Push(eax);
2591 CompatibleReceiverCheck(masm, ecx, ebx, edx, eax, &receiver_check_failed);
2592 __ Pop(eax);
2593 // Get the callback offset from the FunctionTemplateInfo, and jump to the
2594 // beginning of the code.
2595 __ mov(edx, FieldOperand(ebx, FunctionTemplateInfo::kCallCodeOffset));
2596 __ mov(edx, FieldOperand(edx, CallHandlerInfo::kFastHandlerOffset));
2597 __ add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag));
2598 __ jmp(edx);
2599
2600 // Compatible receiver check failed: pop return address, arguments and
2601 // receiver and throw an Illegal Invocation exception.
2602 __ bind(&receiver_check_failed);
2603 __ Pop(eax);
2604 __ PopReturnAddressTo(ebx);
2605 __ lea(eax, Operand(eax, times_pointer_size, 1 * kPointerSize));
2606 __ add(esp, eax);
2607 __ PushReturnAddressFrom(ebx);
2608 {
2609 FrameScope scope(masm, StackFrame::INTERNAL);
2610 __ TailCallRuntime(Runtime::kThrowIllegalInvocation);
2611 }
2612}
2613
2614
Ben Murdochb0fe1622011-05-05 13:52:32 +01002615void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002616 // Lookup the function in the JavaScript frame.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002617 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002618 {
2619 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002620 // Pass function as argument.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002621 __ push(eax);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002622 __ CallRuntime(Runtime::kCompileForOnStackReplacement);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002623 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01002624
Ben Murdoch257744e2011-11-30 15:57:28 +00002625 Label skip;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002626 // If the code object is null, just return to the unoptimized code.
2627 __ cmp(eax, Immediate(0));
Ben Murdoch257744e2011-11-30 15:57:28 +00002628 __ j(not_equal, &skip, Label::kNear);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002629 __ ret(0);
2630
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002631 __ bind(&skip);
2632
2633 // Load deoptimization data from the code object.
2634 __ mov(ebx, Operand(eax, Code::kDeoptimizationDataOffset - kHeapObjectTag));
2635
2636 // Load the OSR entrypoint offset from the deoptimization data.
2637 __ mov(ebx, Operand(ebx, FixedArray::OffsetOfElementAt(
2638 DeoptimizationInputData::kOsrPcOffsetIndex) - kHeapObjectTag));
2639 __ SmiUntag(ebx);
2640
2641 // Compute the target address = code_obj + header_size + osr_offset
2642 __ lea(eax, Operand(eax, ebx, times_1, Code::kHeaderSize - kHeapObjectTag));
2643
2644 // Overwrite the return address on the stack.
2645 __ mov(Operand(esp, 0), eax);
2646
2647 // And "return" to the OSR entry point of the function.
2648 __ ret(0);
2649}
2650
2651
2652void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
2653 // We check the stack limit as indicator that recompilation might be done.
Ben Murdoch257744e2011-11-30 15:57:28 +00002654 Label ok;
Ben Murdochb0fe1622011-05-05 13:52:32 +01002655 ExternalReference stack_limit =
Steve Block44f0eee2011-05-26 01:26:41 +01002656 ExternalReference::address_of_stack_limit(masm->isolate());
Ben Murdochb0fe1622011-05-05 13:52:32 +01002657 __ cmp(esp, Operand::StaticVariable(stack_limit));
Ben Murdoch257744e2011-11-30 15:57:28 +00002658 __ j(above_equal, &ok, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002659 {
2660 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002661 __ CallRuntime(Runtime::kStackGuard);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002662 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002663 __ jmp(masm->isolate()->builtins()->OnStackReplacement(),
2664 RelocInfo::CODE_TARGET);
2665
Ben Murdochb0fe1622011-05-05 13:52:32 +01002666 __ bind(&ok);
2667 __ ret(0);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002668}
2669
Steve Blocka7e24c12009-10-30 11:49:00 +00002670#undef __
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002671} // namespace internal
2672} // namespace v8
Leon Clarkef7060e22010-06-03 12:02:55 +01002673
2674#endif // V8_TARGET_ARCH_IA32