blob: ce07908d93e52f8cb134c1b81f31d0729b42da81 [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
126 // -- edi: constructor function
127 // -- ebx: allocation site or undefined
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000128 // -- edx: new target
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000129 // -----------------------------------
130
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000131 // Enter a construct frame.
132 {
133 FrameScope scope(masm, StackFrame::CONSTRUCT);
134
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000135 // Preserve the incoming parameters on the stack.
136 __ AssertUndefinedOrAllocationSite(ebx);
137 __ push(ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000138 __ SmiTag(eax);
139 __ push(eax);
140
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000141 if (create_implicit_receiver) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100142 // Allocate the new receiver object.
143 __ Push(edi);
144 __ Push(edx);
145 FastNewObjectStub stub(masm->isolate());
146 __ CallStub(&stub);
147 __ mov(ebx, eax);
148 __ Pop(edx);
149 __ Pop(edi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000150
Ben Murdoch097c5b22016-05-18 11:27:45 +0100151 // ----------- S t a t e -------------
152 // -- edi: constructor function
153 // -- ebx: newly allocated object
154 // -- edx: new target
155 // -----------------------------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000156
157 // Retrieve smi-tagged arguments count from the stack.
158 __ mov(eax, Operand(esp, 0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000159 }
160
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000161 __ SmiUntag(eax);
162
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000163 if (create_implicit_receiver) {
164 // Push the allocated receiver to the stack. We need two copies
165 // because we may have to return the original one and the calling
166 // conventions dictate that the called function pops the receiver.
167 __ push(ebx);
168 __ push(ebx);
169 } else {
170 __ PushRoot(Heap::kTheHoleValueRootIndex);
171 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000172
173 // Set up pointer to last argument.
174 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
175
176 // Copy arguments and receiver to the expression stack.
177 Label loop, entry;
178 __ mov(ecx, eax);
179 __ jmp(&entry);
180 __ bind(&loop);
181 __ push(Operand(ebx, ecx, times_4, 0));
182 __ bind(&entry);
183 __ dec(ecx);
184 __ j(greater_equal, &loop);
185
186 // Call the function.
187 if (is_api_function) {
188 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
189 Handle<Code> code =
190 masm->isolate()->builtins()->HandleApiCallConstruct();
191 __ call(code, RelocInfo::CODE_TARGET);
192 } else {
193 ParameterCount actual(eax);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000194 __ InvokeFunction(edi, edx, actual, CALL_FUNCTION,
195 CheckDebugStepCallWrapper());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000196 }
197
198 // Store offset of return address for deoptimizer.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000199 if (create_implicit_receiver && !is_api_function) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000200 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
201 }
202
203 // Restore context from the frame.
204 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
205
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000206 if (create_implicit_receiver) {
207 // If the result is an object (in the ECMA sense), we should get rid
208 // of the receiver and use the result; see ECMA-262 section 13.2.2-7
209 // on page 74.
210 Label use_receiver, exit;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000211
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000212 // If the result is a smi, it is *not* an object in the ECMA sense.
213 __ JumpIfSmi(eax, &use_receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000214
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000215 // If the type of the result (stored in its map) is less than
216 // FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense.
217 __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ecx);
218 __ j(above_equal, &exit);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000219
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000220 // Throw away the result of the constructor invocation and use the
221 // on-stack receiver as the result.
222 __ bind(&use_receiver);
223 __ mov(eax, Operand(esp, 0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000224
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000225 // Restore the arguments count and leave the construct frame. The
226 // arguments count is stored below the receiver.
227 __ bind(&exit);
228 __ mov(ebx, Operand(esp, 1 * kPointerSize));
229 } else {
230 __ mov(ebx, Operand(esp, 0));
231 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000232
233 // Leave construct frame.
234 }
235
Ben Murdoch097c5b22016-05-18 11:27:45 +0100236 // ES6 9.2.2. Step 13+
237 // Check that the result is not a Smi, indicating that the constructor result
238 // from a derived class is neither undefined nor an Object.
239 if (check_derived_construct) {
240 Label dont_throw;
241 __ JumpIfNotSmi(eax, &dont_throw);
242 {
243 FrameScope scope(masm, StackFrame::INTERNAL);
244 __ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject);
245 }
246 __ bind(&dont_throw);
247 }
248
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000249 // Remove caller arguments from the stack and return.
250 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
251 __ pop(ecx);
252 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
253 __ push(ecx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000254 if (create_implicit_receiver) {
255 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);
256 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000257 __ ret(0);
258}
259
260
261void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100262 Generate_JSConstructStubHelper(masm, false, true, false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000263}
264
265
266void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100267 Generate_JSConstructStubHelper(masm, true, false, false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000268}
269
270
271void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100272 Generate_JSConstructStubHelper(masm, false, false, false);
273}
274
275
276void Builtins::Generate_JSBuiltinsConstructStubForDerived(
277 MacroAssembler* masm) {
278 Generate_JSConstructStubHelper(masm, false, false, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000279}
280
281
282void Builtins::Generate_ConstructedNonConstructable(MacroAssembler* masm) {
283 FrameScope scope(masm, StackFrame::INTERNAL);
284 __ push(edi);
285 __ CallRuntime(Runtime::kThrowConstructedNonConstructable);
286}
287
288
289enum IsTagged { kEaxIsSmiTagged, kEaxIsUntaggedInt };
290
291
292// Clobbers ecx, edx, edi; preserves all other registers.
293static void Generate_CheckStackOverflow(MacroAssembler* masm,
294 IsTagged eax_is_tagged) {
295 // eax : the number of items to be pushed to the stack
296 //
297 // Check the stack for overflow. We are not trying to catch
298 // interruptions (e.g. debug break and preemption) here, so the "real stack
299 // limit" is checked.
300 Label okay;
301 ExternalReference real_stack_limit =
302 ExternalReference::address_of_real_stack_limit(masm->isolate());
303 __ mov(edi, Operand::StaticVariable(real_stack_limit));
304 // Make ecx the space we have left. The stack might already be overflowed
305 // here which will cause ecx to become negative.
306 __ mov(ecx, esp);
307 __ sub(ecx, edi);
308 // Make edx the space we need for the array when it is unrolled onto the
309 // stack.
310 __ mov(edx, eax);
311 int smi_tag = eax_is_tagged == kEaxIsSmiTagged ? kSmiTagSize : 0;
312 __ shl(edx, kPointerSizeLog2 - smi_tag);
313 // Check if the arguments will overflow the stack.
314 __ cmp(ecx, edx);
315 __ j(greater, &okay); // Signed comparison.
316
317 // Out of stack space.
318 __ CallRuntime(Runtime::kThrowStackOverflow);
319
320 __ bind(&okay);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000321}
322
323
324static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
325 bool is_construct) {
326 ProfileEntryHookStub::MaybeCallEntryHook(masm);
327
328 // Clear the context before we push it when entering the internal frame.
329 __ Move(esi, Immediate(0));
330
331 {
332 FrameScope scope(masm, StackFrame::INTERNAL);
333
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000334 // Setup the context (we need to use the caller context from the isolate).
335 ExternalReference context_address(Isolate::kContextAddress,
336 masm->isolate());
337 __ mov(esi, Operand::StaticVariable(context_address));
338
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000339 // Load the previous frame pointer (ebx) to access C arguments
340 __ mov(ebx, Operand(ebp, 0));
341
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000342 // Push the function and the receiver onto the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000343 __ push(Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000344 __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
345
346 // Load the number of arguments and setup pointer to the arguments.
347 __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset));
348 __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset));
349
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000350 // Check if we have enough stack space to push all arguments.
351 // Expects argument count in eax. Clobbers ecx, edx, edi.
352 Generate_CheckStackOverflow(masm, kEaxIsUntaggedInt);
353
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000354 // Copy arguments to the stack in a loop.
355 Label loop, entry;
356 __ Move(ecx, Immediate(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000357 __ jmp(&entry, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000358 __ bind(&loop);
359 __ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv
360 __ push(Operand(edx, 0)); // dereference handle
361 __ inc(ecx);
362 __ bind(&entry);
363 __ cmp(ecx, eax);
364 __ j(not_equal, &loop);
365
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000366 // Load the previous frame pointer (ebx) to access C arguments
367 __ mov(ebx, Operand(ebp, 0));
368
369 // Get the new.target and function from the frame.
370 __ mov(edx, Operand(ebx, EntryFrameConstants::kNewTargetArgOffset));
371 __ mov(edi, Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000372
373 // Invoke the code.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000374 Handle<Code> builtin = is_construct
375 ? masm->isolate()->builtins()->Construct()
376 : masm->isolate()->builtins()->Call();
377 __ Call(builtin, RelocInfo::CODE_TARGET);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000378
379 // Exit the internal frame. Notice that this also removes the empty.
380 // context and the function left on the stack by the code
381 // invocation.
382 }
383 __ ret(kPointerSize); // Remove receiver.
384}
385
386
387void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
388 Generate_JSEntryTrampolineHelper(masm, false);
389}
390
391
392void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
393 Generate_JSEntryTrampolineHelper(masm, true);
394}
395
396
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000397// Generate code for entering a JS function with the interpreter.
398// On entry to the function the receiver and arguments have been pushed on the
399// stack left to right. The actual argument count matches the formal parameter
400// count expected by the function.
401//
402// The live registers are:
403// o edi: the JS function object being called
404// o edx: the new target
405// o esi: our context
406// o ebp: the caller's frame pointer
407// o esp: stack pointer (pointing to return address)
408//
Ben Murdoch097c5b22016-05-18 11:27:45 +0100409// The function builds an interpreter frame. See InterpreterFrameConstants in
410// frames.h for its layout.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000411void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
412 // Open a frame scope to indicate that there is a frame on the stack. The
413 // MANUAL indicates that the scope shouldn't actually generate code to set up
414 // the frame (that is done below).
415 FrameScope frame_scope(masm, StackFrame::MANUAL);
416 __ push(ebp); // Caller's frame pointer.
417 __ mov(ebp, esp);
418 __ push(esi); // Callee's context.
419 __ push(edi); // Callee's JS function.
420 __ push(edx); // Callee's new target.
421
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000422 // Get the bytecode array from the function object and load the pointer to the
423 // first entry into edi (InterpreterBytecodeRegister).
424 __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100425
426 Label load_debug_bytecode_array, bytecode_array_loaded;
427 __ cmp(FieldOperand(eax, SharedFunctionInfo::kDebugInfoOffset),
428 Immediate(DebugInfo::uninitialized()));
429 __ j(not_equal, &load_debug_bytecode_array);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000430 __ mov(kInterpreterBytecodeArrayRegister,
431 FieldOperand(eax, SharedFunctionInfo::kFunctionDataOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100432 __ bind(&bytecode_array_loaded);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000433
434 if (FLAG_debug_code) {
435 // Check function data field is actually a BytecodeArray object.
436 __ AssertNotSmi(kInterpreterBytecodeArrayRegister);
437 __ CmpObjectType(kInterpreterBytecodeArrayRegister, BYTECODE_ARRAY_TYPE,
438 eax);
439 __ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
440 }
441
Ben Murdoch097c5b22016-05-18 11:27:45 +0100442 // Push bytecode array.
443 __ push(kInterpreterBytecodeArrayRegister);
444 // Push zero for bytecode array offset.
445 __ push(Immediate(0));
446
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000447 // Allocate the local and temporary register file on the stack.
448 {
449 // Load frame size from the BytecodeArray object.
450 __ mov(ebx, FieldOperand(kInterpreterBytecodeArrayRegister,
451 BytecodeArray::kFrameSizeOffset));
452
453 // Do a stack check to ensure we don't go over the limit.
454 Label ok;
455 __ mov(ecx, esp);
456 __ sub(ecx, ebx);
457 ExternalReference stack_limit =
458 ExternalReference::address_of_real_stack_limit(masm->isolate());
459 __ cmp(ecx, Operand::StaticVariable(stack_limit));
460 __ j(above_equal, &ok);
461 __ CallRuntime(Runtime::kThrowStackOverflow);
462 __ bind(&ok);
463
464 // If ok, push undefined as the initial value for all register file entries.
465 Label loop_header;
466 Label loop_check;
467 __ mov(eax, Immediate(masm->isolate()->factory()->undefined_value()));
468 __ jmp(&loop_check);
469 __ bind(&loop_header);
470 // TODO(rmcilroy): Consider doing more than one push per loop iteration.
471 __ push(eax);
472 // Continue loop if not done.
473 __ bind(&loop_check);
474 __ sub(ebx, Immediate(kPointerSize));
475 __ j(greater_equal, &loop_header);
476 }
477
478 // TODO(rmcilroy): List of things not currently dealt with here but done in
479 // fullcodegen's prologue:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000480 // - Call ProfileEntryHookStub when isolate has a function_entry_hook.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000481 // - Code aging of the BytecodeArray object.
482
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000483 // Load accumulator, register file, bytecode offset, dispatch table into
484 // registers.
485 __ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
486 __ mov(kInterpreterRegisterFileRegister, ebp);
487 __ add(kInterpreterRegisterFileRegister,
488 Immediate(InterpreterFrameConstants::kRegisterFilePointerFromFp));
489 __ mov(kInterpreterBytecodeOffsetRegister,
490 Immediate(BytecodeArray::kHeaderSize - kHeapObjectTag));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100491 __ mov(ebx, Immediate(ExternalReference::interpreter_dispatch_table_address(
492 masm->isolate())));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000493
494 // Push dispatch table as a stack located parameter to the bytecode handler.
495 DCHECK_EQ(-1, kInterpreterDispatchTableSpillSlot);
496 __ push(ebx);
497
498 // Dispatch to the first bytecode handler for the function.
499 __ movzx_b(eax, Operand(kInterpreterBytecodeArrayRegister,
500 kInterpreterBytecodeOffsetRegister, times_1, 0));
501 __ mov(ebx, Operand(ebx, eax, times_pointer_size, 0));
502 // Restore undefined_value in accumulator (eax)
503 // TODO(rmcilroy): Remove this once we move the dispatch table back into a
504 // register.
505 __ mov(eax, Immediate(masm->isolate()->factory()->undefined_value()));
506 // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
507 // and header removal.
508 __ add(ebx, Immediate(Code::kHeaderSize - kHeapObjectTag));
509 __ call(ebx);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100510
511 // Even though the first bytecode handler was called, we will never return.
512 __ Abort(kUnexpectedReturnFromBytecodeHandler);
513
514 // Load debug copy of the bytecode array.
515 __ bind(&load_debug_bytecode_array);
516 Register debug_info = kInterpreterBytecodeArrayRegister;
517 __ mov(debug_info, FieldOperand(eax, SharedFunctionInfo::kDebugInfoOffset));
518 __ mov(kInterpreterBytecodeArrayRegister,
519 FieldOperand(debug_info, DebugInfo::kAbstractCodeIndex));
520 __ jmp(&bytecode_array_loaded);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000521}
522
523
524void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
525 // TODO(rmcilroy): List of things not currently dealt with here but done in
526 // fullcodegen's EmitReturnSequence.
527 // - Supporting FLAG_trace for Runtime::TraceExit.
528 // - Support profiler (specifically decrementing profiling_counter
529 // appropriately and calling out to HandleInterrupts if necessary).
530
531 // The return value is in accumulator, which is already in rax.
532
533 // Leave the frame (also dropping the register file).
534 __ leave();
535
536 // Drop receiver + arguments and return.
537 __ mov(ebx, FieldOperand(kInterpreterBytecodeArrayRegister,
538 BytecodeArray::kParameterSizeOffset));
539 __ pop(ecx);
540 __ add(esp, ebx);
541 __ push(ecx);
542 __ ret(0);
543}
544
545
546static void Generate_InterpreterPushArgs(MacroAssembler* masm,
547 Register array_limit) {
548 // ----------- S t a t e -------------
549 // -- ebx : Pointer to the last argument in the args array.
550 // -- array_limit : Pointer to one before the first argument in the
551 // args array.
552 // -----------------------------------
553 Label loop_header, loop_check;
554 __ jmp(&loop_check);
555 __ bind(&loop_header);
556 __ Push(Operand(ebx, 0));
557 __ sub(ebx, Immediate(kPointerSize));
558 __ bind(&loop_check);
559 __ cmp(ebx, array_limit);
560 __ j(greater, &loop_header, Label::kNear);
561}
562
563
564// static
Ben Murdoch097c5b22016-05-18 11:27:45 +0100565void Builtins::Generate_InterpreterPushArgsAndCallImpl(
566 MacroAssembler* masm, TailCallMode tail_call_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000567 // ----------- S t a t e -------------
568 // -- eax : the number of arguments (not including the receiver)
569 // -- ebx : the address of the first argument to be pushed. Subsequent
570 // arguments should be consecutive above this, in the same order as
571 // they are to be pushed onto the stack.
572 // -- edi : the target to call (can be any Object).
573 // -----------------------------------
574
575 // Pop return address to allow tail-call after pushing arguments.
576 __ Pop(edx);
577
578 // Find the address of the last argument.
579 __ mov(ecx, eax);
580 __ add(ecx, Immediate(1)); // Add one for receiver.
581 __ shl(ecx, kPointerSizeLog2);
582 __ neg(ecx);
583 __ add(ecx, ebx);
584
585 Generate_InterpreterPushArgs(masm, ecx);
586
587 // Call the target.
588 __ Push(edx); // Re-push return address.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100589 __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
590 tail_call_mode),
591 RelocInfo::CODE_TARGET);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000592}
593
594
595// static
596void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
597 // ----------- S t a t e -------------
598 // -- eax : the number of arguments (not including the receiver)
599 // -- edx : the new target
600 // -- edi : the constructor
601 // -- ebx : the address of the first argument to be pushed. Subsequent
602 // arguments should be consecutive above this, in the same order as
603 // they are to be pushed onto the stack.
604 // -----------------------------------
605
606 // Save number of arguments on the stack below where arguments are going
607 // to be pushed.
608 __ mov(ecx, eax);
609 __ neg(ecx);
610 __ mov(Operand(esp, ecx, times_pointer_size, -kPointerSize), eax);
611 __ mov(eax, ecx);
612
613 // Pop return address to allow tail-call after pushing arguments.
614 __ Pop(ecx);
615
616 // Find the address of the last argument.
617 __ shl(eax, kPointerSizeLog2);
618 __ add(eax, ebx);
619
620 // Push padding for receiver.
621 __ Push(Immediate(0));
622
623 Generate_InterpreterPushArgs(masm, eax);
624
625 // Restore number of arguments from slot on stack.
626 __ mov(eax, Operand(esp, -kPointerSize));
627
628 // Re-push return address.
629 __ Push(ecx);
630
631 // Call the constructor with unmodified eax, edi, ebi values.
632 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
633}
634
635
Ben Murdoch097c5b22016-05-18 11:27:45 +0100636static void Generate_EnterBytecodeDispatch(MacroAssembler* masm) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000637 // Initialize register file register.
638 __ mov(kInterpreterRegisterFileRegister, ebp);
639 __ add(kInterpreterRegisterFileRegister,
640 Immediate(InterpreterFrameConstants::kRegisterFilePointerFromFp));
641
642 // Get the bytecode array pointer from the frame.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000643 __ mov(kInterpreterBytecodeArrayRegister,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100644 Operand(kInterpreterRegisterFileRegister,
645 InterpreterFrameConstants::kBytecodeArrayFromRegisterPointer));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000646
647 if (FLAG_debug_code) {
648 // Check function data field is actually a BytecodeArray object.
649 __ AssertNotSmi(kInterpreterBytecodeArrayRegister);
650 __ CmpObjectType(kInterpreterBytecodeArrayRegister, BYTECODE_ARRAY_TYPE,
651 ebx);
652 __ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
653 }
654
655 // Get the target bytecode offset from the frame.
656 __ mov(
657 kInterpreterBytecodeOffsetRegister,
658 Operand(kInterpreterRegisterFileRegister,
659 InterpreterFrameConstants::kBytecodeOffsetFromRegisterPointer));
660 __ SmiUntag(kInterpreterBytecodeOffsetRegister);
661
Ben Murdoch097c5b22016-05-18 11:27:45 +0100662 // Push dispatch table as a stack located parameter to the bytecode handler.
663 __ mov(ebx, Immediate(ExternalReference::interpreter_dispatch_table_address(
664 masm->isolate())));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000665 DCHECK_EQ(-1, kInterpreterDispatchTableSpillSlot);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100666 __ Pop(esi);
667 __ Push(ebx);
668 __ Push(esi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000669
670 // Dispatch to the target bytecode.
671 __ movzx_b(esi, Operand(kInterpreterBytecodeArrayRegister,
672 kInterpreterBytecodeOffsetRegister, times_1, 0));
673 __ mov(ebx, Operand(ebx, esi, times_pointer_size, 0));
674
675 // Get the context from the frame.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000676 __ mov(kContextRegister,
677 Operand(kInterpreterRegisterFileRegister,
678 InterpreterFrameConstants::kContextFromRegisterPointer));
679
680 // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
681 // and header removal.
682 __ add(ebx, Immediate(Code::kHeaderSize - kHeapObjectTag));
683 __ jmp(ebx);
684}
685
686
Ben Murdoch097c5b22016-05-18 11:27:45 +0100687static void Generate_InterpreterNotifyDeoptimizedHelper(
688 MacroAssembler* masm, Deoptimizer::BailoutType type) {
689 // Enter an internal frame.
690 {
691 FrameScope scope(masm, StackFrame::INTERNAL);
692
693 // Pass the deoptimization type to the runtime system.
694 __ Push(Smi::FromInt(static_cast<int>(type)));
695 __ CallRuntime(Runtime::kNotifyDeoptimized);
696 // Tear down internal frame.
697 }
698
699 // Drop state (we don't use these for interpreter deopts) and and pop the
700 // accumulator value into the accumulator register and push PC at top
701 // of stack (to simulate initial call to bytecode handler in interpreter entry
702 // trampoline).
703 __ Pop(ebx);
704 __ Drop(1);
705 __ Pop(kInterpreterAccumulatorRegister);
706 __ Push(ebx);
707
708 // Enter the bytecode dispatch.
709 Generate_EnterBytecodeDispatch(masm);
710}
711
712
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000713void Builtins::Generate_InterpreterNotifyDeoptimized(MacroAssembler* masm) {
714 Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
715}
716
717
718void Builtins::Generate_InterpreterNotifySoftDeoptimized(MacroAssembler* masm) {
719 Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
720}
721
722
723void Builtins::Generate_InterpreterNotifyLazyDeoptimized(MacroAssembler* masm) {
724 Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
725}
726
Ben Murdoch097c5b22016-05-18 11:27:45 +0100727void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
728 // Set the address of the interpreter entry trampoline as a return address.
729 // This simulates the initial call to bytecode handlers in interpreter entry
730 // trampoline. The return will never actually be taken, but our stack walker
731 // uses this address to determine whether a frame is interpreted.
732 __ Push(masm->isolate()->builtins()->InterpreterEntryTrampoline());
733
734 Generate_EnterBytecodeDispatch(masm);
735}
736
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000737
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000738void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100739 GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000740}
741
742
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000743void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100744 GenerateTailCallToReturnedCode(masm,
745 Runtime::kCompileOptimized_NotConcurrent);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000746}
747
748
749void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100750 GenerateTailCallToReturnedCode(masm, Runtime::kCompileOptimized_Concurrent);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000751}
752
753
754static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
755 // For now, we are relying on the fact that make_code_young doesn't do any
756 // garbage collection which allows us to save/restore the registers without
757 // worrying about which of them contain pointers. We also don't build an
758 // internal frame to make the code faster, since we shouldn't have to do stack
759 // crawls in MakeCodeYoung. This seems a bit fragile.
760
761 // Re-execute the code that was patched back to the young age when
762 // the stub returns.
763 __ sub(Operand(esp, 0), Immediate(5));
764 __ pushad();
765 __ mov(eax, Operand(esp, 8 * kPointerSize));
766 {
767 FrameScope scope(masm, StackFrame::MANUAL);
768 __ PrepareCallCFunction(2, ebx);
769 __ mov(Operand(esp, 1 * kPointerSize),
770 Immediate(ExternalReference::isolate_address(masm->isolate())));
771 __ mov(Operand(esp, 0), eax);
772 __ CallCFunction(
773 ExternalReference::get_make_code_young_function(masm->isolate()), 2);
774 }
775 __ popad();
776 __ ret(0);
777}
778
779#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \
780void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \
781 MacroAssembler* masm) { \
782 GenerateMakeCodeYoungAgainCommon(masm); \
783} \
784void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \
785 MacroAssembler* masm) { \
786 GenerateMakeCodeYoungAgainCommon(masm); \
787}
788CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
789#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
790
791
792void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
793 // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact
794 // that make_code_young doesn't do any garbage collection which allows us to
795 // save/restore the registers without worrying about which of them contain
796 // pointers.
797 __ pushad();
798 __ mov(eax, Operand(esp, 8 * kPointerSize));
799 __ sub(eax, Immediate(Assembler::kCallInstructionLength));
800 { // NOLINT
801 FrameScope scope(masm, StackFrame::MANUAL);
802 __ PrepareCallCFunction(2, ebx);
803 __ mov(Operand(esp, 1 * kPointerSize),
804 Immediate(ExternalReference::isolate_address(masm->isolate())));
805 __ mov(Operand(esp, 0), eax);
806 __ CallCFunction(
807 ExternalReference::get_mark_code_as_executed_function(masm->isolate()),
808 2);
809 }
810 __ popad();
811
812 // Perform prologue operations usually performed by the young code stub.
813 __ pop(eax); // Pop return address into scratch register.
814 __ push(ebp); // Caller's frame pointer.
815 __ mov(ebp, esp);
816 __ push(esi); // Callee's context.
817 __ push(edi); // Callee's JS Function.
818 __ push(eax); // Push return address after frame prologue.
819
820 // Jump to point after the code-age stub.
821 __ ret(0);
822}
823
824
825void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
826 GenerateMakeCodeYoungAgainCommon(masm);
827}
828
829
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000830void Builtins::Generate_MarkCodeAsToBeExecutedOnce(MacroAssembler* masm) {
831 Generate_MarkCodeAsExecutedOnce(masm);
832}
833
834
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000835static void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
836 SaveFPRegsMode save_doubles) {
837 // Enter an internal frame.
838 {
839 FrameScope scope(masm, StackFrame::INTERNAL);
840
841 // Preserve registers across notification, this is important for compiled
842 // stubs that tail call the runtime on deopts passing their parameters in
843 // registers.
844 __ pushad();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000845 __ CallRuntime(Runtime::kNotifyStubFailure, save_doubles);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000846 __ popad();
847 // Tear down internal frame.
848 }
849
850 __ pop(MemOperand(esp, 0)); // Ignore state offset
851 __ ret(0); // Return to IC Miss stub, continuation still on stack.
852}
853
854
855void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
856 Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
857}
858
859
860void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
861 Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
862}
863
864
865static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
866 Deoptimizer::BailoutType type) {
867 {
868 FrameScope scope(masm, StackFrame::INTERNAL);
869
870 // Pass deoptimization type to the runtime system.
871 __ push(Immediate(Smi::FromInt(static_cast<int>(type))));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000872 __ CallRuntime(Runtime::kNotifyDeoptimized);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000873
874 // Tear down internal frame.
875 }
876
877 // Get the full codegen state from the stack and untag it.
878 __ mov(ecx, Operand(esp, 1 * kPointerSize));
879 __ SmiUntag(ecx);
880
881 // Switch on the state.
882 Label not_no_registers, not_tos_eax;
883 __ cmp(ecx, FullCodeGenerator::NO_REGISTERS);
884 __ j(not_equal, &not_no_registers, Label::kNear);
885 __ ret(1 * kPointerSize); // Remove state.
886
887 __ bind(&not_no_registers);
888 __ mov(eax, Operand(esp, 2 * kPointerSize));
889 __ cmp(ecx, FullCodeGenerator::TOS_REG);
890 __ j(not_equal, &not_tos_eax, Label::kNear);
891 __ ret(2 * kPointerSize); // Remove state, eax.
892
893 __ bind(&not_tos_eax);
894 __ Abort(kNoCasesLeft);
895}
896
897
898void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
899 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
900}
901
902
903void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
904 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
905}
906
907
908void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
909 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
910}
911
912
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000913// static
914void Builtins::Generate_DatePrototype_GetField(MacroAssembler* masm,
915 int field_index) {
916 // ----------- S t a t e -------------
917 // -- esp[0] : return address
918 // -- esp[4] : receiver
919 // -----------------------------------
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000920
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000921 // 1. Load receiver into eax and check that it's actually a JSDate object.
922 Label receiver_not_date;
923 {
924 __ mov(eax, Operand(esp, kPointerSize));
925 __ JumpIfSmi(eax, &receiver_not_date);
926 __ CmpObjectType(eax, JS_DATE_TYPE, ebx);
927 __ j(not_equal, &receiver_not_date);
928 }
929
930 // 2. Load the specified date field, falling back to the runtime as necessary.
931 if (field_index == JSDate::kDateValue) {
932 __ mov(eax, FieldOperand(eax, JSDate::kValueOffset));
933 } else {
934 if (field_index < JSDate::kFirstUncachedField) {
935 Label stamp_mismatch;
936 __ mov(edx, Operand::StaticVariable(
937 ExternalReference::date_cache_stamp(masm->isolate())));
938 __ cmp(edx, FieldOperand(eax, JSDate::kCacheStampOffset));
939 __ j(not_equal, &stamp_mismatch, Label::kNear);
940 __ mov(eax, FieldOperand(
941 eax, JSDate::kValueOffset + field_index * kPointerSize));
942 __ ret(1 * kPointerSize);
943 __ bind(&stamp_mismatch);
944 }
945 FrameScope scope(masm, StackFrame::INTERNAL);
946 __ PrepareCallCFunction(2, ebx);
947 __ mov(Operand(esp, 0), eax);
948 __ mov(Operand(esp, 1 * kPointerSize),
949 Immediate(Smi::FromInt(field_index)));
950 __ CallCFunction(
951 ExternalReference::get_date_field_function(masm->isolate()), 2);
952 }
953 __ ret(1 * kPointerSize);
954
955 // 3. Raise a TypeError if the receiver is not a date.
956 __ bind(&receiver_not_date);
957 {
958 FrameScope scope(masm, StackFrame::MANUAL);
959 __ EnterFrame(StackFrame::INTERNAL);
960 __ CallRuntime(Runtime::kThrowNotDateError);
961 }
962}
963
964
965// static
966void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
967 // ----------- S t a t e -------------
968 // -- eax : argc
969 // -- esp[0] : return address
970 // -- esp[4] : argArray
971 // -- esp[8] : thisArg
972 // -- esp[12] : receiver
973 // -----------------------------------
974
975 // 1. Load receiver into edi, argArray into eax (if present), remove all
976 // arguments from the stack (including the receiver), and push thisArg (if
977 // present) instead.
978 {
979 Label no_arg_array, no_this_arg;
980 __ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
981 __ mov(ebx, edx);
982 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000983 __ test(eax, eax);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000984 __ j(zero, &no_this_arg, Label::kNear);
985 {
986 __ mov(edx, Operand(esp, eax, times_pointer_size, 0));
987 __ cmp(eax, Immediate(1));
988 __ j(equal, &no_arg_array, Label::kNear);
989 __ mov(ebx, Operand(esp, eax, times_pointer_size, -kPointerSize));
990 __ bind(&no_arg_array);
991 }
992 __ bind(&no_this_arg);
993 __ PopReturnAddressTo(ecx);
994 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
995 __ Push(edx);
996 __ PushReturnAddressFrom(ecx);
997 __ Move(eax, ebx);
998 }
999
1000 // ----------- S t a t e -------------
1001 // -- eax : argArray
1002 // -- edi : receiver
1003 // -- esp[0] : return address
1004 // -- esp[4] : thisArg
1005 // -----------------------------------
1006
1007 // 2. Make sure the receiver is actually callable.
1008 Label receiver_not_callable;
1009 __ JumpIfSmi(edi, &receiver_not_callable, Label::kNear);
1010 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
1011 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsCallable);
1012 __ j(zero, &receiver_not_callable, Label::kNear);
1013
1014 // 3. Tail call with no arguments if argArray is null or undefined.
1015 Label no_arguments;
1016 __ JumpIfRoot(eax, Heap::kNullValueRootIndex, &no_arguments, Label::kNear);
1017 __ JumpIfRoot(eax, Heap::kUndefinedValueRootIndex, &no_arguments,
1018 Label::kNear);
1019
1020 // 4a. Apply the receiver to the given argArray (passing undefined for
1021 // new.target).
1022 __ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
1023 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1024
1025 // 4b. The argArray is either null or undefined, so we tail call without any
1026 // arguments to the receiver.
1027 __ bind(&no_arguments);
1028 {
1029 __ Set(eax, 0);
1030 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1031 }
1032
1033 // 4c. The receiver is not callable, throw an appropriate TypeError.
1034 __ bind(&receiver_not_callable);
1035 {
1036 __ mov(Operand(esp, kPointerSize), edi);
1037 __ TailCallRuntime(Runtime::kThrowApplyNonFunction);
1038 }
1039}
1040
1041
1042// static
1043void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) {
1044 // Stack Layout:
1045 // esp[0] : Return address
1046 // esp[8] : Argument n
1047 // esp[16] : Argument n-1
1048 // ...
1049 // esp[8 * n] : Argument 1
1050 // esp[8 * (n + 1)] : Receiver (callable to call)
1051 //
1052 // eax contains the number of arguments, n, not counting the receiver.
1053 //
1054 // 1. Make sure we have at least one argument.
1055 {
1056 Label done;
1057 __ test(eax, eax);
1058 __ j(not_zero, &done, Label::kNear);
1059 __ PopReturnAddressTo(ebx);
1060 __ PushRoot(Heap::kUndefinedValueRootIndex);
1061 __ PushReturnAddressFrom(ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001062 __ inc(eax);
1063 __ bind(&done);
1064 }
1065
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001066 // 2. Get the callable to call (passed as receiver) from the stack.
1067 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001068
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001069 // 3. Shift arguments and return address one slot down on the stack
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001070 // (overwriting the original receiver). Adjust argument count to make
1071 // the original first argument the new receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001072 {
1073 Label loop;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001074 __ mov(ecx, eax);
1075 __ bind(&loop);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001076 __ mov(ebx, Operand(esp, ecx, times_pointer_size, 0));
1077 __ mov(Operand(esp, ecx, times_pointer_size, kPointerSize), ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001078 __ dec(ecx);
1079 __ j(not_sign, &loop); // While non-negative (to copy return address).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001080 __ pop(ebx); // Discard copy of return address.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001081 __ dec(eax); // One fewer argument (first argument is new receiver).
1082 }
1083
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001084 // 4. Call the callable.
1085 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001086}
1087
1088
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001089void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
1090 // ----------- S t a t e -------------
1091 // -- eax : argc
1092 // -- esp[0] : return address
1093 // -- esp[4] : argumentsList
1094 // -- esp[8] : thisArgument
1095 // -- esp[12] : target
1096 // -- esp[16] : receiver
1097 // -----------------------------------
1098
1099 // 1. Load target into edi (if present), argumentsList into eax (if present),
1100 // remove all arguments from the stack (including the receiver), and push
1101 // thisArgument (if present) instead.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001102 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001103 Label done;
1104 __ LoadRoot(edi, Heap::kUndefinedValueRootIndex);
1105 __ mov(edx, edi);
1106 __ mov(ebx, edi);
1107 __ cmp(eax, Immediate(1));
1108 __ j(below, &done, Label::kNear);
1109 __ mov(edi, Operand(esp, eax, times_pointer_size, -0 * kPointerSize));
1110 __ j(equal, &done, Label::kNear);
1111 __ mov(edx, Operand(esp, eax, times_pointer_size, -1 * kPointerSize));
1112 __ cmp(eax, Immediate(3));
1113 __ j(below, &done, Label::kNear);
1114 __ mov(ebx, Operand(esp, eax, times_pointer_size, -2 * kPointerSize));
1115 __ bind(&done);
1116 __ PopReturnAddressTo(ecx);
1117 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1118 __ Push(edx);
1119 __ PushReturnAddressFrom(ecx);
1120 __ Move(eax, ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001121 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001122
1123 // ----------- S t a t e -------------
1124 // -- eax : argumentsList
1125 // -- edi : target
1126 // -- esp[0] : return address
1127 // -- esp[4] : thisArgument
1128 // -----------------------------------
1129
1130 // 2. Make sure the target is actually callable.
1131 Label target_not_callable;
1132 __ JumpIfSmi(edi, &target_not_callable, Label::kNear);
1133 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
1134 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsCallable);
1135 __ j(zero, &target_not_callable, Label::kNear);
1136
1137 // 3a. Apply the target to the given argumentsList (passing undefined for
1138 // new.target).
1139 __ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
1140 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1141
1142 // 3b. The target is not callable, throw an appropriate TypeError.
1143 __ bind(&target_not_callable);
1144 {
1145 __ mov(Operand(esp, kPointerSize), edi);
1146 __ TailCallRuntime(Runtime::kThrowApplyNonFunction);
1147 }
1148}
1149
1150
1151void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
1152 // ----------- S t a t e -------------
1153 // -- eax : argc
1154 // -- esp[0] : return address
1155 // -- esp[4] : new.target (optional)
1156 // -- esp[8] : argumentsList
1157 // -- esp[12] : target
1158 // -- esp[16] : receiver
1159 // -----------------------------------
1160
1161 // 1. Load target into edi (if present), argumentsList into eax (if present),
1162 // new.target into edx (if present, otherwise use target), remove all
1163 // arguments from the stack (including the receiver), and push thisArgument
1164 // (if present) instead.
1165 {
1166 Label done;
1167 __ LoadRoot(edi, Heap::kUndefinedValueRootIndex);
1168 __ mov(edx, edi);
1169 __ mov(ebx, edi);
1170 __ cmp(eax, Immediate(1));
1171 __ j(below, &done, Label::kNear);
1172 __ mov(edi, Operand(esp, eax, times_pointer_size, -0 * kPointerSize));
1173 __ mov(edx, edi);
1174 __ j(equal, &done, Label::kNear);
1175 __ mov(ebx, Operand(esp, eax, times_pointer_size, -1 * kPointerSize));
1176 __ cmp(eax, Immediate(3));
1177 __ j(below, &done, Label::kNear);
1178 __ mov(edx, Operand(esp, eax, times_pointer_size, -2 * kPointerSize));
1179 __ bind(&done);
1180 __ PopReturnAddressTo(ecx);
1181 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1182 __ PushRoot(Heap::kUndefinedValueRootIndex);
1183 __ PushReturnAddressFrom(ecx);
1184 __ Move(eax, ebx);
1185 }
1186
1187 // ----------- S t a t e -------------
1188 // -- eax : argumentsList
1189 // -- edx : new.target
1190 // -- edi : target
1191 // -- esp[0] : return address
1192 // -- esp[4] : receiver (undefined)
1193 // -----------------------------------
1194
1195 // 2. Make sure the target is actually a constructor.
1196 Label target_not_constructor;
1197 __ JumpIfSmi(edi, &target_not_constructor, Label::kNear);
1198 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
1199 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsConstructor);
1200 __ j(zero, &target_not_constructor, Label::kNear);
1201
1202 // 3. Make sure the target is actually a constructor.
1203 Label new_target_not_constructor;
1204 __ JumpIfSmi(edx, &new_target_not_constructor, Label::kNear);
1205 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
1206 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsConstructor);
1207 __ j(zero, &new_target_not_constructor, Label::kNear);
1208
1209 // 4a. Construct the target with the given new.target and argumentsList.
1210 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1211
1212 // 4b. The target is not a constructor, throw an appropriate TypeError.
1213 __ bind(&target_not_constructor);
1214 {
1215 __ mov(Operand(esp, kPointerSize), edi);
1216 __ TailCallRuntime(Runtime::kThrowCalledNonCallable);
1217 }
1218
1219 // 4c. The new.target is not a constructor, throw an appropriate TypeError.
1220 __ bind(&new_target_not_constructor);
1221 {
1222 __ mov(Operand(esp, kPointerSize), edx);
1223 __ TailCallRuntime(Runtime::kThrowCalledNonCallable);
1224 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001225}
1226
1227
1228void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
1229 // ----------- S t a t e -------------
1230 // -- eax : argc
1231 // -- esp[0] : return address
1232 // -- esp[4] : last argument
1233 // -----------------------------------
1234 Label generic_array_code;
1235
1236 // Get the InternalArray function.
1237 __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi);
1238
1239 if (FLAG_debug_code) {
1240 // Initial map for the builtin InternalArray function should be a map.
1241 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1242 // Will both indicate a NULL and a Smi.
1243 __ test(ebx, Immediate(kSmiTagMask));
1244 __ Assert(not_zero, kUnexpectedInitialMapForInternalArrayFunction);
1245 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1246 __ Assert(equal, kUnexpectedInitialMapForInternalArrayFunction);
1247 }
1248
1249 // Run the native code for the InternalArray function called as a normal
1250 // function.
1251 // tail call a stub
1252 InternalArrayConstructorStub stub(masm->isolate());
1253 __ TailCallStub(&stub);
1254}
1255
1256
1257void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
1258 // ----------- S t a t e -------------
1259 // -- eax : argc
1260 // -- esp[0] : return address
1261 // -- esp[4] : last argument
1262 // -----------------------------------
1263 Label generic_array_code;
1264
1265 // Get the Array function.
1266 __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001267 __ mov(edx, edi);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001268
1269 if (FLAG_debug_code) {
1270 // Initial map for the builtin Array function should be a map.
1271 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1272 // Will both indicate a NULL and a Smi.
1273 __ test(ebx, Immediate(kSmiTagMask));
1274 __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction);
1275 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1276 __ Assert(equal, kUnexpectedInitialMapForArrayFunction);
1277 }
1278
1279 // Run the native code for the Array function called as a normal function.
1280 // tail call a stub
1281 __ mov(ebx, masm->isolate()->factory()->undefined_value());
1282 ArrayConstructorStub stub(masm->isolate());
1283 __ TailCallStub(&stub);
1284}
1285
1286
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001287// static
Ben Murdoch097c5b22016-05-18 11:27:45 +01001288void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
1289 // ----------- S t a t e -------------
1290 // -- eax : number of arguments
1291 // -- esp[0] : return address
1292 // -- esp[(argc - n) * 8] : arg[n] (zero-based)
1293 // -- esp[(argc + 1) * 8] : receiver
1294 // -----------------------------------
1295 Condition const cc = (kind == MathMaxMinKind::kMin) ? below : above;
1296 Heap::RootListIndex const root_index =
1297 (kind == MathMaxMinKind::kMin) ? Heap::kInfinityValueRootIndex
1298 : Heap::kMinusInfinityValueRootIndex;
1299 const int reg_sel = (kind == MathMaxMinKind::kMin) ? 1 : 0;
1300
1301 // Load the accumulator with the default return value (either -Infinity or
1302 // +Infinity), with the tagged value in edx and the double value in stx_0.
1303 __ LoadRoot(edx, root_index);
1304 __ fld_d(FieldOperand(edx, HeapNumber::kValueOffset));
1305 __ Move(ecx, eax);
1306
1307 Label done_loop, loop;
1308 __ bind(&loop);
1309 {
1310 // Check if all parameters done.
1311 __ test(ecx, ecx);
1312 __ j(zero, &done_loop);
1313
1314 // Load the next parameter tagged value into ebx.
1315 __ mov(ebx, Operand(esp, ecx, times_pointer_size, 0));
1316
1317 // Load the double value of the parameter into stx_1, maybe converting the
1318 // parameter to a number first using the ToNumberStub if necessary.
1319 Label convert, convert_smi, convert_number, done_convert;
1320 __ bind(&convert);
1321 __ JumpIfSmi(ebx, &convert_smi);
1322 __ JumpIfRoot(FieldOperand(ebx, HeapObject::kMapOffset),
1323 Heap::kHeapNumberMapRootIndex, &convert_number);
1324 {
1325 // Parameter is not a Number, use the ToNumberStub to convert it.
1326 FrameScope scope(masm, StackFrame::INTERNAL);
1327 __ SmiTag(eax);
1328 __ SmiTag(ecx);
1329 __ Push(eax);
1330 __ Push(ecx);
1331 __ Push(edx);
1332 __ mov(eax, ebx);
1333 ToNumberStub stub(masm->isolate());
1334 __ CallStub(&stub);
1335 __ mov(ebx, eax);
1336 __ Pop(edx);
1337 __ Pop(ecx);
1338 __ Pop(eax);
1339 {
1340 // Restore the double accumulator value (stX_0).
1341 Label restore_smi, done_restore;
1342 __ JumpIfSmi(edx, &restore_smi, Label::kNear);
1343 __ fld_d(FieldOperand(edx, HeapNumber::kValueOffset));
1344 __ jmp(&done_restore, Label::kNear);
1345 __ bind(&restore_smi);
1346 __ SmiUntag(edx);
1347 __ push(edx);
1348 __ fild_s(Operand(esp, 0));
1349 __ pop(edx);
1350 __ SmiTag(edx);
1351 __ bind(&done_restore);
1352 }
1353 __ SmiUntag(ecx);
1354 __ SmiUntag(eax);
1355 }
1356 __ jmp(&convert);
1357 __ bind(&convert_number);
1358 // Load another value into stx_1
1359 __ fld_d(FieldOperand(ebx, HeapNumber::kValueOffset));
1360 __ fxch();
1361 __ jmp(&done_convert, Label::kNear);
1362 __ bind(&convert_smi);
1363 __ SmiUntag(ebx);
1364 __ push(ebx);
1365 __ fild_s(Operand(esp, 0));
1366 __ pop(ebx);
1367 __ fxch();
1368 __ SmiTag(ebx);
1369 __ bind(&done_convert);
1370
1371 // Perform the actual comparison with the accumulator value on the left hand
1372 // side (stx_0) and the next parameter value on the right hand side (stx_1).
1373 Label compare_equal, compare_nan, compare_swap, done_compare;
1374
1375 // Duplicates the 2 float data for FCmp
1376 __ fld(1);
1377 __ fld(1);
1378 __ FCmp();
1379 __ j(parity_even, &compare_nan, Label::kNear);
1380 __ j(cc, &done_compare, Label::kNear);
1381 __ j(equal, &compare_equal, Label::kNear);
1382
1383 // Result is on the right hand side(stx_0).
1384 __ bind(&compare_swap);
1385 __ fxch();
1386 __ mov(edx, ebx);
1387 __ jmp(&done_compare, Label::kNear);
1388
1389 // At least one side is NaN, which means that the result will be NaN too.
1390 __ bind(&compare_nan);
1391 // Set the result on the right hand side (stx_0) to nan
1392 __ fstp(0);
1393 __ LoadRoot(edx, Heap::kNanValueRootIndex);
1394 __ fld_d(FieldOperand(edx, HeapNumber::kValueOffset));
1395 __ jmp(&done_compare, Label::kNear);
1396
1397 // Left and right hand side are equal, check for -0 vs. +0.
1398 __ bind(&compare_equal);
1399 // Check the sign of the value in reg_sel
1400 __ fld(reg_sel);
1401 __ FXamSign();
1402 __ j(not_zero, &compare_swap);
1403
1404 __ bind(&done_compare);
1405 // The right result is on the right hand side(stx_0)
1406 // and can remove the useless stx_1 now.
1407 __ fxch();
1408 __ fstp(0);
1409 __ dec(ecx);
1410 __ jmp(&loop);
1411 }
1412
1413 __ bind(&done_loop);
1414 __ PopReturnAddressTo(ecx);
1415 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1416 __ PushReturnAddressFrom(ecx);
1417 __ mov(eax, edx);
1418 __ Ret();
1419}
1420
1421// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001422void Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001423 // ----------- S t a t e -------------
1424 // -- eax : number of arguments
1425 // -- edi : constructor function
1426 // -- esp[0] : return address
1427 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1428 // -- esp[(argc + 1) * 4] : receiver
1429 // -----------------------------------
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001430
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001431 // 1. Load the first argument into eax and get rid of the rest (including the
1432 // receiver).
1433 Label no_arguments;
1434 {
1435 __ test(eax, eax);
1436 __ j(zero, &no_arguments, Label::kNear);
1437 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1438 __ PopReturnAddressTo(ecx);
1439 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1440 __ PushReturnAddressFrom(ecx);
1441 __ mov(eax, ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001442 }
1443
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001444 // 2a. Convert the first argument to a number.
1445 ToNumberStub stub(masm->isolate());
1446 __ TailCallStub(&stub);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001447
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001448 // 2b. No arguments, return +0 (already in eax).
1449 __ bind(&no_arguments);
1450 __ ret(1 * kPointerSize);
1451}
1452
1453
1454// static
1455void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001456 // ----------- S t a t e -------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001457 // -- eax : number of arguments
1458 // -- edi : constructor function
1459 // -- edx : new target
1460 // -- esp[0] : return address
1461 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1462 // -- esp[(argc + 1) * 4] : receiver
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001463 // -----------------------------------
1464
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001465 // 1. Make sure we operate in the context of the called function.
1466 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001467
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001468 // 2. Load the first argument into ebx and get rid of the rest (including the
1469 // receiver).
1470 {
1471 Label no_arguments, done;
1472 __ test(eax, eax);
1473 __ j(zero, &no_arguments, Label::kNear);
1474 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1475 __ jmp(&done, Label::kNear);
1476 __ bind(&no_arguments);
1477 __ Move(ebx, Smi::FromInt(0));
1478 __ bind(&done);
1479 __ PopReturnAddressTo(ecx);
1480 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1481 __ PushReturnAddressFrom(ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001482 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001483
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001484 // 3. Make sure ebx is a number.
1485 {
1486 Label done_convert;
1487 __ JumpIfSmi(ebx, &done_convert);
1488 __ CompareRoot(FieldOperand(ebx, HeapObject::kMapOffset),
1489 Heap::kHeapNumberMapRootIndex);
1490 __ j(equal, &done_convert);
1491 {
1492 FrameScope scope(masm, StackFrame::INTERNAL);
1493 __ Push(edi);
1494 __ Push(edx);
1495 __ Move(eax, ebx);
1496 ToNumberStub stub(masm->isolate());
1497 __ CallStub(&stub);
1498 __ Move(ebx, eax);
1499 __ Pop(edx);
1500 __ Pop(edi);
1501 }
1502 __ bind(&done_convert);
1503 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001504
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001505 // 4. Check if new target and constructor differ.
1506 Label new_object;
1507 __ cmp(edx, edi);
1508 __ j(not_equal, &new_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001509
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001510 // 5. Allocate a JSValue wrapper for the number.
1511 __ AllocateJSValue(eax, edi, ebx, ecx, &new_object);
1512 __ Ret();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001513
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001514 // 6. Fallback to the runtime to create new object.
1515 __ bind(&new_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001516 {
1517 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001518 __ Push(ebx); // the first argument
Ben Murdoch097c5b22016-05-18 11:27:45 +01001519 FastNewObjectStub stub(masm->isolate());
1520 __ CallStub(&stub);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001521 __ Pop(FieldOperand(eax, JSValue::kValueOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001522 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001523 __ Ret();
1524}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001525
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001526
1527// static
1528void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
1529 // ----------- S t a t e -------------
1530 // -- eax : number of arguments
1531 // -- edi : constructor function
1532 // -- esp[0] : return address
1533 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1534 // -- esp[(argc + 1) * 4] : receiver
1535 // -----------------------------------
1536
1537 // 1. Load the first argument into eax and get rid of the rest (including the
1538 // receiver).
1539 Label no_arguments;
1540 {
1541 __ test(eax, eax);
1542 __ j(zero, &no_arguments, Label::kNear);
1543 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1544 __ PopReturnAddressTo(ecx);
1545 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1546 __ PushReturnAddressFrom(ecx);
1547 __ mov(eax, ebx);
1548 }
1549
1550 // 2a. At least one argument, return eax if it's a string, otherwise
1551 // dispatch to appropriate conversion.
1552 Label to_string, symbol_descriptive_string;
1553 {
1554 __ JumpIfSmi(eax, &to_string, Label::kNear);
1555 STATIC_ASSERT(FIRST_NONSTRING_TYPE == SYMBOL_TYPE);
1556 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
1557 __ j(above, &to_string, Label::kNear);
1558 __ j(equal, &symbol_descriptive_string, Label::kNear);
1559 __ Ret();
1560 }
1561
1562 // 2b. No arguments, return the empty string (and pop the receiver).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001563 __ bind(&no_arguments);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001564 {
1565 __ LoadRoot(eax, Heap::kempty_stringRootIndex);
1566 __ ret(1 * kPointerSize);
1567 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001568
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001569 // 3a. Convert eax to a string.
1570 __ bind(&to_string);
1571 {
1572 ToStringStub stub(masm->isolate());
1573 __ TailCallStub(&stub);
1574 }
1575
1576 // 3b. Convert symbol in eax to a string.
1577 __ bind(&symbol_descriptive_string);
1578 {
1579 __ PopReturnAddressTo(ecx);
1580 __ Push(eax);
1581 __ PushReturnAddressFrom(ecx);
1582 __ TailCallRuntime(Runtime::kSymbolDescriptiveString);
1583 }
1584}
1585
1586
1587// static
1588void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
1589 // ----------- S t a t e -------------
1590 // -- eax : number of arguments
1591 // -- edi : constructor function
1592 // -- edx : new target
1593 // -- esp[0] : return address
1594 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1595 // -- esp[(argc + 1) * 4] : receiver
1596 // -----------------------------------
1597
1598 // 1. Make sure we operate in the context of the called function.
1599 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1600
1601 // 2. Load the first argument into ebx and get rid of the rest (including the
1602 // receiver).
1603 {
1604 Label no_arguments, done;
1605 __ test(eax, eax);
1606 __ j(zero, &no_arguments, Label::kNear);
1607 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1608 __ jmp(&done, Label::kNear);
1609 __ bind(&no_arguments);
1610 __ LoadRoot(ebx, Heap::kempty_stringRootIndex);
1611 __ bind(&done);
1612 __ PopReturnAddressTo(ecx);
1613 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1614 __ PushReturnAddressFrom(ecx);
1615 }
1616
1617 // 3. Make sure ebx is a string.
1618 {
1619 Label convert, done_convert;
1620 __ JumpIfSmi(ebx, &convert, Label::kNear);
1621 __ CmpObjectType(ebx, FIRST_NONSTRING_TYPE, ecx);
1622 __ j(below, &done_convert);
1623 __ bind(&convert);
1624 {
1625 FrameScope scope(masm, StackFrame::INTERNAL);
1626 ToStringStub stub(masm->isolate());
1627 __ Push(edi);
1628 __ Push(edx);
1629 __ Move(eax, ebx);
1630 __ CallStub(&stub);
1631 __ Move(ebx, eax);
1632 __ Pop(edx);
1633 __ Pop(edi);
1634 }
1635 __ bind(&done_convert);
1636 }
1637
1638 // 4. Check if new target and constructor differ.
1639 Label new_object;
1640 __ cmp(edx, edi);
1641 __ j(not_equal, &new_object);
1642
1643 // 5. Allocate a JSValue wrapper for the string.
1644 __ AllocateJSValue(eax, edi, ebx, ecx, &new_object);
1645 __ Ret();
1646
1647 // 6. Fallback to the runtime to create new object.
1648 __ bind(&new_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001649 {
1650 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001651 __ Push(ebx); // the first argument
Ben Murdoch097c5b22016-05-18 11:27:45 +01001652 FastNewObjectStub stub(masm->isolate());
1653 __ CallStub(&stub);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001654 __ Pop(FieldOperand(eax, JSValue::kValueOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001655 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001656 __ Ret();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001657}
1658
1659
1660static void ArgumentsAdaptorStackCheck(MacroAssembler* masm,
1661 Label* stack_overflow) {
1662 // ----------- S t a t e -------------
1663 // -- eax : actual number of arguments
1664 // -- ebx : expected number of arguments
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001665 // -- edx : new target (passed through to callee)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001666 // -----------------------------------
1667 // Check the stack for overflow. We are not trying to catch
1668 // interruptions (e.g. debug break and preemption) here, so the "real stack
1669 // limit" is checked.
1670 ExternalReference real_stack_limit =
1671 ExternalReference::address_of_real_stack_limit(masm->isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001672 __ mov(edi, Operand::StaticVariable(real_stack_limit));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001673 // Make ecx the space we have left. The stack might already be overflowed
1674 // here which will cause ecx to become negative.
1675 __ mov(ecx, esp);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001676 __ sub(ecx, edi);
1677 // Make edi the space we need for the array when it is unrolled onto the
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001678 // stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001679 __ mov(edi, ebx);
1680 __ shl(edi, kPointerSizeLog2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001681 // Check if the arguments will overflow the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001682 __ cmp(ecx, edi);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001683 __ j(less_equal, stack_overflow); // Signed comparison.
1684}
1685
1686
1687static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1688 __ push(ebp);
1689 __ mov(ebp, esp);
1690
1691 // Store the arguments adaptor context sentinel.
1692 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
1693
1694 // Push the function on the stack.
1695 __ push(edi);
1696
1697 // Preserve the number of arguments on the stack. Must preserve eax,
1698 // ebx and ecx because these registers are used when copying the
1699 // arguments and the receiver.
1700 STATIC_ASSERT(kSmiTagSize == 1);
1701 __ lea(edi, Operand(eax, eax, times_1, kSmiTag));
1702 __ push(edi);
1703}
1704
1705
1706static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1707 // Retrieve the number of arguments from the stack.
1708 __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1709
1710 // Leave the frame.
1711 __ leave();
1712
1713 // Remove caller arguments from the stack.
1714 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
1715 __ pop(ecx);
1716 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
1717 __ push(ecx);
1718}
1719
1720
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001721// static
1722void Builtins::Generate_Apply(MacroAssembler* masm) {
1723 // ----------- S t a t e -------------
1724 // -- eax : argumentsList
1725 // -- edi : target
1726 // -- edx : new.target (checked to be constructor or undefined)
1727 // -- esp[0] : return address.
1728 // -- esp[4] : thisArgument
1729 // -----------------------------------
1730
1731 // Create the list of arguments from the array-like argumentsList.
1732 {
1733 Label create_arguments, create_array, create_runtime, done_create;
1734 __ JumpIfSmi(eax, &create_runtime);
1735
1736 // Load the map of argumentsList into ecx.
1737 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
1738
1739 // Load native context into ebx.
1740 __ mov(ebx, NativeContextOperand());
1741
1742 // Check if argumentsList is an (unmodified) arguments object.
1743 __ cmp(ecx, ContextOperand(ebx, Context::SLOPPY_ARGUMENTS_MAP_INDEX));
1744 __ j(equal, &create_arguments);
1745 __ cmp(ecx, ContextOperand(ebx, Context::STRICT_ARGUMENTS_MAP_INDEX));
1746 __ j(equal, &create_arguments);
1747
1748 // Check if argumentsList is a fast JSArray.
1749 __ CmpInstanceType(ecx, JS_ARRAY_TYPE);
1750 __ j(equal, &create_array);
1751
1752 // Ask the runtime to create the list (actually a FixedArray).
1753 __ bind(&create_runtime);
1754 {
1755 FrameScope scope(masm, StackFrame::INTERNAL);
1756 __ Push(edi);
1757 __ Push(edx);
1758 __ Push(eax);
1759 __ CallRuntime(Runtime::kCreateListFromArrayLike);
1760 __ Pop(edx);
1761 __ Pop(edi);
1762 __ mov(ebx, FieldOperand(eax, FixedArray::kLengthOffset));
1763 __ SmiUntag(ebx);
1764 }
1765 __ jmp(&done_create);
1766
1767 // Try to create the list from an arguments object.
1768 __ bind(&create_arguments);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001769 __ mov(ebx, FieldOperand(eax, JSArgumentsObject::kLengthOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001770 __ mov(ecx, FieldOperand(eax, JSObject::kElementsOffset));
1771 __ cmp(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
1772 __ j(not_equal, &create_runtime);
1773 __ SmiUntag(ebx);
1774 __ mov(eax, ecx);
1775 __ jmp(&done_create);
1776
1777 // Try to create the list from a JSArray object.
1778 __ bind(&create_array);
1779 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
1780 __ DecodeField<Map::ElementsKindBits>(ecx);
1781 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
1782 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
1783 STATIC_ASSERT(FAST_ELEMENTS == 2);
1784 __ cmp(ecx, Immediate(FAST_ELEMENTS));
1785 __ j(above, &create_runtime);
1786 __ cmp(ecx, Immediate(FAST_HOLEY_SMI_ELEMENTS));
1787 __ j(equal, &create_runtime);
1788 __ mov(ebx, FieldOperand(eax, JSArray::kLengthOffset));
1789 __ SmiUntag(ebx);
1790 __ mov(eax, FieldOperand(eax, JSArray::kElementsOffset));
1791
1792 __ bind(&done_create);
1793 }
1794
1795 // Check for stack overflow.
1796 {
1797 // Check the stack for overflow. We are not trying to catch interruptions
1798 // (i.e. debug break and preemption) here, so check the "real stack limit".
1799 Label done;
1800 ExternalReference real_stack_limit =
1801 ExternalReference::address_of_real_stack_limit(masm->isolate());
1802 __ mov(ecx, Operand::StaticVariable(real_stack_limit));
1803 // Make ecx the space we have left. The stack might already be overflowed
1804 // here which will cause ecx to become negative.
1805 __ neg(ecx);
1806 __ add(ecx, esp);
1807 __ sar(ecx, kPointerSizeLog2);
1808 // Check if the arguments will overflow the stack.
1809 __ cmp(ecx, ebx);
1810 __ j(greater, &done, Label::kNear); // Signed comparison.
1811 __ TailCallRuntime(Runtime::kThrowStackOverflow);
1812 __ bind(&done);
1813 }
1814
1815 // ----------- S t a t e -------------
1816 // -- edi : target
1817 // -- eax : args (a FixedArray built from argumentsList)
1818 // -- ebx : len (number of elements to push from args)
1819 // -- edx : new.target (checked to be constructor or undefined)
1820 // -- esp[0] : return address.
1821 // -- esp[4] : thisArgument
1822 // -----------------------------------
1823
1824 // Push arguments onto the stack (thisArgument is already on the stack).
1825 {
1826 __ push(edx);
1827 __ fld_s(MemOperand(esp, 0));
1828 __ lea(esp, Operand(esp, kFloatSize));
1829
1830 __ PopReturnAddressTo(edx);
1831 __ Move(ecx, Immediate(0));
1832 Label done, loop;
1833 __ bind(&loop);
1834 __ cmp(ecx, ebx);
1835 __ j(equal, &done, Label::kNear);
1836 __ Push(
1837 FieldOperand(eax, ecx, times_pointer_size, FixedArray::kHeaderSize));
1838 __ inc(ecx);
1839 __ jmp(&loop);
1840 __ bind(&done);
1841 __ PushReturnAddressFrom(edx);
1842
1843 __ lea(esp, Operand(esp, -kFloatSize));
1844 __ fstp_s(MemOperand(esp, 0));
1845 __ pop(edx);
1846
1847 __ Move(eax, ebx);
1848 }
1849
1850 // Dispatch to Call or Construct depending on whether new.target is undefined.
1851 {
1852 __ CompareRoot(edx, Heap::kUndefinedValueRootIndex);
1853 __ j(equal, masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1854 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
1855 }
1856}
1857
Ben Murdoch097c5b22016-05-18 11:27:45 +01001858namespace {
1859
1860// Drops top JavaScript frame and an arguments adaptor frame below it (if
1861// present) preserving all the arguments prepared for current call.
1862// Does nothing if debugger is currently active.
1863// ES6 14.6.3. PrepareForTailCall
1864//
1865// Stack structure for the function g() tail calling f():
1866//
1867// ------- Caller frame: -------
1868// | ...
1869// | g()'s arg M
1870// | ...
1871// | g()'s arg 1
1872// | g()'s receiver arg
1873// | g()'s caller pc
1874// ------- g()'s frame: -------
1875// | g()'s caller fp <- fp
1876// | g()'s context
1877// | function pointer: g
1878// | -------------------------
1879// | ...
1880// | ...
1881// | f()'s arg N
1882// | ...
1883// | f()'s arg 1
1884// | f()'s receiver arg
1885// | f()'s caller pc <- sp
1886// ----------------------
1887//
1888void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
1889 Register scratch1, Register scratch2,
1890 Register scratch3) {
1891 DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
1892 Comment cmnt(masm, "[ PrepareForTailCall");
1893
1894 // Prepare for tail call only if the debugger is not active.
1895 Label done;
1896 ExternalReference debug_is_active =
1897 ExternalReference::debug_is_active_address(masm->isolate());
1898 __ movzx_b(scratch1, Operand::StaticVariable(debug_is_active));
1899 __ cmp(scratch1, Immediate(0));
1900 __ j(not_equal, &done, Label::kNear);
1901
1902 // Drop possible interpreter handler/stub frame.
1903 {
1904 Label no_interpreter_frame;
1905 __ cmp(Operand(ebp, StandardFrameConstants::kMarkerOffset),
1906 Immediate(Smi::FromInt(StackFrame::STUB)));
1907 __ j(not_equal, &no_interpreter_frame, Label::kNear);
1908 __ mov(ebp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
1909 __ bind(&no_interpreter_frame);
1910 }
1911
1912 // Check if next frame is an arguments adaptor frame.
1913 Label no_arguments_adaptor, formal_parameter_count_loaded;
1914 __ mov(scratch2, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
1915 __ cmp(Operand(scratch2, StandardFrameConstants::kContextOffset),
1916 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
1917 __ j(not_equal, &no_arguments_adaptor, Label::kNear);
1918
1919 // Drop arguments adaptor frame and load arguments count.
1920 __ mov(ebp, scratch2);
1921 __ mov(scratch1, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1922 __ SmiUntag(scratch1);
1923 __ jmp(&formal_parameter_count_loaded, Label::kNear);
1924
1925 __ bind(&no_arguments_adaptor);
1926 // Load caller's formal parameter count
1927 __ mov(scratch1, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1928 __ mov(scratch1,
1929 FieldOperand(scratch1, JSFunction::kSharedFunctionInfoOffset));
1930 __ mov(
1931 scratch1,
1932 FieldOperand(scratch1, SharedFunctionInfo::kFormalParameterCountOffset));
1933 __ SmiUntag(scratch1);
1934
1935 __ bind(&formal_parameter_count_loaded);
1936
1937 // Calculate the destination address where we will put the return address
1938 // after we drop current frame.
1939 Register new_sp_reg = scratch2;
1940 __ sub(scratch1, args_reg);
1941 __ lea(new_sp_reg, Operand(ebp, scratch1, times_pointer_size,
1942 StandardFrameConstants::kCallerPCOffset));
1943
1944 if (FLAG_debug_code) {
1945 __ cmp(esp, new_sp_reg);
1946 __ Check(below, kStackAccessBelowStackPointer);
1947 }
1948
1949 // Copy receiver and return address as well.
1950 Register count_reg = scratch1;
1951 __ lea(count_reg, Operand(args_reg, 2));
1952
1953 // Copy return address from caller's frame to current frame's return address
1954 // to avoid its trashing and let the following loop copy it to the right
1955 // place.
1956 Register tmp_reg = scratch3;
1957 __ mov(tmp_reg, Operand(ebp, StandardFrameConstants::kCallerPCOffset));
1958 __ mov(Operand(esp, 0), tmp_reg);
1959
1960 // Restore caller's frame pointer now as it could be overwritten by
1961 // the copying loop.
1962 __ mov(ebp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
1963
1964 Operand src(esp, count_reg, times_pointer_size, 0);
1965 Operand dst(new_sp_reg, count_reg, times_pointer_size, 0);
1966
1967 // Now copy callee arguments to the caller frame going backwards to avoid
1968 // callee arguments corruption (source and destination areas could overlap).
1969 Label loop, entry;
1970 __ jmp(&entry, Label::kNear);
1971 __ bind(&loop);
1972 __ dec(count_reg);
1973 __ mov(tmp_reg, src);
1974 __ mov(dst, tmp_reg);
1975 __ bind(&entry);
1976 __ cmp(count_reg, Immediate(0));
1977 __ j(not_equal, &loop, Label::kNear);
1978
1979 // Leave current frame.
1980 __ mov(esp, new_sp_reg);
1981
1982 __ bind(&done);
1983}
1984} // namespace
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001985
1986// static
1987void Builtins::Generate_CallFunction(MacroAssembler* masm,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001988 ConvertReceiverMode mode,
1989 TailCallMode tail_call_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001990 // ----------- S t a t e -------------
1991 // -- eax : the number of arguments (not including the receiver)
1992 // -- edi : the function to call (checked to be a JSFunction)
1993 // -----------------------------------
1994 __ AssertFunction(edi);
1995
1996 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
1997 // Check that the function is not a "classConstructor".
1998 Label class_constructor;
1999 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2000 __ test_b(FieldOperand(edx, SharedFunctionInfo::kFunctionKindByteOffset),
2001 SharedFunctionInfo::kClassConstructorBitsWithinByte);
2002 __ j(not_zero, &class_constructor);
2003
2004 // Enter the context of the function; ToObject has to run in the function
2005 // context, and we also need to take the global proxy from the function
2006 // context in case of conversion.
2007 STATIC_ASSERT(SharedFunctionInfo::kNativeByteOffset ==
2008 SharedFunctionInfo::kStrictModeByteOffset);
2009 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
2010 // We need to convert the receiver for non-native sloppy mode functions.
2011 Label done_convert;
2012 __ test_b(FieldOperand(edx, SharedFunctionInfo::kNativeByteOffset),
2013 (1 << SharedFunctionInfo::kNativeBitWithinByte) |
2014 (1 << SharedFunctionInfo::kStrictModeBitWithinByte));
2015 __ j(not_zero, &done_convert);
2016 {
2017 // ----------- S t a t e -------------
2018 // -- eax : the number of arguments (not including the receiver)
2019 // -- edx : the shared function info.
2020 // -- edi : the function to call (checked to be a JSFunction)
2021 // -- esi : the function context.
2022 // -----------------------------------
2023
2024 if (mode == ConvertReceiverMode::kNullOrUndefined) {
2025 // Patch receiver to global proxy.
2026 __ LoadGlobalProxy(ecx);
2027 } else {
2028 Label convert_to_object, convert_receiver;
2029 __ mov(ecx, Operand(esp, eax, times_pointer_size, kPointerSize));
2030 __ JumpIfSmi(ecx, &convert_to_object, Label::kNear);
2031 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
2032 __ CmpObjectType(ecx, FIRST_JS_RECEIVER_TYPE, ebx);
2033 __ j(above_equal, &done_convert);
2034 if (mode != ConvertReceiverMode::kNotNullOrUndefined) {
2035 Label convert_global_proxy;
2036 __ JumpIfRoot(ecx, Heap::kUndefinedValueRootIndex,
2037 &convert_global_proxy, Label::kNear);
2038 __ JumpIfNotRoot(ecx, Heap::kNullValueRootIndex, &convert_to_object,
2039 Label::kNear);
2040 __ bind(&convert_global_proxy);
2041 {
2042 // Patch receiver to global proxy.
2043 __ LoadGlobalProxy(ecx);
2044 }
2045 __ jmp(&convert_receiver);
2046 }
2047 __ bind(&convert_to_object);
2048 {
2049 // Convert receiver using ToObject.
2050 // TODO(bmeurer): Inline the allocation here to avoid building the frame
2051 // in the fast case? (fall back to AllocateInNewSpace?)
2052 FrameScope scope(masm, StackFrame::INTERNAL);
2053 __ SmiTag(eax);
2054 __ Push(eax);
2055 __ Push(edi);
2056 __ mov(eax, ecx);
2057 ToObjectStub stub(masm->isolate());
2058 __ CallStub(&stub);
2059 __ mov(ecx, eax);
2060 __ Pop(edi);
2061 __ Pop(eax);
2062 __ SmiUntag(eax);
2063 }
2064 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2065 __ bind(&convert_receiver);
2066 }
2067 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ecx);
2068 }
2069 __ bind(&done_convert);
2070
2071 // ----------- S t a t e -------------
2072 // -- eax : the number of arguments (not including the receiver)
2073 // -- edx : the shared function info.
2074 // -- edi : the function to call (checked to be a JSFunction)
2075 // -- esi : the function context.
2076 // -----------------------------------
2077
Ben Murdoch097c5b22016-05-18 11:27:45 +01002078 if (tail_call_mode == TailCallMode::kAllow) {
2079 PrepareForTailCall(masm, eax, ebx, ecx, edx);
2080 // Reload shared function info.
2081 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2082 }
2083
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002084 __ mov(ebx,
2085 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
2086 __ SmiUntag(ebx);
2087 ParameterCount actual(eax);
2088 ParameterCount expected(ebx);
2089 __ InvokeFunctionCode(edi, no_reg, expected, actual, JUMP_FUNCTION,
2090 CheckDebugStepCallWrapper());
2091 // The function is a "classConstructor", need to raise an exception.
2092 __ bind(&class_constructor);
2093 {
2094 FrameScope frame(masm, StackFrame::INTERNAL);
2095 __ push(edi);
2096 __ CallRuntime(Runtime::kThrowConstructorNonCallableError);
2097 }
2098}
2099
2100
2101namespace {
2102
2103void Generate_PushBoundArguments(MacroAssembler* masm) {
2104 // ----------- S t a t e -------------
2105 // -- eax : the number of arguments (not including the receiver)
2106 // -- edx : new.target (only in case of [[Construct]])
2107 // -- edi : target (checked to be a JSBoundFunction)
2108 // -----------------------------------
2109
2110 // Load [[BoundArguments]] into ecx and length of that into ebx.
2111 Label no_bound_arguments;
2112 __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset));
2113 __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
2114 __ SmiUntag(ebx);
2115 __ test(ebx, ebx);
2116 __ j(zero, &no_bound_arguments);
2117 {
2118 // ----------- S t a t e -------------
2119 // -- eax : the number of arguments (not including the receiver)
2120 // -- edx : new.target (only in case of [[Construct]])
2121 // -- edi : target (checked to be a JSBoundFunction)
2122 // -- ecx : the [[BoundArguments]] (implemented as FixedArray)
2123 // -- ebx : the number of [[BoundArguments]]
2124 // -----------------------------------
2125
2126 // Reserve stack space for the [[BoundArguments]].
2127 {
2128 Label done;
2129 __ lea(ecx, Operand(ebx, times_pointer_size, 0));
2130 __ sub(esp, ecx);
2131 // Check the stack for overflow. We are not trying to catch interruptions
2132 // (i.e. debug break and preemption) here, so check the "real stack
2133 // limit".
2134 __ CompareRoot(esp, ecx, Heap::kRealStackLimitRootIndex);
2135 __ j(greater, &done, Label::kNear); // Signed comparison.
2136 // Restore the stack pointer.
2137 __ lea(esp, Operand(esp, ebx, times_pointer_size, 0));
2138 {
2139 FrameScope scope(masm, StackFrame::MANUAL);
2140 __ EnterFrame(StackFrame::INTERNAL);
2141 __ CallRuntime(Runtime::kThrowStackOverflow);
2142 }
2143 __ bind(&done);
2144 }
2145
2146 // Adjust effective number of arguments to include return address.
2147 __ inc(eax);
2148
2149 // Relocate arguments and return address down the stack.
2150 {
2151 Label loop;
2152 __ Set(ecx, 0);
2153 __ lea(ebx, Operand(esp, ebx, times_pointer_size, 0));
2154 __ bind(&loop);
2155 __ fld_s(Operand(ebx, ecx, times_pointer_size, 0));
2156 __ fstp_s(Operand(esp, ecx, times_pointer_size, 0));
2157 __ inc(ecx);
2158 __ cmp(ecx, eax);
2159 __ j(less, &loop);
2160 }
2161
2162 // Copy [[BoundArguments]] to the stack (below the arguments).
2163 {
2164 Label loop;
2165 __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset));
2166 __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
2167 __ SmiUntag(ebx);
2168 __ bind(&loop);
2169 __ dec(ebx);
2170 __ fld_s(
2171 FieldOperand(ecx, ebx, times_pointer_size, FixedArray::kHeaderSize));
2172 __ fstp_s(Operand(esp, eax, times_pointer_size, 0));
2173 __ lea(eax, Operand(eax, 1));
2174 __ j(greater, &loop);
2175 }
2176
2177 // Adjust effective number of arguments (eax contains the number of
2178 // arguments from the call plus return address plus the number of
2179 // [[BoundArguments]]), so we need to subtract one for the return address.
2180 __ dec(eax);
2181 }
2182 __ bind(&no_bound_arguments);
2183}
2184
2185} // namespace
2186
2187
2188// static
Ben Murdoch097c5b22016-05-18 11:27:45 +01002189void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm,
2190 TailCallMode tail_call_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002191 // ----------- S t a t e -------------
2192 // -- eax : the number of arguments (not including the receiver)
2193 // -- edi : the function to call (checked to be a JSBoundFunction)
2194 // -----------------------------------
2195 __ AssertBoundFunction(edi);
2196
Ben Murdoch097c5b22016-05-18 11:27:45 +01002197 if (tail_call_mode == TailCallMode::kAllow) {
2198 PrepareForTailCall(masm, eax, ebx, ecx, edx);
2199 }
2200
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002201 // Patch the receiver to [[BoundThis]].
2202 __ mov(ebx, FieldOperand(edi, JSBoundFunction::kBoundThisOffset));
2203 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ebx);
2204
2205 // Push the [[BoundArguments]] onto the stack.
2206 Generate_PushBoundArguments(masm);
2207
2208 // Call the [[BoundTargetFunction]] via the Call builtin.
2209 __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2210 __ mov(ecx, Operand::StaticVariable(ExternalReference(
2211 Builtins::kCall_ReceiverIsAny, masm->isolate())));
2212 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2213 __ jmp(ecx);
2214}
2215
2216
2217// static
Ben Murdoch097c5b22016-05-18 11:27:45 +01002218void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
2219 TailCallMode tail_call_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002220 // ----------- S t a t e -------------
2221 // -- eax : the number of arguments (not including the receiver)
2222 // -- edi : the target to call (can be any Object).
2223 // -----------------------------------
2224
2225 Label non_callable, non_function, non_smi;
2226 __ JumpIfSmi(edi, &non_callable);
2227 __ bind(&non_smi);
2228 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002229 __ j(equal, masm->isolate()->builtins()->CallFunction(mode, tail_call_mode),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002230 RelocInfo::CODE_TARGET);
2231 __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002232 __ j(equal, masm->isolate()->builtins()->CallBoundFunction(tail_call_mode),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002233 RelocInfo::CODE_TARGET);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002234
2235 // Check if target has a [[Call]] internal method.
2236 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsCallable);
2237 __ j(zero, &non_callable);
2238
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002239 __ CmpInstanceType(ecx, JS_PROXY_TYPE);
2240 __ j(not_equal, &non_function);
2241
Ben Murdoch097c5b22016-05-18 11:27:45 +01002242 // 0. Prepare for tail call if necessary.
2243 if (tail_call_mode == TailCallMode::kAllow) {
2244 PrepareForTailCall(masm, eax, ebx, ecx, edx);
2245 }
2246
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002247 // 1. Runtime fallback for Proxy [[Call]].
2248 __ PopReturnAddressTo(ecx);
2249 __ Push(edi);
2250 __ PushReturnAddressFrom(ecx);
2251 // Increase the arguments size to include the pushed function and the
2252 // existing receiver on the stack.
2253 __ add(eax, Immediate(2));
2254 // Tail-call to the runtime.
2255 __ JumpToExternalReference(
2256 ExternalReference(Runtime::kJSProxyCall, masm->isolate()));
2257
2258 // 2. Call to something else, which might have a [[Call]] internal method (if
2259 // not we raise an exception).
2260 __ bind(&non_function);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002261 // Overwrite the original receiver with the (original) target.
2262 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
2263 // Let the "call_as_function_delegate" take care of the rest.
2264 __ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, edi);
2265 __ Jump(masm->isolate()->builtins()->CallFunction(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002266 ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002267 RelocInfo::CODE_TARGET);
2268
2269 // 3. Call to something that is not callable.
2270 __ bind(&non_callable);
2271 {
2272 FrameScope scope(masm, StackFrame::INTERNAL);
2273 __ Push(edi);
2274 __ CallRuntime(Runtime::kThrowCalledNonCallable);
2275 }
2276}
2277
2278
2279// static
2280void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
2281 // ----------- S t a t e -------------
2282 // -- eax : the number of arguments (not including the receiver)
2283 // -- edx : the new target (checked to be a constructor)
2284 // -- edi : the constructor to call (checked to be a JSFunction)
2285 // -----------------------------------
2286 __ AssertFunction(edi);
2287
2288 // Calling convention for function specific ConstructStubs require
2289 // ebx to contain either an AllocationSite or undefined.
2290 __ LoadRoot(ebx, Heap::kUndefinedValueRootIndex);
2291
2292 // Tail call to the function-specific construct stub (still in the caller
2293 // context at this point).
2294 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2295 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset));
2296 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2297 __ jmp(ecx);
2298}
2299
2300
2301// static
2302void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) {
2303 // ----------- S t a t e -------------
2304 // -- eax : the number of arguments (not including the receiver)
2305 // -- edx : the new target (checked to be a constructor)
2306 // -- edi : the constructor to call (checked to be a JSBoundFunction)
2307 // -----------------------------------
2308 __ AssertBoundFunction(edi);
2309
2310 // Push the [[BoundArguments]] onto the stack.
2311 Generate_PushBoundArguments(masm);
2312
2313 // Patch new.target to [[BoundTargetFunction]] if new.target equals target.
2314 {
2315 Label done;
2316 __ cmp(edi, edx);
2317 __ j(not_equal, &done, Label::kNear);
2318 __ mov(edx, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2319 __ bind(&done);
2320 }
2321
2322 // Construct the [[BoundTargetFunction]] via the Construct builtin.
2323 __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2324 __ mov(ecx, Operand::StaticVariable(
2325 ExternalReference(Builtins::kConstruct, masm->isolate())));
2326 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2327 __ jmp(ecx);
2328}
2329
2330
2331// static
2332void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
2333 // ----------- S t a t e -------------
2334 // -- eax : the number of arguments (not including the receiver)
2335 // -- edi : the constructor to call (checked to be a JSProxy)
2336 // -- edx : the new target (either the same as the constructor or
2337 // the JSFunction on which new was invoked initially)
2338 // -----------------------------------
2339
2340 // Call into the Runtime for Proxy [[Construct]].
2341 __ PopReturnAddressTo(ecx);
2342 __ Push(edi);
2343 __ Push(edx);
2344 __ PushReturnAddressFrom(ecx);
2345 // Include the pushed new_target, constructor and the receiver.
2346 __ add(eax, Immediate(3));
2347 // Tail-call to the runtime.
2348 __ JumpToExternalReference(
2349 ExternalReference(Runtime::kJSProxyConstruct, masm->isolate()));
2350}
2351
2352
2353// static
2354void Builtins::Generate_Construct(MacroAssembler* masm) {
2355 // ----------- S t a t e -------------
2356 // -- eax : the number of arguments (not including the receiver)
2357 // -- edx : the new target (either the same as the constructor or
2358 // the JSFunction on which new was invoked initially)
2359 // -- edi : the constructor to call (can be any Object)
2360 // -----------------------------------
2361
2362 // Check if target is a Smi.
2363 Label non_constructor;
2364 __ JumpIfSmi(edi, &non_constructor, Label::kNear);
2365
2366 // Dispatch based on instance type.
2367 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
2368 __ j(equal, masm->isolate()->builtins()->ConstructFunction(),
2369 RelocInfo::CODE_TARGET);
2370
2371 // Check if target has a [[Construct]] internal method.
2372 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsConstructor);
2373 __ j(zero, &non_constructor, Label::kNear);
2374
2375 // Only dispatch to bound functions after checking whether they are
2376 // constructors.
2377 __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE);
2378 __ j(equal, masm->isolate()->builtins()->ConstructBoundFunction(),
2379 RelocInfo::CODE_TARGET);
2380
2381 // Only dispatch to proxies after checking whether they are constructors.
2382 __ CmpInstanceType(ecx, JS_PROXY_TYPE);
2383 __ j(equal, masm->isolate()->builtins()->ConstructProxy(),
2384 RelocInfo::CODE_TARGET);
2385
2386 // Called Construct on an exotic Object with a [[Construct]] internal method.
2387 {
2388 // Overwrite the original receiver with the (original) target.
2389 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
2390 // Let the "call_as_constructor_delegate" take care of the rest.
2391 __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, edi);
2392 __ Jump(masm->isolate()->builtins()->CallFunction(),
2393 RelocInfo::CODE_TARGET);
2394 }
2395
2396 // Called Construct on an Object that doesn't have a [[Construct]] internal
2397 // method.
2398 __ bind(&non_constructor);
2399 __ Jump(masm->isolate()->builtins()->ConstructedNonConstructable(),
2400 RelocInfo::CODE_TARGET);
2401}
2402
2403
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002404void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
2405 // ----------- S t a t e -------------
2406 // -- eax : actual number of arguments
2407 // -- ebx : expected number of arguments
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002408 // -- edx : new target (passed through to callee)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002409 // -- edi : function (passed through to callee)
2410 // -----------------------------------
2411
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002412 Label invoke, dont_adapt_arguments, stack_overflow;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002413 __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1);
2414
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002415 Label enough, too_few;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002416 __ cmp(eax, ebx);
2417 __ j(less, &too_few);
2418 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
2419 __ j(equal, &dont_adapt_arguments);
2420
2421 { // Enough parameters: Actual >= expected.
2422 __ bind(&enough);
2423 EnterArgumentsAdaptorFrame(masm);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002424 ArgumentsAdaptorStackCheck(masm, &stack_overflow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002425
2426 // Copy receiver and all expected arguments.
2427 const int offset = StandardFrameConstants::kCallerSPOffset;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002428 __ lea(edi, Operand(ebp, eax, times_4, offset));
2429 __ mov(eax, -1); // account for receiver
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002430
2431 Label copy;
2432 __ bind(&copy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002433 __ inc(eax);
2434 __ push(Operand(edi, 0));
2435 __ sub(edi, Immediate(kPointerSize));
2436 __ cmp(eax, ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002437 __ j(less, &copy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002438 // eax now contains the expected number of arguments.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002439 __ jmp(&invoke);
2440 }
2441
2442 { // Too few parameters: Actual < expected.
2443 __ bind(&too_few);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002444
2445 // If the function is strong we need to throw an error.
2446 Label no_strong_error;
2447 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2448 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrongModeByteOffset),
2449 1 << SharedFunctionInfo::kStrongModeBitWithinByte);
2450 __ j(equal, &no_strong_error, Label::kNear);
2451
2452 // What we really care about is the required number of arguments.
2453 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kLengthOffset));
2454 __ SmiUntag(ecx);
2455 __ cmp(eax, ecx);
2456 __ j(greater_equal, &no_strong_error, Label::kNear);
2457
2458 {
2459 FrameScope frame(masm, StackFrame::MANUAL);
2460 EnterArgumentsAdaptorFrame(masm);
2461 __ CallRuntime(Runtime::kThrowStrongModeTooFewArguments);
2462 }
2463
2464 __ bind(&no_strong_error);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002465 EnterArgumentsAdaptorFrame(masm);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002466 ArgumentsAdaptorStackCheck(masm, &stack_overflow);
2467
2468 // Remember expected arguments in ecx.
2469 __ mov(ecx, ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002470
2471 // Copy receiver and all actual arguments.
2472 const int offset = StandardFrameConstants::kCallerSPOffset;
2473 __ lea(edi, Operand(ebp, eax, times_4, offset));
2474 // ebx = expected - actual.
2475 __ sub(ebx, eax);
2476 // eax = -actual - 1
2477 __ neg(eax);
2478 __ sub(eax, Immediate(1));
2479
2480 Label copy;
2481 __ bind(&copy);
2482 __ inc(eax);
2483 __ push(Operand(edi, 0));
2484 __ sub(edi, Immediate(kPointerSize));
2485 __ test(eax, eax);
2486 __ j(not_zero, &copy);
2487
2488 // Fill remaining expected arguments with undefined values.
2489 Label fill;
2490 __ bind(&fill);
2491 __ inc(eax);
2492 __ push(Immediate(masm->isolate()->factory()->undefined_value()));
2493 __ cmp(eax, ebx);
2494 __ j(less, &fill);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002495
2496 // Restore expected arguments.
2497 __ mov(eax, ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002498 }
2499
2500 // Call the entry point.
2501 __ bind(&invoke);
2502 // Restore function pointer.
2503 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002504 // eax : expected number of arguments
2505 // edx : new target (passed through to callee)
2506 // edi : function (passed through to callee)
2507 __ mov(ecx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
2508 __ call(ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002509
2510 // Store offset of return address for deoptimizer.
2511 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
2512
2513 // Leave frame and return.
2514 LeaveArgumentsAdaptorFrame(masm);
2515 __ ret(0);
2516
2517 // -------------------------------------------
2518 // Dont adapt arguments.
2519 // -------------------------------------------
2520 __ bind(&dont_adapt_arguments);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002521 __ mov(ecx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
2522 __ jmp(ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002523
2524 __ bind(&stack_overflow);
2525 {
2526 FrameScope frame(masm, StackFrame::MANUAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002527 __ CallRuntime(Runtime::kThrowStackOverflow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002528 __ int3();
2529 }
2530}
2531
2532
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002533static void CompatibleReceiverCheck(MacroAssembler* masm, Register receiver,
2534 Register function_template_info,
2535 Register scratch0, Register scratch1,
2536 Label* receiver_check_failed) {
2537 // If there is no signature, return the holder.
2538 __ CompareRoot(FieldOperand(function_template_info,
2539 FunctionTemplateInfo::kSignatureOffset),
2540 Heap::kUndefinedValueRootIndex);
2541 Label receiver_check_passed;
2542 __ j(equal, &receiver_check_passed, Label::kNear);
2543
2544 // Walk the prototype chain.
2545 __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
2546 Label prototype_loop_start;
2547 __ bind(&prototype_loop_start);
2548
2549 // Get the constructor, if any.
2550 __ GetMapConstructor(scratch0, scratch0, scratch1);
2551 __ CmpInstanceType(scratch1, JS_FUNCTION_TYPE);
2552 Label next_prototype;
2553 __ j(not_equal, &next_prototype, Label::kNear);
2554
2555 // Get the constructor's signature.
2556 __ mov(scratch0,
2557 FieldOperand(scratch0, JSFunction::kSharedFunctionInfoOffset));
2558 __ mov(scratch0,
2559 FieldOperand(scratch0, SharedFunctionInfo::kFunctionDataOffset));
2560
2561 // Loop through the chain of inheriting function templates.
2562 Label function_template_loop;
2563 __ bind(&function_template_loop);
2564
2565 // If the signatures match, we have a compatible receiver.
2566 __ cmp(scratch0, FieldOperand(function_template_info,
2567 FunctionTemplateInfo::kSignatureOffset));
2568 __ j(equal, &receiver_check_passed, Label::kNear);
2569
2570 // If the current type is not a FunctionTemplateInfo, load the next prototype
2571 // in the chain.
2572 __ JumpIfSmi(scratch0, &next_prototype, Label::kNear);
2573 __ CmpObjectType(scratch0, FUNCTION_TEMPLATE_INFO_TYPE, scratch1);
2574 __ j(not_equal, &next_prototype, Label::kNear);
2575
2576 // Otherwise load the parent function template and iterate.
2577 __ mov(scratch0,
2578 FieldOperand(scratch0, FunctionTemplateInfo::kParentTemplateOffset));
2579 __ jmp(&function_template_loop, Label::kNear);
2580
2581 // Load the next prototype.
2582 __ bind(&next_prototype);
2583 __ mov(receiver, FieldOperand(receiver, HeapObject::kMapOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002584 __ test(FieldOperand(receiver, Map::kBitField3Offset),
2585 Immediate(Map::HasHiddenPrototype::kMask));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002586 __ j(zero, receiver_check_failed);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002587
2588 __ mov(receiver, FieldOperand(receiver, Map::kPrototypeOffset));
2589 __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002590 // Iterate.
2591 __ jmp(&prototype_loop_start, Label::kNear);
2592
2593 __ bind(&receiver_check_passed);
2594}
2595
2596
2597void Builtins::Generate_HandleFastApiCall(MacroAssembler* masm) {
2598 // ----------- S t a t e -------------
2599 // -- eax : number of arguments (not including the receiver)
2600 // -- edi : callee
2601 // -- esi : context
2602 // -- esp[0] : return address
2603 // -- esp[4] : last argument
2604 // -- ...
2605 // -- esp[eax * 4] : first argument
2606 // -- esp[(eax + 1) * 4] : receiver
2607 // -----------------------------------
2608
2609 // Load the FunctionTemplateInfo.
2610 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2611 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kFunctionDataOffset));
2612
2613 // Do the compatible receiver check.
2614 Label receiver_check_failed;
2615 __ mov(ecx, Operand(esp, eax, times_pointer_size, kPCOnStackSize));
2616 __ Push(eax);
2617 CompatibleReceiverCheck(masm, ecx, ebx, edx, eax, &receiver_check_failed);
2618 __ Pop(eax);
2619 // Get the callback offset from the FunctionTemplateInfo, and jump to the
2620 // beginning of the code.
2621 __ mov(edx, FieldOperand(ebx, FunctionTemplateInfo::kCallCodeOffset));
2622 __ mov(edx, FieldOperand(edx, CallHandlerInfo::kFastHandlerOffset));
2623 __ add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag));
2624 __ jmp(edx);
2625
2626 // Compatible receiver check failed: pop return address, arguments and
2627 // receiver and throw an Illegal Invocation exception.
2628 __ bind(&receiver_check_failed);
2629 __ Pop(eax);
2630 __ PopReturnAddressTo(ebx);
2631 __ lea(eax, Operand(eax, times_pointer_size, 1 * kPointerSize));
2632 __ add(esp, eax);
2633 __ PushReturnAddressFrom(ebx);
2634 {
2635 FrameScope scope(masm, StackFrame::INTERNAL);
2636 __ TailCallRuntime(Runtime::kThrowIllegalInvocation);
2637 }
2638}
2639
2640
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002641void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
2642 // Lookup the function in the JavaScript frame.
2643 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
2644 {
2645 FrameScope scope(masm, StackFrame::INTERNAL);
2646 // Pass function as argument.
2647 __ push(eax);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002648 __ CallRuntime(Runtime::kCompileForOnStackReplacement);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002649 }
2650
2651 Label skip;
2652 // If the code object is null, just return to the unoptimized code.
2653 __ cmp(eax, Immediate(0));
2654 __ j(not_equal, &skip, Label::kNear);
2655 __ ret(0);
2656
2657 __ bind(&skip);
2658
2659 // Load deoptimization data from the code object.
2660 __ mov(ebx, Operand(eax, Code::kDeoptimizationDataOffset - kHeapObjectTag));
2661
2662 // Load the OSR entrypoint offset from the deoptimization data.
2663 __ mov(ebx, Operand(ebx, FixedArray::OffsetOfElementAt(
2664 DeoptimizationInputData::kOsrPcOffsetIndex) - kHeapObjectTag));
2665 __ SmiUntag(ebx);
2666
2667 // Compute the target address = code_obj + header_size + osr_offset
2668 __ lea(eax, Operand(eax, ebx, times_1, Code::kHeaderSize - kHeapObjectTag));
2669
2670 // Overwrite the return address on the stack.
2671 __ mov(Operand(esp, 0), eax);
2672
2673 // And "return" to the OSR entry point of the function.
2674 __ ret(0);
2675}
2676
2677
2678void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
2679 // We check the stack limit as indicator that recompilation might be done.
2680 Label ok;
2681 ExternalReference stack_limit =
2682 ExternalReference::address_of_stack_limit(masm->isolate());
2683 __ cmp(esp, Operand::StaticVariable(stack_limit));
2684 __ j(above_equal, &ok, Label::kNear);
2685 {
2686 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002687 __ CallRuntime(Runtime::kStackGuard);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002688 }
2689 __ jmp(masm->isolate()->builtins()->OnStackReplacement(),
2690 RelocInfo::CODE_TARGET);
2691
2692 __ bind(&ok);
2693 __ ret(0);
2694}
2695
2696#undef __
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002697} // namespace internal
2698} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002699
2700#endif // V8_TARGET_ARCH_X87