blob: 9e13172c852ef516fdb1442eaf7a9e747ef843e5 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#if V8_TARGET_ARCH_X87
6
7#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/x87/frames-x87.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012
13namespace v8 {
14namespace internal {
15
16
17#define __ ACCESS_MASM(masm)
18
19
20void 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
Ben Murdochb8a8cc12014-11-26 15:28:44 +000027 // -- esp[0] : return address
28 // -- esp[4] : last argument
29 // -- ...
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000030 // -- esp[4 * argc] : first argument
Ben Murdochb8a8cc12014-11-26 15:28:44 +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));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000040
41 // 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);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000054 }
55
56 // JumpToExternalReference expects eax to contain the number of arguments
57 // including the receiver and the extra arguments.
58 __ add(eax, Immediate(num_extra_args + 1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000059
Ben Murdochb8a8cc12014-11-26 15:28:44 +000060 __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
61}
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 Murdochb8a8cc12014-11-26 15:28:44 +0000120static 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 Murdochb8a8cc12014-11-26 15:28:44 +0000124 // ----------- S t a t e -------------
125 // -- eax: number of arguments
Ben Murdochda12d292016-06-02 14:46:10 +0100126 // -- esi: context
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000127 // -- edi: constructor function
128 // -- ebx: allocation site or undefined
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000129 // -- edx: new target
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000130 // -----------------------------------
131
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000132 // Enter a construct frame.
133 {
134 FrameScope scope(masm, StackFrame::CONSTRUCT);
135
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000136 // Preserve the incoming parameters on the stack.
137 __ AssertUndefinedOrAllocationSite(ebx);
Ben Murdochda12d292016-06-02 14:46:10 +0100138 __ push(esi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000139 __ push(ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000140 __ SmiTag(eax);
141 __ push(eax);
142
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000143 if (create_implicit_receiver) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100144 // Allocate the new receiver object.
145 __ Push(edi);
146 __ Push(edx);
147 FastNewObjectStub stub(masm->isolate());
148 __ CallStub(&stub);
149 __ mov(ebx, eax);
150 __ Pop(edx);
151 __ Pop(edi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000152
Ben Murdoch097c5b22016-05-18 11:27:45 +0100153 // ----------- S t a t e -------------
154 // -- edi: constructor function
155 // -- ebx: newly allocated object
156 // -- edx: new target
157 // -----------------------------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000158
159 // Retrieve smi-tagged arguments count from the stack.
160 __ mov(eax, Operand(esp, 0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000161 }
162
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000163 __ SmiUntag(eax);
164
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000165 if (create_implicit_receiver) {
166 // Push the allocated receiver to the stack. We need two copies
167 // because we may have to return the original one and the calling
168 // conventions dictate that the called function pops the receiver.
169 __ push(ebx);
170 __ push(ebx);
171 } else {
172 __ PushRoot(Heap::kTheHoleValueRootIndex);
173 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000174
175 // Set up pointer to last argument.
176 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
177
178 // Copy arguments and receiver to the expression stack.
179 Label loop, entry;
180 __ mov(ecx, eax);
181 __ jmp(&entry);
182 __ bind(&loop);
183 __ push(Operand(ebx, ecx, times_4, 0));
184 __ bind(&entry);
185 __ dec(ecx);
186 __ j(greater_equal, &loop);
187
188 // Call the function.
189 if (is_api_function) {
190 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
191 Handle<Code> code =
192 masm->isolate()->builtins()->HandleApiCallConstruct();
193 __ call(code, RelocInfo::CODE_TARGET);
194 } else {
195 ParameterCount actual(eax);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000196 __ InvokeFunction(edi, edx, actual, CALL_FUNCTION,
197 CheckDebugStepCallWrapper());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000198 }
199
200 // Store offset of return address for deoptimizer.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000201 if (create_implicit_receiver && !is_api_function) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000202 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
203 }
204
205 // Restore context from the frame.
Ben Murdochda12d292016-06-02 14:46:10 +0100206 __ mov(esi, Operand(ebp, ConstructFrameConstants::kContextOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000207
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000208 if (create_implicit_receiver) {
209 // If the result is an object (in the ECMA sense), we should get rid
210 // of the receiver and use the result; see ECMA-262 section 13.2.2-7
211 // on page 74.
212 Label use_receiver, exit;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000213
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000214 // If the result is a smi, it is *not* an object in the ECMA sense.
215 __ JumpIfSmi(eax, &use_receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000216
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000217 // If the type of the result (stored in its map) is less than
218 // FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense.
219 __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ecx);
220 __ j(above_equal, &exit);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000221
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000222 // Throw away the result of the constructor invocation and use the
223 // on-stack receiver as the result.
224 __ bind(&use_receiver);
225 __ mov(eax, Operand(esp, 0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000226
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000227 // Restore the arguments count and leave the construct frame. The
228 // arguments count is stored below the receiver.
229 __ bind(&exit);
230 __ mov(ebx, Operand(esp, 1 * kPointerSize));
231 } else {
232 __ mov(ebx, Operand(esp, 0));
233 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000234
235 // Leave construct frame.
236 }
237
Ben Murdoch097c5b22016-05-18 11:27:45 +0100238 // ES6 9.2.2. Step 13+
239 // Check that the result is not a Smi, indicating that the constructor result
240 // from a derived class is neither undefined nor an Object.
241 if (check_derived_construct) {
242 Label dont_throw;
243 __ JumpIfNotSmi(eax, &dont_throw);
244 {
245 FrameScope scope(masm, StackFrame::INTERNAL);
246 __ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject);
247 }
248 __ bind(&dont_throw);
249 }
250
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000251 // Remove caller arguments from the stack and return.
252 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
253 __ pop(ecx);
254 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
255 __ push(ecx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000256 if (create_implicit_receiver) {
257 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);
258 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000259 __ ret(0);
260}
261
262
263void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100264 Generate_JSConstructStubHelper(masm, false, true, false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000265}
266
267
268void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100269 Generate_JSConstructStubHelper(masm, true, false, false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000270}
271
272
273void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100274 Generate_JSConstructStubHelper(masm, false, false, false);
275}
276
277
278void Builtins::Generate_JSBuiltinsConstructStubForDerived(
279 MacroAssembler* masm) {
280 Generate_JSConstructStubHelper(masm, false, false, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000281}
282
283
284void Builtins::Generate_ConstructedNonConstructable(MacroAssembler* masm) {
285 FrameScope scope(masm, StackFrame::INTERNAL);
286 __ push(edi);
287 __ CallRuntime(Runtime::kThrowConstructedNonConstructable);
288}
289
290
291enum IsTagged { kEaxIsSmiTagged, kEaxIsUntaggedInt };
292
293
294// Clobbers ecx, edx, edi; preserves all other registers.
295static void Generate_CheckStackOverflow(MacroAssembler* masm,
296 IsTagged eax_is_tagged) {
297 // eax : the number of items to be pushed to the stack
298 //
299 // Check the stack for overflow. We are not trying to catch
300 // interruptions (e.g. debug break and preemption) here, so the "real stack
301 // limit" is checked.
302 Label okay;
303 ExternalReference real_stack_limit =
304 ExternalReference::address_of_real_stack_limit(masm->isolate());
305 __ mov(edi, Operand::StaticVariable(real_stack_limit));
306 // Make ecx the space we have left. The stack might already be overflowed
307 // here which will cause ecx to become negative.
308 __ mov(ecx, esp);
309 __ sub(ecx, edi);
310 // Make edx the space we need for the array when it is unrolled onto the
311 // stack.
312 __ mov(edx, eax);
313 int smi_tag = eax_is_tagged == kEaxIsSmiTagged ? kSmiTagSize : 0;
314 __ shl(edx, kPointerSizeLog2 - smi_tag);
315 // Check if the arguments will overflow the stack.
316 __ cmp(ecx, edx);
317 __ j(greater, &okay); // Signed comparison.
318
319 // Out of stack space.
320 __ CallRuntime(Runtime::kThrowStackOverflow);
321
322 __ bind(&okay);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000323}
324
325
326static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
327 bool is_construct) {
328 ProfileEntryHookStub::MaybeCallEntryHook(masm);
329
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000330 {
331 FrameScope scope(masm, StackFrame::INTERNAL);
332
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 Murdochb8a8cc12014-11-26 15:28:44 +0000338 // Load the previous frame pointer (ebx) to access C arguments
339 __ mov(ebx, Operand(ebp, 0));
340
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000341 // Push the function and the receiver onto the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000342 __ push(Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000343 __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
344
345 // 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));
348
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 Murdochb8a8cc12014-11-26 15:28:44 +0000353 // Copy arguments to the stack in a loop.
354 Label loop, entry;
355 __ Move(ecx, Immediate(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000356 __ jmp(&entry, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000357 __ 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);
364
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));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000371
372 // 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 Murdochb8a8cc12014-11-26 15:28:44 +0000377
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.
381 }
382 __ ret(kPointerSize); // Remove receiver.
383}
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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000605 // Pop return address to allow tail-call after pushing arguments.
606 __ Pop(ecx);
607
Ben Murdochda12d292016-06-02 14:46:10 +0100608 // Push edi in the slot meant for receiver. We need an extra register
609 // so store edi temporarily on stack.
610 __ Push(edi);
611
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000612 // Find the address of the last argument.
Ben Murdochda12d292016-06-02 14:46:10 +0100613 __ mov(edi, eax);
614 __ neg(edi);
615 __ shl(edi, kPointerSizeLog2);
616 __ add(edi, ebx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000617
Ben Murdochda12d292016-06-02 14:46:10 +0100618 Generate_InterpreterPushArgs(masm, edi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000619
Ben Murdochda12d292016-06-02 14:46:10 +0100620 // Restore the constructor from slot on stack. It was pushed at the slot
621 // meant for receiver.
622 __ mov(edi, Operand(esp, eax, times_pointer_size, 0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000623
624 // Re-push return address.
625 __ Push(ecx);
626
627 // Call the constructor with unmodified eax, edi, ebi values.
628 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
629}
630
631
Ben Murdoch097c5b22016-05-18 11:27:45 +0100632static void Generate_EnterBytecodeDispatch(MacroAssembler* masm) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000633 // Initialize register file register.
634 __ mov(kInterpreterRegisterFileRegister, ebp);
635 __ add(kInterpreterRegisterFileRegister,
636 Immediate(InterpreterFrameConstants::kRegisterFilePointerFromFp));
637
638 // Get the bytecode array pointer from the frame.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000639 __ mov(kInterpreterBytecodeArrayRegister,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100640 Operand(kInterpreterRegisterFileRegister,
641 InterpreterFrameConstants::kBytecodeArrayFromRegisterPointer));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000642
643 if (FLAG_debug_code) {
644 // Check function data field is actually a BytecodeArray object.
645 __ AssertNotSmi(kInterpreterBytecodeArrayRegister);
646 __ CmpObjectType(kInterpreterBytecodeArrayRegister, BYTECODE_ARRAY_TYPE,
647 ebx);
648 __ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
649 }
650
651 // Get the target bytecode offset from the frame.
652 __ mov(
653 kInterpreterBytecodeOffsetRegister,
654 Operand(kInterpreterRegisterFileRegister,
655 InterpreterFrameConstants::kBytecodeOffsetFromRegisterPointer));
656 __ SmiUntag(kInterpreterBytecodeOffsetRegister);
657
Ben Murdoch097c5b22016-05-18 11:27:45 +0100658 // Push dispatch table as a stack located parameter to the bytecode handler.
659 __ mov(ebx, Immediate(ExternalReference::interpreter_dispatch_table_address(
660 masm->isolate())));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000661 DCHECK_EQ(-1, kInterpreterDispatchTableSpillSlot);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100662 __ Pop(esi);
663 __ Push(ebx);
664 __ Push(esi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000665
666 // Dispatch to the target bytecode.
667 __ movzx_b(esi, Operand(kInterpreterBytecodeArrayRegister,
668 kInterpreterBytecodeOffsetRegister, times_1, 0));
669 __ mov(ebx, Operand(ebx, esi, times_pointer_size, 0));
670
671 // Get the context from the frame.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000672 __ mov(kContextRegister,
673 Operand(kInterpreterRegisterFileRegister,
674 InterpreterFrameConstants::kContextFromRegisterPointer));
675
676 // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
677 // and header removal.
678 __ add(ebx, Immediate(Code::kHeaderSize - kHeapObjectTag));
679 __ jmp(ebx);
680}
681
682
Ben Murdoch097c5b22016-05-18 11:27:45 +0100683static void Generate_InterpreterNotifyDeoptimizedHelper(
684 MacroAssembler* masm, Deoptimizer::BailoutType type) {
685 // Enter an internal frame.
686 {
687 FrameScope scope(masm, StackFrame::INTERNAL);
688
689 // Pass the deoptimization type to the runtime system.
690 __ Push(Smi::FromInt(static_cast<int>(type)));
691 __ CallRuntime(Runtime::kNotifyDeoptimized);
692 // Tear down internal frame.
693 }
694
695 // Drop state (we don't use these for interpreter deopts) and and pop the
696 // accumulator value into the accumulator register and push PC at top
697 // of stack (to simulate initial call to bytecode handler in interpreter entry
698 // trampoline).
699 __ Pop(ebx);
700 __ Drop(1);
701 __ Pop(kInterpreterAccumulatorRegister);
702 __ Push(ebx);
703
704 // Enter the bytecode dispatch.
705 Generate_EnterBytecodeDispatch(masm);
706}
707
708
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000709void Builtins::Generate_InterpreterNotifyDeoptimized(MacroAssembler* masm) {
710 Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
711}
712
713
714void Builtins::Generate_InterpreterNotifySoftDeoptimized(MacroAssembler* masm) {
715 Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
716}
717
718
719void Builtins::Generate_InterpreterNotifyLazyDeoptimized(MacroAssembler* masm) {
720 Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
721}
722
Ben Murdoch097c5b22016-05-18 11:27:45 +0100723void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
724 // Set the address of the interpreter entry trampoline as a return address.
725 // This simulates the initial call to bytecode handlers in interpreter entry
726 // trampoline. The return will never actually be taken, but our stack walker
727 // uses this address to determine whether a frame is interpreted.
728 __ Push(masm->isolate()->builtins()->InterpreterEntryTrampoline());
729
730 Generate_EnterBytecodeDispatch(masm);
731}
732
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000733
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000734void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100735 GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000736}
737
738
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000739void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100740 GenerateTailCallToReturnedCode(masm,
741 Runtime::kCompileOptimized_NotConcurrent);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000742}
743
744
745void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100746 GenerateTailCallToReturnedCode(masm, Runtime::kCompileOptimized_Concurrent);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000747}
748
749
750static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
751 // For now, we are relying on the fact that make_code_young doesn't do any
752 // garbage collection which allows us to save/restore the registers without
753 // worrying about which of them contain pointers. We also don't build an
754 // internal frame to make the code faster, since we shouldn't have to do stack
755 // crawls in MakeCodeYoung. This seems a bit fragile.
756
757 // Re-execute the code that was patched back to the young age when
758 // the stub returns.
759 __ sub(Operand(esp, 0), Immediate(5));
760 __ pushad();
761 __ mov(eax, Operand(esp, 8 * kPointerSize));
762 {
763 FrameScope scope(masm, StackFrame::MANUAL);
764 __ PrepareCallCFunction(2, ebx);
765 __ mov(Operand(esp, 1 * kPointerSize),
766 Immediate(ExternalReference::isolate_address(masm->isolate())));
767 __ mov(Operand(esp, 0), eax);
768 __ CallCFunction(
769 ExternalReference::get_make_code_young_function(masm->isolate()), 2);
770 }
771 __ popad();
772 __ ret(0);
773}
774
775#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \
776void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \
777 MacroAssembler* masm) { \
778 GenerateMakeCodeYoungAgainCommon(masm); \
779} \
780void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \
781 MacroAssembler* masm) { \
782 GenerateMakeCodeYoungAgainCommon(masm); \
783}
784CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
785#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
786
787
788void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
789 // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact
790 // that make_code_young doesn't do any garbage collection which allows us to
791 // save/restore the registers without worrying about which of them contain
792 // pointers.
793 __ pushad();
794 __ mov(eax, Operand(esp, 8 * kPointerSize));
795 __ sub(eax, Immediate(Assembler::kCallInstructionLength));
796 { // NOLINT
797 FrameScope scope(masm, StackFrame::MANUAL);
798 __ PrepareCallCFunction(2, ebx);
799 __ mov(Operand(esp, 1 * kPointerSize),
800 Immediate(ExternalReference::isolate_address(masm->isolate())));
801 __ mov(Operand(esp, 0), eax);
802 __ CallCFunction(
803 ExternalReference::get_mark_code_as_executed_function(masm->isolate()),
804 2);
805 }
806 __ popad();
807
808 // Perform prologue operations usually performed by the young code stub.
809 __ pop(eax); // Pop return address into scratch register.
810 __ push(ebp); // Caller's frame pointer.
811 __ mov(ebp, esp);
812 __ push(esi); // Callee's context.
813 __ push(edi); // Callee's JS Function.
814 __ push(eax); // Push return address after frame prologue.
815
816 // Jump to point after the code-age stub.
817 __ ret(0);
818}
819
820
821void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
822 GenerateMakeCodeYoungAgainCommon(masm);
823}
824
825
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000826void Builtins::Generate_MarkCodeAsToBeExecutedOnce(MacroAssembler* masm) {
827 Generate_MarkCodeAsExecutedOnce(masm);
828}
829
830
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000831static void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
832 SaveFPRegsMode save_doubles) {
833 // Enter an internal frame.
834 {
835 FrameScope scope(masm, StackFrame::INTERNAL);
836
837 // Preserve registers across notification, this is important for compiled
838 // stubs that tail call the runtime on deopts passing their parameters in
839 // registers.
840 __ pushad();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000841 __ CallRuntime(Runtime::kNotifyStubFailure, save_doubles);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000842 __ popad();
843 // Tear down internal frame.
844 }
845
846 __ pop(MemOperand(esp, 0)); // Ignore state offset
847 __ ret(0); // Return to IC Miss stub, continuation still on stack.
848}
849
850
851void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
852 Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
853}
854
855
856void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
857 Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
858}
859
860
861static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
862 Deoptimizer::BailoutType type) {
863 {
864 FrameScope scope(masm, StackFrame::INTERNAL);
865
866 // Pass deoptimization type to the runtime system.
867 __ push(Immediate(Smi::FromInt(static_cast<int>(type))));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000868 __ CallRuntime(Runtime::kNotifyDeoptimized);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000869
870 // Tear down internal frame.
871 }
872
873 // Get the full codegen state from the stack and untag it.
874 __ mov(ecx, Operand(esp, 1 * kPointerSize));
875 __ SmiUntag(ecx);
876
877 // Switch on the state.
878 Label not_no_registers, not_tos_eax;
879 __ cmp(ecx, FullCodeGenerator::NO_REGISTERS);
880 __ j(not_equal, &not_no_registers, Label::kNear);
881 __ ret(1 * kPointerSize); // Remove state.
882
883 __ bind(&not_no_registers);
884 __ mov(eax, Operand(esp, 2 * kPointerSize));
885 __ cmp(ecx, FullCodeGenerator::TOS_REG);
886 __ j(not_equal, &not_tos_eax, Label::kNear);
887 __ ret(2 * kPointerSize); // Remove state, eax.
888
889 __ bind(&not_tos_eax);
890 __ Abort(kNoCasesLeft);
891}
892
893
894void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
895 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
896}
897
898
899void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
900 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
901}
902
903
904void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
905 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
906}
907
908
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000909// static
910void Builtins::Generate_DatePrototype_GetField(MacroAssembler* masm,
911 int field_index) {
912 // ----------- S t a t e -------------
913 // -- esp[0] : return address
914 // -- esp[4] : receiver
915 // -----------------------------------
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000916
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000917 // 1. Load receiver into eax and check that it's actually a JSDate object.
918 Label receiver_not_date;
919 {
920 __ mov(eax, Operand(esp, kPointerSize));
921 __ JumpIfSmi(eax, &receiver_not_date);
922 __ CmpObjectType(eax, JS_DATE_TYPE, ebx);
923 __ j(not_equal, &receiver_not_date);
924 }
925
926 // 2. Load the specified date field, falling back to the runtime as necessary.
927 if (field_index == JSDate::kDateValue) {
928 __ mov(eax, FieldOperand(eax, JSDate::kValueOffset));
929 } else {
930 if (field_index < JSDate::kFirstUncachedField) {
931 Label stamp_mismatch;
932 __ mov(edx, Operand::StaticVariable(
933 ExternalReference::date_cache_stamp(masm->isolate())));
934 __ cmp(edx, FieldOperand(eax, JSDate::kCacheStampOffset));
935 __ j(not_equal, &stamp_mismatch, Label::kNear);
936 __ mov(eax, FieldOperand(
937 eax, JSDate::kValueOffset + field_index * kPointerSize));
938 __ ret(1 * kPointerSize);
939 __ bind(&stamp_mismatch);
940 }
941 FrameScope scope(masm, StackFrame::INTERNAL);
942 __ PrepareCallCFunction(2, ebx);
943 __ mov(Operand(esp, 0), eax);
944 __ mov(Operand(esp, 1 * kPointerSize),
945 Immediate(Smi::FromInt(field_index)));
946 __ CallCFunction(
947 ExternalReference::get_date_field_function(masm->isolate()), 2);
948 }
949 __ ret(1 * kPointerSize);
950
951 // 3. Raise a TypeError if the receiver is not a date.
952 __ bind(&receiver_not_date);
953 {
954 FrameScope scope(masm, StackFrame::MANUAL);
955 __ EnterFrame(StackFrame::INTERNAL);
956 __ CallRuntime(Runtime::kThrowNotDateError);
957 }
958}
959
Ben Murdochda12d292016-06-02 14:46:10 +0100960// static
961void Builtins::Generate_FunctionHasInstance(MacroAssembler* masm) {
962 // ----------- S t a t e -------------
963 // -- eax : argc
964 // -- esp[0] : return address
965 // -- esp[4] : first argument (left-hand side)
966 // -- esp[8] : receiver (right-hand side)
967 // -----------------------------------
968
969 {
970 FrameScope scope(masm, StackFrame::INTERNAL);
971 __ mov(InstanceOfDescriptor::LeftRegister(),
972 Operand(ebp, 2 * kPointerSize)); // Load left-hand side.
973 __ mov(InstanceOfDescriptor::RightRegister(),
974 Operand(ebp, 3 * kPointerSize)); // Load right-hand side.
975 InstanceOfStub stub(masm->isolate(), true);
976 __ CallStub(&stub);
977 }
978
979 // Pop the argument and the receiver.
980 __ ret(2 * kPointerSize);
981}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000982
983// static
984void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
985 // ----------- S t a t e -------------
986 // -- eax : argc
987 // -- esp[0] : return address
988 // -- esp[4] : argArray
989 // -- esp[8] : thisArg
990 // -- esp[12] : receiver
991 // -----------------------------------
992
993 // 1. Load receiver into edi, argArray into eax (if present), remove all
994 // arguments from the stack (including the receiver), and push thisArg (if
995 // present) instead.
996 {
997 Label no_arg_array, no_this_arg;
998 __ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
999 __ mov(ebx, edx);
1000 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001001 __ test(eax, eax);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001002 __ j(zero, &no_this_arg, Label::kNear);
1003 {
1004 __ mov(edx, Operand(esp, eax, times_pointer_size, 0));
1005 __ cmp(eax, Immediate(1));
1006 __ j(equal, &no_arg_array, Label::kNear);
1007 __ mov(ebx, Operand(esp, eax, times_pointer_size, -kPointerSize));
1008 __ bind(&no_arg_array);
1009 }
1010 __ bind(&no_this_arg);
1011 __ PopReturnAddressTo(ecx);
1012 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1013 __ Push(edx);
1014 __ PushReturnAddressFrom(ecx);
1015 __ Move(eax, ebx);
1016 }
1017
1018 // ----------- S t a t e -------------
1019 // -- eax : argArray
1020 // -- edi : receiver
1021 // -- esp[0] : return address
1022 // -- esp[4] : thisArg
1023 // -----------------------------------
1024
1025 // 2. Make sure the receiver is actually callable.
1026 Label receiver_not_callable;
1027 __ JumpIfSmi(edi, &receiver_not_callable, Label::kNear);
1028 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
Ben Murdochda12d292016-06-02 14:46:10 +01001029 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
1030 Immediate(1 << Map::kIsCallable));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001031 __ j(zero, &receiver_not_callable, Label::kNear);
1032
1033 // 3. Tail call with no arguments if argArray is null or undefined.
1034 Label no_arguments;
1035 __ JumpIfRoot(eax, Heap::kNullValueRootIndex, &no_arguments, Label::kNear);
1036 __ JumpIfRoot(eax, Heap::kUndefinedValueRootIndex, &no_arguments,
1037 Label::kNear);
1038
1039 // 4a. Apply the receiver to the given argArray (passing undefined for
1040 // new.target).
1041 __ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
1042 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1043
1044 // 4b. The argArray is either null or undefined, so we tail call without any
1045 // arguments to the receiver.
1046 __ bind(&no_arguments);
1047 {
1048 __ Set(eax, 0);
1049 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1050 }
1051
1052 // 4c. The receiver is not callable, throw an appropriate TypeError.
1053 __ bind(&receiver_not_callable);
1054 {
1055 __ mov(Operand(esp, kPointerSize), edi);
1056 __ TailCallRuntime(Runtime::kThrowApplyNonFunction);
1057 }
1058}
1059
1060
1061// static
1062void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) {
1063 // Stack Layout:
1064 // esp[0] : Return address
1065 // esp[8] : Argument n
1066 // esp[16] : Argument n-1
1067 // ...
1068 // esp[8 * n] : Argument 1
1069 // esp[8 * (n + 1)] : Receiver (callable to call)
1070 //
1071 // eax contains the number of arguments, n, not counting the receiver.
1072 //
1073 // 1. Make sure we have at least one argument.
1074 {
1075 Label done;
1076 __ test(eax, eax);
1077 __ j(not_zero, &done, Label::kNear);
1078 __ PopReturnAddressTo(ebx);
1079 __ PushRoot(Heap::kUndefinedValueRootIndex);
1080 __ PushReturnAddressFrom(ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001081 __ inc(eax);
1082 __ bind(&done);
1083 }
1084
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001085 // 2. Get the callable to call (passed as receiver) from the stack.
1086 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001087
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001088 // 3. Shift arguments and return address one slot down on the stack
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001089 // (overwriting the original receiver). Adjust argument count to make
1090 // the original first argument the new receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001091 {
1092 Label loop;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001093 __ mov(ecx, eax);
1094 __ bind(&loop);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001095 __ mov(ebx, Operand(esp, ecx, times_pointer_size, 0));
1096 __ mov(Operand(esp, ecx, times_pointer_size, kPointerSize), ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001097 __ dec(ecx);
1098 __ j(not_sign, &loop); // While non-negative (to copy return address).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001099 __ pop(ebx); // Discard copy of return address.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001100 __ dec(eax); // One fewer argument (first argument is new receiver).
1101 }
1102
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001103 // 4. Call the callable.
1104 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001105}
1106
1107
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001108void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
1109 // ----------- S t a t e -------------
1110 // -- eax : argc
1111 // -- esp[0] : return address
1112 // -- esp[4] : argumentsList
1113 // -- esp[8] : thisArgument
1114 // -- esp[12] : target
1115 // -- esp[16] : receiver
1116 // -----------------------------------
1117
1118 // 1. Load target into edi (if present), argumentsList into eax (if present),
1119 // remove all arguments from the stack (including the receiver), and push
1120 // thisArgument (if present) instead.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001121 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001122 Label done;
1123 __ LoadRoot(edi, Heap::kUndefinedValueRootIndex);
1124 __ mov(edx, edi);
1125 __ mov(ebx, edi);
1126 __ cmp(eax, Immediate(1));
1127 __ j(below, &done, Label::kNear);
1128 __ mov(edi, Operand(esp, eax, times_pointer_size, -0 * kPointerSize));
1129 __ j(equal, &done, Label::kNear);
1130 __ mov(edx, Operand(esp, eax, times_pointer_size, -1 * kPointerSize));
1131 __ cmp(eax, Immediate(3));
1132 __ j(below, &done, Label::kNear);
1133 __ mov(ebx, Operand(esp, eax, times_pointer_size, -2 * kPointerSize));
1134 __ bind(&done);
1135 __ PopReturnAddressTo(ecx);
1136 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1137 __ Push(edx);
1138 __ PushReturnAddressFrom(ecx);
1139 __ Move(eax, ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001140 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001141
1142 // ----------- S t a t e -------------
1143 // -- eax : argumentsList
1144 // -- edi : target
1145 // -- esp[0] : return address
1146 // -- esp[4] : thisArgument
1147 // -----------------------------------
1148
1149 // 2. Make sure the target is actually callable.
1150 Label target_not_callable;
1151 __ JumpIfSmi(edi, &target_not_callable, Label::kNear);
1152 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
Ben Murdochda12d292016-06-02 14:46:10 +01001153 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
1154 Immediate(1 << Map::kIsCallable));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001155 __ j(zero, &target_not_callable, Label::kNear);
1156
1157 // 3a. Apply the target to the given argumentsList (passing undefined for
1158 // new.target).
1159 __ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
1160 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1161
1162 // 3b. The target is not callable, throw an appropriate TypeError.
1163 __ bind(&target_not_callable);
1164 {
1165 __ mov(Operand(esp, kPointerSize), edi);
1166 __ TailCallRuntime(Runtime::kThrowApplyNonFunction);
1167 }
1168}
1169
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001170void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
1171 // ----------- S t a t e -------------
1172 // -- eax : argc
1173 // -- esp[0] : return address
1174 // -- esp[4] : new.target (optional)
1175 // -- esp[8] : argumentsList
1176 // -- esp[12] : target
1177 // -- esp[16] : receiver
1178 // -----------------------------------
1179
1180 // 1. Load target into edi (if present), argumentsList into eax (if present),
1181 // new.target into edx (if present, otherwise use target), remove all
1182 // arguments from the stack (including the receiver), and push thisArgument
1183 // (if present) instead.
1184 {
1185 Label done;
1186 __ LoadRoot(edi, Heap::kUndefinedValueRootIndex);
1187 __ mov(edx, edi);
1188 __ mov(ebx, edi);
1189 __ cmp(eax, Immediate(1));
1190 __ j(below, &done, Label::kNear);
1191 __ mov(edi, Operand(esp, eax, times_pointer_size, -0 * kPointerSize));
1192 __ mov(edx, edi);
1193 __ j(equal, &done, Label::kNear);
1194 __ mov(ebx, Operand(esp, eax, times_pointer_size, -1 * kPointerSize));
1195 __ cmp(eax, Immediate(3));
1196 __ j(below, &done, Label::kNear);
1197 __ mov(edx, Operand(esp, eax, times_pointer_size, -2 * kPointerSize));
1198 __ bind(&done);
1199 __ PopReturnAddressTo(ecx);
1200 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1201 __ PushRoot(Heap::kUndefinedValueRootIndex);
1202 __ PushReturnAddressFrom(ecx);
1203 __ Move(eax, ebx);
1204 }
1205
1206 // ----------- S t a t e -------------
1207 // -- eax : argumentsList
1208 // -- edx : new.target
1209 // -- edi : target
1210 // -- esp[0] : return address
1211 // -- esp[4] : receiver (undefined)
1212 // -----------------------------------
1213
1214 // 2. Make sure the target is actually a constructor.
1215 Label target_not_constructor;
1216 __ JumpIfSmi(edi, &target_not_constructor, Label::kNear);
1217 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
Ben Murdochda12d292016-06-02 14:46:10 +01001218 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
1219 Immediate(1 << Map::kIsConstructor));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001220 __ j(zero, &target_not_constructor, Label::kNear);
1221
1222 // 3. Make sure the target is actually a constructor.
1223 Label new_target_not_constructor;
1224 __ JumpIfSmi(edx, &new_target_not_constructor, Label::kNear);
1225 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
Ben Murdochda12d292016-06-02 14:46:10 +01001226 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
1227 Immediate(1 << Map::kIsConstructor));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001228 __ j(zero, &new_target_not_constructor, Label::kNear);
1229
1230 // 4a. Construct the target with the given new.target and argumentsList.
1231 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1232
1233 // 4b. The target is not a constructor, throw an appropriate TypeError.
1234 __ bind(&target_not_constructor);
1235 {
1236 __ mov(Operand(esp, kPointerSize), edi);
1237 __ TailCallRuntime(Runtime::kThrowCalledNonCallable);
1238 }
1239
1240 // 4c. The new.target is not a constructor, throw an appropriate TypeError.
1241 __ bind(&new_target_not_constructor);
1242 {
1243 __ mov(Operand(esp, kPointerSize), edx);
1244 __ TailCallRuntime(Runtime::kThrowCalledNonCallable);
1245 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001246}
1247
1248
1249void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
1250 // ----------- S t a t e -------------
1251 // -- eax : argc
1252 // -- esp[0] : return address
1253 // -- esp[4] : last argument
1254 // -----------------------------------
1255 Label generic_array_code;
1256
1257 // Get the InternalArray function.
1258 __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi);
1259
1260 if (FLAG_debug_code) {
1261 // Initial map for the builtin InternalArray function should be a map.
1262 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1263 // Will both indicate a NULL and a Smi.
1264 __ test(ebx, Immediate(kSmiTagMask));
1265 __ Assert(not_zero, kUnexpectedInitialMapForInternalArrayFunction);
1266 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1267 __ Assert(equal, kUnexpectedInitialMapForInternalArrayFunction);
1268 }
1269
1270 // Run the native code for the InternalArray function called as a normal
1271 // function.
1272 // tail call a stub
1273 InternalArrayConstructorStub stub(masm->isolate());
1274 __ TailCallStub(&stub);
1275}
1276
1277
1278void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
1279 // ----------- S t a t e -------------
1280 // -- eax : argc
1281 // -- esp[0] : return address
1282 // -- esp[4] : last argument
1283 // -----------------------------------
1284 Label generic_array_code;
1285
1286 // Get the Array function.
1287 __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001288 __ mov(edx, edi);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001289
1290 if (FLAG_debug_code) {
1291 // Initial map for the builtin Array function should be a map.
1292 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1293 // Will both indicate a NULL and a Smi.
1294 __ test(ebx, Immediate(kSmiTagMask));
1295 __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction);
1296 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1297 __ Assert(equal, kUnexpectedInitialMapForArrayFunction);
1298 }
1299
1300 // Run the native code for the Array function called as a normal function.
1301 // tail call a stub
1302 __ mov(ebx, masm->isolate()->factory()->undefined_value());
1303 ArrayConstructorStub stub(masm->isolate());
1304 __ TailCallStub(&stub);
1305}
1306
1307
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001308// static
Ben Murdoch097c5b22016-05-18 11:27:45 +01001309void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
1310 // ----------- S t a t e -------------
1311 // -- eax : number of arguments
1312 // -- esp[0] : return address
1313 // -- esp[(argc - n) * 8] : arg[n] (zero-based)
1314 // -- esp[(argc + 1) * 8] : receiver
1315 // -----------------------------------
1316 Condition const cc = (kind == MathMaxMinKind::kMin) ? below : above;
1317 Heap::RootListIndex const root_index =
1318 (kind == MathMaxMinKind::kMin) ? Heap::kInfinityValueRootIndex
1319 : Heap::kMinusInfinityValueRootIndex;
1320 const int reg_sel = (kind == MathMaxMinKind::kMin) ? 1 : 0;
1321
1322 // Load the accumulator with the default return value (either -Infinity or
1323 // +Infinity), with the tagged value in edx and the double value in stx_0.
1324 __ LoadRoot(edx, root_index);
1325 __ fld_d(FieldOperand(edx, HeapNumber::kValueOffset));
1326 __ Move(ecx, eax);
1327
1328 Label done_loop, loop;
1329 __ bind(&loop);
1330 {
1331 // Check if all parameters done.
1332 __ test(ecx, ecx);
1333 __ j(zero, &done_loop);
1334
1335 // Load the next parameter tagged value into ebx.
1336 __ mov(ebx, Operand(esp, ecx, times_pointer_size, 0));
1337
1338 // Load the double value of the parameter into stx_1, maybe converting the
1339 // parameter to a number first using the ToNumberStub if necessary.
1340 Label convert, convert_smi, convert_number, done_convert;
1341 __ bind(&convert);
1342 __ JumpIfSmi(ebx, &convert_smi);
1343 __ JumpIfRoot(FieldOperand(ebx, HeapObject::kMapOffset),
1344 Heap::kHeapNumberMapRootIndex, &convert_number);
1345 {
1346 // Parameter is not a Number, use the ToNumberStub to convert it.
1347 FrameScope scope(masm, StackFrame::INTERNAL);
1348 __ SmiTag(eax);
1349 __ SmiTag(ecx);
1350 __ Push(eax);
1351 __ Push(ecx);
1352 __ Push(edx);
1353 __ mov(eax, ebx);
1354 ToNumberStub stub(masm->isolate());
1355 __ CallStub(&stub);
1356 __ mov(ebx, eax);
1357 __ Pop(edx);
1358 __ Pop(ecx);
1359 __ Pop(eax);
1360 {
1361 // Restore the double accumulator value (stX_0).
1362 Label restore_smi, done_restore;
1363 __ JumpIfSmi(edx, &restore_smi, Label::kNear);
1364 __ fld_d(FieldOperand(edx, HeapNumber::kValueOffset));
1365 __ jmp(&done_restore, Label::kNear);
1366 __ bind(&restore_smi);
1367 __ SmiUntag(edx);
1368 __ push(edx);
1369 __ fild_s(Operand(esp, 0));
1370 __ pop(edx);
1371 __ SmiTag(edx);
1372 __ bind(&done_restore);
1373 }
1374 __ SmiUntag(ecx);
1375 __ SmiUntag(eax);
1376 }
1377 __ jmp(&convert);
1378 __ bind(&convert_number);
1379 // Load another value into stx_1
1380 __ fld_d(FieldOperand(ebx, HeapNumber::kValueOffset));
1381 __ fxch();
1382 __ jmp(&done_convert, Label::kNear);
1383 __ bind(&convert_smi);
1384 __ SmiUntag(ebx);
1385 __ push(ebx);
1386 __ fild_s(Operand(esp, 0));
1387 __ pop(ebx);
1388 __ fxch();
1389 __ SmiTag(ebx);
1390 __ bind(&done_convert);
1391
1392 // Perform the actual comparison with the accumulator value on the left hand
1393 // side (stx_0) and the next parameter value on the right hand side (stx_1).
1394 Label compare_equal, compare_nan, compare_swap, done_compare;
1395
1396 // Duplicates the 2 float data for FCmp
1397 __ fld(1);
1398 __ fld(1);
1399 __ FCmp();
1400 __ j(parity_even, &compare_nan, Label::kNear);
1401 __ j(cc, &done_compare, Label::kNear);
1402 __ j(equal, &compare_equal, Label::kNear);
1403
1404 // Result is on the right hand side(stx_0).
1405 __ bind(&compare_swap);
1406 __ fxch();
1407 __ mov(edx, ebx);
1408 __ jmp(&done_compare, Label::kNear);
1409
1410 // At least one side is NaN, which means that the result will be NaN too.
1411 __ bind(&compare_nan);
1412 // Set the result on the right hand side (stx_0) to nan
1413 __ fstp(0);
1414 __ LoadRoot(edx, Heap::kNanValueRootIndex);
1415 __ fld_d(FieldOperand(edx, HeapNumber::kValueOffset));
1416 __ jmp(&done_compare, Label::kNear);
1417
1418 // Left and right hand side are equal, check for -0 vs. +0.
1419 __ bind(&compare_equal);
1420 // Check the sign of the value in reg_sel
1421 __ fld(reg_sel);
1422 __ FXamSign();
1423 __ j(not_zero, &compare_swap);
1424
1425 __ bind(&done_compare);
1426 // The right result is on the right hand side(stx_0)
1427 // and can remove the useless stx_1 now.
1428 __ fxch();
1429 __ fstp(0);
1430 __ dec(ecx);
1431 __ jmp(&loop);
1432 }
1433
1434 __ bind(&done_loop);
1435 __ PopReturnAddressTo(ecx);
1436 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1437 __ PushReturnAddressFrom(ecx);
1438 __ mov(eax, edx);
1439 __ Ret();
1440}
1441
1442// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001443void Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001444 // ----------- S t a t e -------------
1445 // -- eax : number of arguments
1446 // -- edi : constructor function
1447 // -- esp[0] : return address
1448 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1449 // -- esp[(argc + 1) * 4] : receiver
1450 // -----------------------------------
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001451
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001452 // 1. Load the first argument into eax and get rid of the rest (including the
1453 // receiver).
1454 Label no_arguments;
1455 {
1456 __ test(eax, eax);
1457 __ j(zero, &no_arguments, Label::kNear);
1458 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1459 __ PopReturnAddressTo(ecx);
1460 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1461 __ PushReturnAddressFrom(ecx);
1462 __ mov(eax, ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001463 }
1464
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001465 // 2a. Convert the first argument to a number.
1466 ToNumberStub stub(masm->isolate());
1467 __ TailCallStub(&stub);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001468
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001469 // 2b. No arguments, return +0 (already in eax).
1470 __ bind(&no_arguments);
1471 __ ret(1 * kPointerSize);
1472}
1473
1474
1475// static
1476void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001477 // ----------- S t a t e -------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001478 // -- eax : number of arguments
1479 // -- edi : constructor function
1480 // -- edx : new target
1481 // -- esp[0] : return address
1482 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1483 // -- esp[(argc + 1) * 4] : receiver
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001484 // -----------------------------------
1485
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001486 // 1. Make sure we operate in the context of the called function.
1487 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001488
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001489 // 2. Load the first argument into ebx and get rid of the rest (including the
1490 // receiver).
1491 {
1492 Label no_arguments, done;
1493 __ test(eax, eax);
1494 __ j(zero, &no_arguments, Label::kNear);
1495 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1496 __ jmp(&done, Label::kNear);
1497 __ bind(&no_arguments);
1498 __ Move(ebx, Smi::FromInt(0));
1499 __ bind(&done);
1500 __ PopReturnAddressTo(ecx);
1501 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1502 __ PushReturnAddressFrom(ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001503 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001504
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001505 // 3. Make sure ebx is a number.
1506 {
1507 Label done_convert;
1508 __ JumpIfSmi(ebx, &done_convert);
1509 __ CompareRoot(FieldOperand(ebx, HeapObject::kMapOffset),
1510 Heap::kHeapNumberMapRootIndex);
1511 __ j(equal, &done_convert);
1512 {
1513 FrameScope scope(masm, StackFrame::INTERNAL);
1514 __ Push(edi);
1515 __ Push(edx);
1516 __ Move(eax, ebx);
1517 ToNumberStub stub(masm->isolate());
1518 __ CallStub(&stub);
1519 __ Move(ebx, eax);
1520 __ Pop(edx);
1521 __ Pop(edi);
1522 }
1523 __ bind(&done_convert);
1524 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001525
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001526 // 4. Check if new target and constructor differ.
1527 Label new_object;
1528 __ cmp(edx, edi);
1529 __ j(not_equal, &new_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001530
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001531 // 5. Allocate a JSValue wrapper for the number.
1532 __ AllocateJSValue(eax, edi, ebx, ecx, &new_object);
1533 __ Ret();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001534
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001535 // 6. Fallback to the runtime to create new object.
1536 __ bind(&new_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001537 {
1538 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001539 __ Push(ebx); // the first argument
Ben Murdoch097c5b22016-05-18 11:27:45 +01001540 FastNewObjectStub stub(masm->isolate());
1541 __ CallStub(&stub);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001542 __ Pop(FieldOperand(eax, JSValue::kValueOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001543 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001544 __ Ret();
1545}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001546
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001547
1548// static
1549void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
1550 // ----------- S t a t e -------------
1551 // -- eax : number of arguments
1552 // -- edi : constructor function
1553 // -- esp[0] : return address
1554 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1555 // -- esp[(argc + 1) * 4] : receiver
1556 // -----------------------------------
1557
1558 // 1. Load the first argument into eax and get rid of the rest (including the
1559 // receiver).
1560 Label no_arguments;
1561 {
1562 __ test(eax, eax);
1563 __ j(zero, &no_arguments, Label::kNear);
1564 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1565 __ PopReturnAddressTo(ecx);
1566 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1567 __ PushReturnAddressFrom(ecx);
1568 __ mov(eax, ebx);
1569 }
1570
1571 // 2a. At least one argument, return eax if it's a string, otherwise
1572 // dispatch to appropriate conversion.
1573 Label to_string, symbol_descriptive_string;
1574 {
1575 __ JumpIfSmi(eax, &to_string, Label::kNear);
1576 STATIC_ASSERT(FIRST_NONSTRING_TYPE == SYMBOL_TYPE);
1577 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
1578 __ j(above, &to_string, Label::kNear);
1579 __ j(equal, &symbol_descriptive_string, Label::kNear);
1580 __ Ret();
1581 }
1582
1583 // 2b. No arguments, return the empty string (and pop the receiver).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001584 __ bind(&no_arguments);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001585 {
1586 __ LoadRoot(eax, Heap::kempty_stringRootIndex);
1587 __ ret(1 * kPointerSize);
1588 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001589
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001590 // 3a. Convert eax to a string.
1591 __ bind(&to_string);
1592 {
1593 ToStringStub stub(masm->isolate());
1594 __ TailCallStub(&stub);
1595 }
1596
1597 // 3b. Convert symbol in eax to a string.
1598 __ bind(&symbol_descriptive_string);
1599 {
1600 __ PopReturnAddressTo(ecx);
1601 __ Push(eax);
1602 __ PushReturnAddressFrom(ecx);
1603 __ TailCallRuntime(Runtime::kSymbolDescriptiveString);
1604 }
1605}
1606
1607
1608// static
1609void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
1610 // ----------- S t a t e -------------
1611 // -- eax : number of arguments
1612 // -- edi : constructor function
1613 // -- edx : new target
1614 // -- esp[0] : return address
1615 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1616 // -- esp[(argc + 1) * 4] : receiver
1617 // -----------------------------------
1618
1619 // 1. Make sure we operate in the context of the called function.
1620 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1621
1622 // 2. Load the first argument into ebx and get rid of the rest (including the
1623 // receiver).
1624 {
1625 Label no_arguments, done;
1626 __ test(eax, eax);
1627 __ j(zero, &no_arguments, Label::kNear);
1628 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1629 __ jmp(&done, Label::kNear);
1630 __ bind(&no_arguments);
1631 __ LoadRoot(ebx, Heap::kempty_stringRootIndex);
1632 __ bind(&done);
1633 __ PopReturnAddressTo(ecx);
1634 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1635 __ PushReturnAddressFrom(ecx);
1636 }
1637
1638 // 3. Make sure ebx is a string.
1639 {
1640 Label convert, done_convert;
1641 __ JumpIfSmi(ebx, &convert, Label::kNear);
1642 __ CmpObjectType(ebx, FIRST_NONSTRING_TYPE, ecx);
1643 __ j(below, &done_convert);
1644 __ bind(&convert);
1645 {
1646 FrameScope scope(masm, StackFrame::INTERNAL);
1647 ToStringStub stub(masm->isolate());
1648 __ Push(edi);
1649 __ Push(edx);
1650 __ Move(eax, ebx);
1651 __ CallStub(&stub);
1652 __ Move(ebx, eax);
1653 __ Pop(edx);
1654 __ Pop(edi);
1655 }
1656 __ bind(&done_convert);
1657 }
1658
1659 // 4. Check if new target and constructor differ.
1660 Label new_object;
1661 __ cmp(edx, edi);
1662 __ j(not_equal, &new_object);
1663
1664 // 5. Allocate a JSValue wrapper for the string.
1665 __ AllocateJSValue(eax, edi, ebx, ecx, &new_object);
1666 __ Ret();
1667
1668 // 6. Fallback to the runtime to create new object.
1669 __ bind(&new_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001670 {
1671 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001672 __ Push(ebx); // the first argument
Ben Murdoch097c5b22016-05-18 11:27:45 +01001673 FastNewObjectStub stub(masm->isolate());
1674 __ CallStub(&stub);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001675 __ Pop(FieldOperand(eax, JSValue::kValueOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001676 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001677 __ Ret();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001678}
1679
1680
1681static void ArgumentsAdaptorStackCheck(MacroAssembler* masm,
1682 Label* stack_overflow) {
1683 // ----------- S t a t e -------------
1684 // -- eax : actual number of arguments
1685 // -- ebx : expected number of arguments
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001686 // -- edx : new target (passed through to callee)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001687 // -----------------------------------
1688 // Check the stack for overflow. We are not trying to catch
1689 // interruptions (e.g. debug break and preemption) here, so the "real stack
1690 // limit" is checked.
1691 ExternalReference real_stack_limit =
1692 ExternalReference::address_of_real_stack_limit(masm->isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001693 __ mov(edi, Operand::StaticVariable(real_stack_limit));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001694 // Make ecx the space we have left. The stack might already be overflowed
1695 // here which will cause ecx to become negative.
1696 __ mov(ecx, esp);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001697 __ sub(ecx, edi);
1698 // Make edi the space we need for the array when it is unrolled onto the
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001699 // stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001700 __ mov(edi, ebx);
1701 __ shl(edi, kPointerSizeLog2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001702 // Check if the arguments will overflow the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001703 __ cmp(ecx, edi);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001704 __ j(less_equal, stack_overflow); // Signed comparison.
1705}
1706
1707
1708static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1709 __ push(ebp);
1710 __ mov(ebp, esp);
1711
1712 // Store the arguments adaptor context sentinel.
1713 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
1714
1715 // Push the function on the stack.
1716 __ push(edi);
1717
1718 // Preserve the number of arguments on the stack. Must preserve eax,
1719 // ebx and ecx because these registers are used when copying the
1720 // arguments and the receiver.
1721 STATIC_ASSERT(kSmiTagSize == 1);
1722 __ lea(edi, Operand(eax, eax, times_1, kSmiTag));
1723 __ push(edi);
1724}
1725
1726
1727static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1728 // Retrieve the number of arguments from the stack.
1729 __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1730
1731 // Leave the frame.
1732 __ leave();
1733
1734 // Remove caller arguments from the stack.
1735 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
1736 __ pop(ecx);
1737 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
1738 __ push(ecx);
1739}
1740
1741
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001742// static
1743void Builtins::Generate_Apply(MacroAssembler* masm) {
1744 // ----------- S t a t e -------------
1745 // -- eax : argumentsList
1746 // -- edi : target
1747 // -- edx : new.target (checked to be constructor or undefined)
1748 // -- esp[0] : return address.
1749 // -- esp[4] : thisArgument
1750 // -----------------------------------
1751
1752 // Create the list of arguments from the array-like argumentsList.
1753 {
1754 Label create_arguments, create_array, create_runtime, done_create;
1755 __ JumpIfSmi(eax, &create_runtime);
1756
1757 // Load the map of argumentsList into ecx.
1758 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
1759
1760 // Load native context into ebx.
1761 __ mov(ebx, NativeContextOperand());
1762
1763 // Check if argumentsList is an (unmodified) arguments object.
1764 __ cmp(ecx, ContextOperand(ebx, Context::SLOPPY_ARGUMENTS_MAP_INDEX));
1765 __ j(equal, &create_arguments);
1766 __ cmp(ecx, ContextOperand(ebx, Context::STRICT_ARGUMENTS_MAP_INDEX));
1767 __ j(equal, &create_arguments);
1768
1769 // Check if argumentsList is a fast JSArray.
1770 __ CmpInstanceType(ecx, JS_ARRAY_TYPE);
1771 __ j(equal, &create_array);
1772
1773 // Ask the runtime to create the list (actually a FixedArray).
1774 __ bind(&create_runtime);
1775 {
1776 FrameScope scope(masm, StackFrame::INTERNAL);
1777 __ Push(edi);
1778 __ Push(edx);
1779 __ Push(eax);
1780 __ CallRuntime(Runtime::kCreateListFromArrayLike);
1781 __ Pop(edx);
1782 __ Pop(edi);
1783 __ mov(ebx, FieldOperand(eax, FixedArray::kLengthOffset));
1784 __ SmiUntag(ebx);
1785 }
1786 __ jmp(&done_create);
1787
1788 // Try to create the list from an arguments object.
1789 __ bind(&create_arguments);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001790 __ mov(ebx, FieldOperand(eax, JSArgumentsObject::kLengthOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001791 __ mov(ecx, FieldOperand(eax, JSObject::kElementsOffset));
1792 __ cmp(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
1793 __ j(not_equal, &create_runtime);
1794 __ SmiUntag(ebx);
1795 __ mov(eax, ecx);
1796 __ jmp(&done_create);
1797
1798 // Try to create the list from a JSArray object.
1799 __ bind(&create_array);
1800 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
1801 __ DecodeField<Map::ElementsKindBits>(ecx);
1802 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
1803 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
1804 STATIC_ASSERT(FAST_ELEMENTS == 2);
1805 __ cmp(ecx, Immediate(FAST_ELEMENTS));
1806 __ j(above, &create_runtime);
1807 __ cmp(ecx, Immediate(FAST_HOLEY_SMI_ELEMENTS));
1808 __ j(equal, &create_runtime);
1809 __ mov(ebx, FieldOperand(eax, JSArray::kLengthOffset));
1810 __ SmiUntag(ebx);
1811 __ mov(eax, FieldOperand(eax, JSArray::kElementsOffset));
1812
1813 __ bind(&done_create);
1814 }
1815
1816 // Check for stack overflow.
1817 {
1818 // Check the stack for overflow. We are not trying to catch interruptions
1819 // (i.e. debug break and preemption) here, so check the "real stack limit".
1820 Label done;
1821 ExternalReference real_stack_limit =
1822 ExternalReference::address_of_real_stack_limit(masm->isolate());
1823 __ mov(ecx, Operand::StaticVariable(real_stack_limit));
1824 // Make ecx the space we have left. The stack might already be overflowed
1825 // here which will cause ecx to become negative.
1826 __ neg(ecx);
1827 __ add(ecx, esp);
1828 __ sar(ecx, kPointerSizeLog2);
1829 // Check if the arguments will overflow the stack.
1830 __ cmp(ecx, ebx);
1831 __ j(greater, &done, Label::kNear); // Signed comparison.
1832 __ TailCallRuntime(Runtime::kThrowStackOverflow);
1833 __ bind(&done);
1834 }
1835
1836 // ----------- S t a t e -------------
1837 // -- edi : target
1838 // -- eax : args (a FixedArray built from argumentsList)
1839 // -- ebx : len (number of elements to push from args)
1840 // -- edx : new.target (checked to be constructor or undefined)
1841 // -- esp[0] : return address.
1842 // -- esp[4] : thisArgument
1843 // -----------------------------------
1844
1845 // Push arguments onto the stack (thisArgument is already on the stack).
1846 {
1847 __ push(edx);
1848 __ fld_s(MemOperand(esp, 0));
1849 __ lea(esp, Operand(esp, kFloatSize));
1850
1851 __ PopReturnAddressTo(edx);
1852 __ Move(ecx, Immediate(0));
1853 Label done, loop;
1854 __ bind(&loop);
1855 __ cmp(ecx, ebx);
1856 __ j(equal, &done, Label::kNear);
1857 __ Push(
1858 FieldOperand(eax, ecx, times_pointer_size, FixedArray::kHeaderSize));
1859 __ inc(ecx);
1860 __ jmp(&loop);
1861 __ bind(&done);
1862 __ PushReturnAddressFrom(edx);
1863
1864 __ lea(esp, Operand(esp, -kFloatSize));
1865 __ fstp_s(MemOperand(esp, 0));
1866 __ pop(edx);
1867
1868 __ Move(eax, ebx);
1869 }
1870
1871 // Dispatch to Call or Construct depending on whether new.target is undefined.
1872 {
1873 __ CompareRoot(edx, Heap::kUndefinedValueRootIndex);
1874 __ j(equal, masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1875 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
1876 }
1877}
1878
Ben Murdoch097c5b22016-05-18 11:27:45 +01001879namespace {
1880
1881// Drops top JavaScript frame and an arguments adaptor frame below it (if
1882// present) preserving all the arguments prepared for current call.
1883// Does nothing if debugger is currently active.
1884// ES6 14.6.3. PrepareForTailCall
1885//
1886// Stack structure for the function g() tail calling f():
1887//
1888// ------- Caller frame: -------
1889// | ...
1890// | g()'s arg M
1891// | ...
1892// | g()'s arg 1
1893// | g()'s receiver arg
1894// | g()'s caller pc
1895// ------- g()'s frame: -------
1896// | g()'s caller fp <- fp
1897// | g()'s context
1898// | function pointer: g
1899// | -------------------------
1900// | ...
1901// | ...
1902// | f()'s arg N
1903// | ...
1904// | f()'s arg 1
1905// | f()'s receiver arg
1906// | f()'s caller pc <- sp
1907// ----------------------
1908//
1909void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
1910 Register scratch1, Register scratch2,
1911 Register scratch3) {
1912 DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
1913 Comment cmnt(masm, "[ PrepareForTailCall");
1914
Ben Murdochda12d292016-06-02 14:46:10 +01001915 // Prepare for tail call only if ES2015 tail call elimination is enabled.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001916 Label done;
Ben Murdochda12d292016-06-02 14:46:10 +01001917 ExternalReference is_tail_call_elimination_enabled =
1918 ExternalReference::is_tail_call_elimination_enabled_address(
1919 masm->isolate());
1920 __ movzx_b(scratch1,
1921 Operand::StaticVariable(is_tail_call_elimination_enabled));
Ben Murdoch097c5b22016-05-18 11:27:45 +01001922 __ cmp(scratch1, Immediate(0));
Ben Murdochda12d292016-06-02 14:46:10 +01001923 __ j(equal, &done, Label::kNear);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001924
1925 // Drop possible interpreter handler/stub frame.
1926 {
1927 Label no_interpreter_frame;
Ben Murdochda12d292016-06-02 14:46:10 +01001928 __ cmp(Operand(ebp, CommonFrameConstants::kContextOrFrameTypeOffset),
Ben Murdoch097c5b22016-05-18 11:27:45 +01001929 Immediate(Smi::FromInt(StackFrame::STUB)));
1930 __ j(not_equal, &no_interpreter_frame, Label::kNear);
1931 __ mov(ebp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
1932 __ bind(&no_interpreter_frame);
1933 }
1934
1935 // Check if next frame is an arguments adaptor frame.
Ben Murdochda12d292016-06-02 14:46:10 +01001936 Register caller_args_count_reg = scratch1;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001937 Label no_arguments_adaptor, formal_parameter_count_loaded;
1938 __ mov(scratch2, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
Ben Murdochda12d292016-06-02 14:46:10 +01001939 __ cmp(Operand(scratch2, CommonFrameConstants::kContextOrFrameTypeOffset),
Ben Murdoch097c5b22016-05-18 11:27:45 +01001940 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
1941 __ j(not_equal, &no_arguments_adaptor, Label::kNear);
1942
Ben Murdochda12d292016-06-02 14:46:10 +01001943 // Drop current frame and load arguments count from arguments adaptor frame.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001944 __ mov(ebp, scratch2);
Ben Murdochda12d292016-06-02 14:46:10 +01001945 __ mov(caller_args_count_reg,
1946 Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1947 __ SmiUntag(caller_args_count_reg);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001948 __ jmp(&formal_parameter_count_loaded, Label::kNear);
1949
1950 __ bind(&no_arguments_adaptor);
1951 // Load caller's formal parameter count
1952 __ mov(scratch1, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1953 __ mov(scratch1,
1954 FieldOperand(scratch1, JSFunction::kSharedFunctionInfoOffset));
1955 __ mov(
Ben Murdochda12d292016-06-02 14:46:10 +01001956 caller_args_count_reg,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001957 FieldOperand(scratch1, SharedFunctionInfo::kFormalParameterCountOffset));
Ben Murdochda12d292016-06-02 14:46:10 +01001958 __ SmiUntag(caller_args_count_reg);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001959
1960 __ bind(&formal_parameter_count_loaded);
1961
Ben Murdochda12d292016-06-02 14:46:10 +01001962 ParameterCount callee_args_count(args_reg);
1963 __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
1964 scratch3, ReturnAddressState::kOnStack, 0);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001965 __ bind(&done);
1966}
1967} // namespace
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001968
1969// static
1970void Builtins::Generate_CallFunction(MacroAssembler* masm,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001971 ConvertReceiverMode mode,
1972 TailCallMode tail_call_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001973 // ----------- S t a t e -------------
1974 // -- eax : the number of arguments (not including the receiver)
1975 // -- edi : the function to call (checked to be a JSFunction)
1976 // -----------------------------------
1977 __ AssertFunction(edi);
1978
1979 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
1980 // Check that the function is not a "classConstructor".
1981 Label class_constructor;
1982 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1983 __ test_b(FieldOperand(edx, SharedFunctionInfo::kFunctionKindByteOffset),
Ben Murdochda12d292016-06-02 14:46:10 +01001984 Immediate(SharedFunctionInfo::kClassConstructorBitsWithinByte));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001985 __ j(not_zero, &class_constructor);
1986
1987 // Enter the context of the function; ToObject has to run in the function
1988 // context, and we also need to take the global proxy from the function
1989 // context in case of conversion.
1990 STATIC_ASSERT(SharedFunctionInfo::kNativeByteOffset ==
1991 SharedFunctionInfo::kStrictModeByteOffset);
1992 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1993 // We need to convert the receiver for non-native sloppy mode functions.
1994 Label done_convert;
1995 __ test_b(FieldOperand(edx, SharedFunctionInfo::kNativeByteOffset),
Ben Murdochda12d292016-06-02 14:46:10 +01001996 Immediate((1 << SharedFunctionInfo::kNativeBitWithinByte) |
1997 (1 << SharedFunctionInfo::kStrictModeBitWithinByte)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001998 __ j(not_zero, &done_convert);
1999 {
2000 // ----------- S t a t e -------------
2001 // -- eax : the number of arguments (not including the receiver)
2002 // -- edx : the shared function info.
2003 // -- edi : the function to call (checked to be a JSFunction)
2004 // -- esi : the function context.
2005 // -----------------------------------
2006
2007 if (mode == ConvertReceiverMode::kNullOrUndefined) {
2008 // Patch receiver to global proxy.
2009 __ LoadGlobalProxy(ecx);
2010 } else {
2011 Label convert_to_object, convert_receiver;
2012 __ mov(ecx, Operand(esp, eax, times_pointer_size, kPointerSize));
2013 __ JumpIfSmi(ecx, &convert_to_object, Label::kNear);
2014 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
2015 __ CmpObjectType(ecx, FIRST_JS_RECEIVER_TYPE, ebx);
2016 __ j(above_equal, &done_convert);
2017 if (mode != ConvertReceiverMode::kNotNullOrUndefined) {
2018 Label convert_global_proxy;
2019 __ JumpIfRoot(ecx, Heap::kUndefinedValueRootIndex,
2020 &convert_global_proxy, Label::kNear);
2021 __ JumpIfNotRoot(ecx, Heap::kNullValueRootIndex, &convert_to_object,
2022 Label::kNear);
2023 __ bind(&convert_global_proxy);
2024 {
2025 // Patch receiver to global proxy.
2026 __ LoadGlobalProxy(ecx);
2027 }
2028 __ jmp(&convert_receiver);
2029 }
2030 __ bind(&convert_to_object);
2031 {
2032 // Convert receiver using ToObject.
2033 // TODO(bmeurer): Inline the allocation here to avoid building the frame
2034 // in the fast case? (fall back to AllocateInNewSpace?)
2035 FrameScope scope(masm, StackFrame::INTERNAL);
2036 __ SmiTag(eax);
2037 __ Push(eax);
2038 __ Push(edi);
2039 __ mov(eax, ecx);
2040 ToObjectStub stub(masm->isolate());
2041 __ CallStub(&stub);
2042 __ mov(ecx, eax);
2043 __ Pop(edi);
2044 __ Pop(eax);
2045 __ SmiUntag(eax);
2046 }
2047 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2048 __ bind(&convert_receiver);
2049 }
2050 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ecx);
2051 }
2052 __ bind(&done_convert);
2053
2054 // ----------- S t a t e -------------
2055 // -- eax : the number of arguments (not including the receiver)
2056 // -- edx : the shared function info.
2057 // -- edi : the function to call (checked to be a JSFunction)
2058 // -- esi : the function context.
2059 // -----------------------------------
2060
Ben Murdoch097c5b22016-05-18 11:27:45 +01002061 if (tail_call_mode == TailCallMode::kAllow) {
2062 PrepareForTailCall(masm, eax, ebx, ecx, edx);
2063 // Reload shared function info.
2064 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2065 }
2066
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002067 __ mov(ebx,
2068 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
2069 __ SmiUntag(ebx);
2070 ParameterCount actual(eax);
2071 ParameterCount expected(ebx);
2072 __ InvokeFunctionCode(edi, no_reg, expected, actual, JUMP_FUNCTION,
2073 CheckDebugStepCallWrapper());
2074 // The function is a "classConstructor", need to raise an exception.
2075 __ bind(&class_constructor);
2076 {
2077 FrameScope frame(masm, StackFrame::INTERNAL);
2078 __ push(edi);
2079 __ CallRuntime(Runtime::kThrowConstructorNonCallableError);
2080 }
2081}
2082
2083
2084namespace {
2085
2086void Generate_PushBoundArguments(MacroAssembler* masm) {
2087 // ----------- S t a t e -------------
2088 // -- eax : the number of arguments (not including the receiver)
2089 // -- edx : new.target (only in case of [[Construct]])
2090 // -- edi : target (checked to be a JSBoundFunction)
2091 // -----------------------------------
2092
2093 // Load [[BoundArguments]] into ecx and length of that into ebx.
2094 Label no_bound_arguments;
2095 __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset));
2096 __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
2097 __ SmiUntag(ebx);
2098 __ test(ebx, ebx);
2099 __ j(zero, &no_bound_arguments);
2100 {
2101 // ----------- S t a t e -------------
2102 // -- eax : the number of arguments (not including the receiver)
2103 // -- edx : new.target (only in case of [[Construct]])
2104 // -- edi : target (checked to be a JSBoundFunction)
2105 // -- ecx : the [[BoundArguments]] (implemented as FixedArray)
2106 // -- ebx : the number of [[BoundArguments]]
2107 // -----------------------------------
2108
2109 // Reserve stack space for the [[BoundArguments]].
2110 {
2111 Label done;
2112 __ lea(ecx, Operand(ebx, times_pointer_size, 0));
2113 __ sub(esp, ecx);
2114 // Check the stack for overflow. We are not trying to catch interruptions
2115 // (i.e. debug break and preemption) here, so check the "real stack
2116 // limit".
2117 __ CompareRoot(esp, ecx, Heap::kRealStackLimitRootIndex);
2118 __ j(greater, &done, Label::kNear); // Signed comparison.
2119 // Restore the stack pointer.
2120 __ lea(esp, Operand(esp, ebx, times_pointer_size, 0));
2121 {
2122 FrameScope scope(masm, StackFrame::MANUAL);
2123 __ EnterFrame(StackFrame::INTERNAL);
2124 __ CallRuntime(Runtime::kThrowStackOverflow);
2125 }
2126 __ bind(&done);
2127 }
2128
2129 // Adjust effective number of arguments to include return address.
2130 __ inc(eax);
2131
2132 // Relocate arguments and return address down the stack.
2133 {
2134 Label loop;
2135 __ Set(ecx, 0);
2136 __ lea(ebx, Operand(esp, ebx, times_pointer_size, 0));
2137 __ bind(&loop);
2138 __ fld_s(Operand(ebx, ecx, times_pointer_size, 0));
2139 __ fstp_s(Operand(esp, ecx, times_pointer_size, 0));
2140 __ inc(ecx);
2141 __ cmp(ecx, eax);
2142 __ j(less, &loop);
2143 }
2144
2145 // Copy [[BoundArguments]] to the stack (below the arguments).
2146 {
2147 Label loop;
2148 __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset));
2149 __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
2150 __ SmiUntag(ebx);
2151 __ bind(&loop);
2152 __ dec(ebx);
2153 __ fld_s(
2154 FieldOperand(ecx, ebx, times_pointer_size, FixedArray::kHeaderSize));
2155 __ fstp_s(Operand(esp, eax, times_pointer_size, 0));
2156 __ lea(eax, Operand(eax, 1));
2157 __ j(greater, &loop);
2158 }
2159
2160 // Adjust effective number of arguments (eax contains the number of
2161 // arguments from the call plus return address plus the number of
2162 // [[BoundArguments]]), so we need to subtract one for the return address.
2163 __ dec(eax);
2164 }
2165 __ bind(&no_bound_arguments);
2166}
2167
2168} // namespace
2169
2170
2171// static
Ben Murdoch097c5b22016-05-18 11:27:45 +01002172void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm,
2173 TailCallMode tail_call_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002174 // ----------- S t a t e -------------
2175 // -- eax : the number of arguments (not including the receiver)
2176 // -- edi : the function to call (checked to be a JSBoundFunction)
2177 // -----------------------------------
2178 __ AssertBoundFunction(edi);
2179
Ben Murdoch097c5b22016-05-18 11:27:45 +01002180 if (tail_call_mode == TailCallMode::kAllow) {
2181 PrepareForTailCall(masm, eax, ebx, ecx, edx);
2182 }
2183
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002184 // Patch the receiver to [[BoundThis]].
2185 __ mov(ebx, FieldOperand(edi, JSBoundFunction::kBoundThisOffset));
2186 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ebx);
2187
2188 // Push the [[BoundArguments]] onto the stack.
2189 Generate_PushBoundArguments(masm);
2190
2191 // Call the [[BoundTargetFunction]] via the Call builtin.
2192 __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2193 __ mov(ecx, Operand::StaticVariable(ExternalReference(
2194 Builtins::kCall_ReceiverIsAny, masm->isolate())));
2195 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2196 __ jmp(ecx);
2197}
2198
2199
2200// static
Ben Murdoch097c5b22016-05-18 11:27:45 +01002201void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
2202 TailCallMode tail_call_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002203 // ----------- S t a t e -------------
2204 // -- eax : the number of arguments (not including the receiver)
2205 // -- edi : the target to call (can be any Object).
2206 // -----------------------------------
2207
2208 Label non_callable, non_function, non_smi;
2209 __ JumpIfSmi(edi, &non_callable);
2210 __ bind(&non_smi);
2211 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002212 __ j(equal, masm->isolate()->builtins()->CallFunction(mode, tail_call_mode),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002213 RelocInfo::CODE_TARGET);
2214 __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002215 __ j(equal, masm->isolate()->builtins()->CallBoundFunction(tail_call_mode),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002216 RelocInfo::CODE_TARGET);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002217
2218 // Check if target has a [[Call]] internal method.
Ben Murdochda12d292016-06-02 14:46:10 +01002219 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
2220 Immediate(1 << Map::kIsCallable));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002221 __ j(zero, &non_callable);
2222
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002223 __ CmpInstanceType(ecx, JS_PROXY_TYPE);
2224 __ j(not_equal, &non_function);
2225
Ben Murdoch097c5b22016-05-18 11:27:45 +01002226 // 0. Prepare for tail call if necessary.
2227 if (tail_call_mode == TailCallMode::kAllow) {
2228 PrepareForTailCall(masm, eax, ebx, ecx, edx);
2229 }
2230
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002231 // 1. Runtime fallback for Proxy [[Call]].
2232 __ PopReturnAddressTo(ecx);
2233 __ Push(edi);
2234 __ PushReturnAddressFrom(ecx);
2235 // Increase the arguments size to include the pushed function and the
2236 // existing receiver on the stack.
2237 __ add(eax, Immediate(2));
2238 // Tail-call to the runtime.
2239 __ JumpToExternalReference(
2240 ExternalReference(Runtime::kJSProxyCall, masm->isolate()));
2241
2242 // 2. Call to something else, which might have a [[Call]] internal method (if
2243 // not we raise an exception).
2244 __ bind(&non_function);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002245 // Overwrite the original receiver with the (original) target.
2246 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
2247 // Let the "call_as_function_delegate" take care of the rest.
2248 __ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, edi);
2249 __ Jump(masm->isolate()->builtins()->CallFunction(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002250 ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002251 RelocInfo::CODE_TARGET);
2252
2253 // 3. Call to something that is not callable.
2254 __ bind(&non_callable);
2255 {
2256 FrameScope scope(masm, StackFrame::INTERNAL);
2257 __ Push(edi);
2258 __ CallRuntime(Runtime::kThrowCalledNonCallable);
2259 }
2260}
2261
2262
2263// static
2264void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
2265 // ----------- S t a t e -------------
2266 // -- eax : the number of arguments (not including the receiver)
2267 // -- edx : the new target (checked to be a constructor)
2268 // -- edi : the constructor to call (checked to be a JSFunction)
2269 // -----------------------------------
2270 __ AssertFunction(edi);
2271
2272 // Calling convention for function specific ConstructStubs require
2273 // ebx to contain either an AllocationSite or undefined.
2274 __ LoadRoot(ebx, Heap::kUndefinedValueRootIndex);
2275
2276 // Tail call to the function-specific construct stub (still in the caller
2277 // context at this point).
2278 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2279 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset));
2280 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2281 __ jmp(ecx);
2282}
2283
2284
2285// static
2286void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) {
2287 // ----------- S t a t e -------------
2288 // -- eax : the number of arguments (not including the receiver)
2289 // -- edx : the new target (checked to be a constructor)
2290 // -- edi : the constructor to call (checked to be a JSBoundFunction)
2291 // -----------------------------------
2292 __ AssertBoundFunction(edi);
2293
2294 // Push the [[BoundArguments]] onto the stack.
2295 Generate_PushBoundArguments(masm);
2296
2297 // Patch new.target to [[BoundTargetFunction]] if new.target equals target.
2298 {
2299 Label done;
2300 __ cmp(edi, edx);
2301 __ j(not_equal, &done, Label::kNear);
2302 __ mov(edx, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2303 __ bind(&done);
2304 }
2305
2306 // Construct the [[BoundTargetFunction]] via the Construct builtin.
2307 __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2308 __ mov(ecx, Operand::StaticVariable(
2309 ExternalReference(Builtins::kConstruct, masm->isolate())));
2310 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2311 __ jmp(ecx);
2312}
2313
2314
2315// static
2316void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
2317 // ----------- S t a t e -------------
2318 // -- eax : the number of arguments (not including the receiver)
2319 // -- edi : the constructor to call (checked to be a JSProxy)
2320 // -- edx : the new target (either the same as the constructor or
2321 // the JSFunction on which new was invoked initially)
2322 // -----------------------------------
2323
2324 // Call into the Runtime for Proxy [[Construct]].
2325 __ PopReturnAddressTo(ecx);
2326 __ Push(edi);
2327 __ Push(edx);
2328 __ PushReturnAddressFrom(ecx);
2329 // Include the pushed new_target, constructor and the receiver.
2330 __ add(eax, Immediate(3));
2331 // Tail-call to the runtime.
2332 __ JumpToExternalReference(
2333 ExternalReference(Runtime::kJSProxyConstruct, masm->isolate()));
2334}
2335
2336
2337// static
2338void Builtins::Generate_Construct(MacroAssembler* masm) {
2339 // ----------- S t a t e -------------
2340 // -- eax : the number of arguments (not including the receiver)
2341 // -- edx : the new target (either the same as the constructor or
2342 // the JSFunction on which new was invoked initially)
2343 // -- edi : the constructor to call (can be any Object)
2344 // -----------------------------------
2345
2346 // Check if target is a Smi.
2347 Label non_constructor;
2348 __ JumpIfSmi(edi, &non_constructor, Label::kNear);
2349
2350 // Dispatch based on instance type.
2351 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
2352 __ j(equal, masm->isolate()->builtins()->ConstructFunction(),
2353 RelocInfo::CODE_TARGET);
2354
2355 // Check if target has a [[Construct]] internal method.
Ben Murdochda12d292016-06-02 14:46:10 +01002356 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
2357 Immediate(1 << Map::kIsConstructor));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002358 __ j(zero, &non_constructor, Label::kNear);
2359
2360 // Only dispatch to bound functions after checking whether they are
2361 // constructors.
2362 __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE);
2363 __ j(equal, masm->isolate()->builtins()->ConstructBoundFunction(),
2364 RelocInfo::CODE_TARGET);
2365
2366 // Only dispatch to proxies after checking whether they are constructors.
2367 __ CmpInstanceType(ecx, JS_PROXY_TYPE);
2368 __ j(equal, masm->isolate()->builtins()->ConstructProxy(),
2369 RelocInfo::CODE_TARGET);
2370
2371 // Called Construct on an exotic Object with a [[Construct]] internal method.
2372 {
2373 // Overwrite the original receiver with the (original) target.
2374 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
2375 // Let the "call_as_constructor_delegate" take care of the rest.
2376 __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, edi);
2377 __ Jump(masm->isolate()->builtins()->CallFunction(),
2378 RelocInfo::CODE_TARGET);
2379 }
2380
2381 // Called Construct on an Object that doesn't have a [[Construct]] internal
2382 // method.
2383 __ bind(&non_constructor);
2384 __ Jump(masm->isolate()->builtins()->ConstructedNonConstructable(),
2385 RelocInfo::CODE_TARGET);
2386}
2387
2388
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002389void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
2390 // ----------- S t a t e -------------
2391 // -- eax : actual number of arguments
2392 // -- ebx : expected number of arguments
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002393 // -- edx : new target (passed through to callee)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002394 // -- edi : function (passed through to callee)
2395 // -----------------------------------
2396
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002397 Label invoke, dont_adapt_arguments, stack_overflow;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002398 __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1);
2399
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002400 Label enough, too_few;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002401 __ cmp(eax, ebx);
2402 __ j(less, &too_few);
2403 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
2404 __ j(equal, &dont_adapt_arguments);
2405
2406 { // Enough parameters: Actual >= expected.
2407 __ bind(&enough);
2408 EnterArgumentsAdaptorFrame(masm);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002409 ArgumentsAdaptorStackCheck(masm, &stack_overflow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002410
2411 // Copy receiver and all expected arguments.
2412 const int offset = StandardFrameConstants::kCallerSPOffset;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002413 __ lea(edi, Operand(ebp, eax, times_4, offset));
2414 __ mov(eax, -1); // account for receiver
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002415
2416 Label copy;
2417 __ bind(&copy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002418 __ inc(eax);
2419 __ push(Operand(edi, 0));
2420 __ sub(edi, Immediate(kPointerSize));
2421 __ cmp(eax, ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002422 __ j(less, &copy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002423 // eax now contains the expected number of arguments.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002424 __ jmp(&invoke);
2425 }
2426
2427 { // Too few parameters: Actual < expected.
2428 __ bind(&too_few);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002429
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002430 EnterArgumentsAdaptorFrame(masm);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002431 ArgumentsAdaptorStackCheck(masm, &stack_overflow);
2432
2433 // Remember expected arguments in ecx.
2434 __ mov(ecx, ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002435
2436 // Copy receiver and all actual arguments.
2437 const int offset = StandardFrameConstants::kCallerSPOffset;
2438 __ lea(edi, Operand(ebp, eax, times_4, offset));
2439 // ebx = expected - actual.
2440 __ sub(ebx, eax);
2441 // eax = -actual - 1
2442 __ neg(eax);
2443 __ sub(eax, Immediate(1));
2444
2445 Label copy;
2446 __ bind(&copy);
2447 __ inc(eax);
2448 __ push(Operand(edi, 0));
2449 __ sub(edi, Immediate(kPointerSize));
2450 __ test(eax, eax);
2451 __ j(not_zero, &copy);
2452
2453 // Fill remaining expected arguments with undefined values.
2454 Label fill;
2455 __ bind(&fill);
2456 __ inc(eax);
2457 __ push(Immediate(masm->isolate()->factory()->undefined_value()));
2458 __ cmp(eax, ebx);
2459 __ j(less, &fill);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002460
2461 // Restore expected arguments.
2462 __ mov(eax, ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002463 }
2464
2465 // Call the entry point.
2466 __ bind(&invoke);
2467 // Restore function pointer.
Ben Murdochda12d292016-06-02 14:46:10 +01002468 __ mov(edi, Operand(ebp, ArgumentsAdaptorFrameConstants::kFunctionOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002469 // eax : expected number of arguments
2470 // edx : new target (passed through to callee)
2471 // edi : function (passed through to callee)
2472 __ mov(ecx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
2473 __ call(ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002474
2475 // Store offset of return address for deoptimizer.
2476 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
2477
2478 // Leave frame and return.
2479 LeaveArgumentsAdaptorFrame(masm);
2480 __ ret(0);
2481
2482 // -------------------------------------------
2483 // Dont adapt arguments.
2484 // -------------------------------------------
2485 __ bind(&dont_adapt_arguments);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002486 __ mov(ecx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
2487 __ jmp(ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002488
2489 __ bind(&stack_overflow);
2490 {
2491 FrameScope frame(masm, StackFrame::MANUAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002492 __ CallRuntime(Runtime::kThrowStackOverflow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002493 __ int3();
2494 }
2495}
2496
2497
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002498static void CompatibleReceiverCheck(MacroAssembler* masm, Register receiver,
2499 Register function_template_info,
2500 Register scratch0, Register scratch1,
2501 Label* receiver_check_failed) {
2502 // If there is no signature, return the holder.
2503 __ CompareRoot(FieldOperand(function_template_info,
2504 FunctionTemplateInfo::kSignatureOffset),
2505 Heap::kUndefinedValueRootIndex);
2506 Label receiver_check_passed;
2507 __ j(equal, &receiver_check_passed, Label::kNear);
2508
2509 // Walk the prototype chain.
2510 __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
2511 Label prototype_loop_start;
2512 __ bind(&prototype_loop_start);
2513
2514 // Get the constructor, if any.
2515 __ GetMapConstructor(scratch0, scratch0, scratch1);
2516 __ CmpInstanceType(scratch1, JS_FUNCTION_TYPE);
2517 Label next_prototype;
2518 __ j(not_equal, &next_prototype, Label::kNear);
2519
2520 // Get the constructor's signature.
2521 __ mov(scratch0,
2522 FieldOperand(scratch0, JSFunction::kSharedFunctionInfoOffset));
2523 __ mov(scratch0,
2524 FieldOperand(scratch0, SharedFunctionInfo::kFunctionDataOffset));
2525
2526 // Loop through the chain of inheriting function templates.
2527 Label function_template_loop;
2528 __ bind(&function_template_loop);
2529
2530 // If the signatures match, we have a compatible receiver.
2531 __ cmp(scratch0, FieldOperand(function_template_info,
2532 FunctionTemplateInfo::kSignatureOffset));
2533 __ j(equal, &receiver_check_passed, Label::kNear);
2534
2535 // If the current type is not a FunctionTemplateInfo, load the next prototype
2536 // in the chain.
2537 __ JumpIfSmi(scratch0, &next_prototype, Label::kNear);
2538 __ CmpObjectType(scratch0, FUNCTION_TEMPLATE_INFO_TYPE, scratch1);
2539 __ j(not_equal, &next_prototype, Label::kNear);
2540
2541 // Otherwise load the parent function template and iterate.
2542 __ mov(scratch0,
2543 FieldOperand(scratch0, FunctionTemplateInfo::kParentTemplateOffset));
2544 __ jmp(&function_template_loop, Label::kNear);
2545
2546 // Load the next prototype.
2547 __ bind(&next_prototype);
2548 __ mov(receiver, FieldOperand(receiver, HeapObject::kMapOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002549 __ test(FieldOperand(receiver, Map::kBitField3Offset),
2550 Immediate(Map::HasHiddenPrototype::kMask));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002551 __ j(zero, receiver_check_failed);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002552
2553 __ mov(receiver, FieldOperand(receiver, Map::kPrototypeOffset));
2554 __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002555 // Iterate.
2556 __ jmp(&prototype_loop_start, Label::kNear);
2557
2558 __ bind(&receiver_check_passed);
2559}
2560
2561
2562void Builtins::Generate_HandleFastApiCall(MacroAssembler* masm) {
2563 // ----------- S t a t e -------------
2564 // -- eax : number of arguments (not including the receiver)
2565 // -- edi : callee
2566 // -- esi : context
2567 // -- esp[0] : return address
2568 // -- esp[4] : last argument
2569 // -- ...
2570 // -- esp[eax * 4] : first argument
2571 // -- esp[(eax + 1) * 4] : receiver
2572 // -----------------------------------
2573
2574 // Load the FunctionTemplateInfo.
2575 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2576 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kFunctionDataOffset));
2577
2578 // Do the compatible receiver check.
2579 Label receiver_check_failed;
2580 __ mov(ecx, Operand(esp, eax, times_pointer_size, kPCOnStackSize));
2581 __ Push(eax);
2582 CompatibleReceiverCheck(masm, ecx, ebx, edx, eax, &receiver_check_failed);
2583 __ Pop(eax);
2584 // Get the callback offset from the FunctionTemplateInfo, and jump to the
2585 // beginning of the code.
2586 __ mov(edx, FieldOperand(ebx, FunctionTemplateInfo::kCallCodeOffset));
2587 __ mov(edx, FieldOperand(edx, CallHandlerInfo::kFastHandlerOffset));
2588 __ add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag));
2589 __ jmp(edx);
2590
2591 // Compatible receiver check failed: pop return address, arguments and
2592 // receiver and throw an Illegal Invocation exception.
2593 __ bind(&receiver_check_failed);
2594 __ Pop(eax);
2595 __ PopReturnAddressTo(ebx);
2596 __ lea(eax, Operand(eax, times_pointer_size, 1 * kPointerSize));
2597 __ add(esp, eax);
2598 __ PushReturnAddressFrom(ebx);
2599 {
2600 FrameScope scope(masm, StackFrame::INTERNAL);
2601 __ TailCallRuntime(Runtime::kThrowIllegalInvocation);
2602 }
2603}
2604
2605
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002606void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
2607 // Lookup the function in the JavaScript frame.
2608 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
2609 {
2610 FrameScope scope(masm, StackFrame::INTERNAL);
2611 // Pass function as argument.
2612 __ push(eax);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002613 __ CallRuntime(Runtime::kCompileForOnStackReplacement);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002614 }
2615
2616 Label skip;
2617 // If the code object is null, just return to the unoptimized code.
2618 __ cmp(eax, Immediate(0));
2619 __ j(not_equal, &skip, Label::kNear);
2620 __ ret(0);
2621
2622 __ bind(&skip);
2623
2624 // Load deoptimization data from the code object.
2625 __ mov(ebx, Operand(eax, Code::kDeoptimizationDataOffset - kHeapObjectTag));
2626
2627 // Load the OSR entrypoint offset from the deoptimization data.
2628 __ mov(ebx, Operand(ebx, FixedArray::OffsetOfElementAt(
2629 DeoptimizationInputData::kOsrPcOffsetIndex) - kHeapObjectTag));
2630 __ SmiUntag(ebx);
2631
2632 // Compute the target address = code_obj + header_size + osr_offset
2633 __ lea(eax, Operand(eax, ebx, times_1, Code::kHeaderSize - kHeapObjectTag));
2634
2635 // Overwrite the return address on the stack.
2636 __ mov(Operand(esp, 0), eax);
2637
2638 // And "return" to the OSR entry point of the function.
2639 __ ret(0);
2640}
2641
2642
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002643#undef __
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002644} // namespace internal
2645} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002646
2647#endif // V8_TARGET_ARCH_X87